首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 呼叫 WebService (SOAP) 實戰:以 QQ 在線狀態查詢為例

     編輯:PHP 綜合知識

企業系統整合常需呼叫外部 SOAP WebService。PHP 5 內建 SoapClient 提供完整客戶端功能。本文以「查詢 QQ 在線狀態」為例,示範從 WSDL 解析、型別檢視、參數建構、呼叫流程到錯誤處理的完整步驟。

完整呼叫範例

<?php
try {
    // 1. 建立客戶端:支援本地 .wsdl 檔或遠端 URL
    $wsdl = 'https://webservice.webxml.com.cn/webservices/qqOnlineWebService.asmx?wsdl';
    $client = new SoapClient($wsdl, [
        'encoding' => 'UTF-8',      // 含中文參數必須指定
        'trace' => 1,               // 除錯用:記錄請求/回應 XML
        'exceptions' => true,       // 拋出 SoapFault 異常
        'cache_wsdl' => WSDL_CACHE_MEMORY, // 效能優化
    ]);

    // 2. 檢視可用方法與型別(開發階段必做)
    echo "

可用方法:

";
    var_dump($client->__getFunctions());
    echo "

資料型別:

";
    var_dump($client->__getTypes());
    echo "
"; // 3. 建構參數:方法需結構體時,用 PHP 類別對應 class QqCheckOnline { public $qqCode = '10000'; // 對應 WSDL 定義的參數名 } $param = new QqCheckOnline(); // 或陣列寫法:$param = ['qqCode' => '10000']; // 4. 呼叫方法:__soapCall 或魔術方法 $result = $client->__soapCall('qqCheckOnline', [$param]); // 等同於:$result = $client->qqCheckOnline($param); // 5. 取得結果:回傳物件屬性名通常為 方法名+Result echo "QQ 在線狀態:" . $result->qqCheckOnlineResult . "
"; } catch (SoapFault $e) { echo "SOAP 錯誤: " . $e->getMessage() . "
"; if (isset($client)) { echo "最後請求:
" . htmlspecialchars($client->__getLastRequest()) . "
"; echo "最後回應:
" . htmlspecialchars($client->__getLastResponse()) . "
"; } } ?>

關鍵步驟深度解析

1. WSDL 快取策略

'cache_wsdl' => WSDL_CACHE_MEMORY // 開發建議 MEMORY 或 NONE,正式環境可用 WSDL_CACHE_DISK
  • WSDL_CACHE_NONE:每次請求下載 WSDL(開發除錯)
  • WSDL_CACHE_MEMORY:請求生命週期內快取(推薦開發/測試)
  • WSDL_CACHE_DISK:檔案快存 /tmp/wsdl-*(正式環境預設)
  • WSDL_CACHE_BOTH:記憶體+磁碟

2. 參數名稱必須與 WSDL 定義完全一致

使用 __getTypes() 檢視輸出,找到對應的 struct 定義,例如:

struct qqCheckOnline {
 string qqCode;
}

PHP 類別屬性名 必須為 qqCode,大小寫敏感。陣列鍵名同理。

3. 複雜型別巢狀結構建構

// WSDL 定義:
// struct UserInfo { string name; int age; Address addr; }
// struct Address { string city; string zip; }

class Address { public $city; public $zip; }
class UserInfo {
    public $name;
    public $age;
    public $addr; // Address 物件
}

$addr = new Address();
$addr->city = 'Taipei';
$addr->zip = '100';

$user = new UserInfo();
$user->name = 'John';
$user->age = 30;
$user->addr = $addr;

$client->__soapCall('SubmitUser', [$user]);

4. 回應 XML 自動解析陷阱

若 WebService 回傳 XML 字串 而非結構化資料,PHP SoapClient 會嘗試解析該 XML 並轉為物件/陣列,導致原始 XML 遺失。對策:

  • 協議方調整回傳結構化型別
  • 或用 __getLastResponse() 取得原始 XML 字串自行解析
  • 或改用 cURL 發送原始 SOAP Envelope 完全掌控

5. HTTPS 與憑證處理

$client = new SoapClient($wsdl, [
    'stream_context' => stream_context_create([
        'ssl' => [
            'verify_peer' => false,       // 正式環境請勿關閉
            'verify_peer_name' => false,
            'allow_self_signed' => true,
        ],
    ]),
]);

6. WS-Security / Header 認證

use SoapHeader;

$auth = new SoapHeader('https://tempuri.org/', 'AuthHeader', [
    'Username' => 'api_user',
    'Password' => 'secret',
]);
$client->__setSoapHeaders($auth);

除錯三大神器

方法用途
$client->__getLastRequest()取得最後發送的原始 SOAP XML 請求
$client->__getLastResponse()取得最後收到的原始 SOAP XML 回應
$client->__getLastRequestHeaders()取得 HTTP 請求標頭

需在建構子設定 'trace' => 1 才能使用。

常見錯誤與解決

錯誤原因解決
SoapFault: Function not found方法名拼錯、大小寫不符、WSDL 未更新用 __getFunctions() 確認正確名稱
SoapFault: Missing parameter參數名稱與 WSDL 定義不符用 __getTypes() 核對 struct 定義
Encoding: Violation of encoding rules中文參數未設定 encoding建構子加 'encoding' => 'UTF-8'
Could not connect to host防火牆、DNS、HTTPS 憑證檢查網路、stream_context ssl 設定
回傳物件屬性為 nullWSDL 定義 nillable=true 但實際無值程式碼判斷 isset/empty 再存取

總結

PHP SoapClient 功能強大但細節多:WSDL 快取、編碼設定、參數名稱精確對應、複雜型別物件建構、除錯追蹤 是成功關鍵。現代專案若可選擇,優先考慮 REST/JSON API;必須用 SOAP 時,善用 __getFunctions/__getTypes 理解契約,再撰寫對應的 DTO 類別,配合 trace 除錯,即能穩定整合。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved