2024 日本 PHP 研討會

SOAP

新增註記

使用者提供的註記 7 則註記

nodkz at mail dot ru
16 年前
問題(在 PHP5 下使用 SOAP 擴充功能時)傳輸包含物件或物件陣列的物件。巢狀物件將無法傳輸。

解決方案
這個類別是由我透過反覆試驗開發出來的。因此,這 23 行程式碼對於大多數在 PHP5 下編寫程式的開發人員來說,解決了使用 SOAP 擴充功能的命運。

<?php
/*
根據 PHP5 中 SOAP 類別的組織流程特性,我們必須將複雜物件包裝在 SoapVar 類別中。否則物件將無法正確編碼,並且無法在遠端 SOAP 處理程式上載入。

函式 "getAsSoap" 用於編碼物件以進行傳輸。編碼後即可正確傳輸。
*/
abstract class SOAPable {
public function
getAsSOAP() {
foreach(
$this as $key=>&$value) {
$this->prepareSOAPrecursive($this->$key);
}
return
$this;
}

private function
prepareSOAPrecursive(&$element) {
if(
is_array($element)) {
foreach(
$element as $key=>&$val) {
$this->prepareSOAPrecursive($val);
}
$element=new SoapVar($element,SOAP_ENC_ARRAY);
}elseif(
is_object($element)) {
if(
$element instanceof SOAPable) {
$element->getAsSOAP();
}
$element=new SoapVar($element,SOAP_ENC_OBJECT);
}
}
}

// ------------------------------------------
// 抽象範例
// ------------------------------------------

class PersonList extends SOAPable {
protected
$ArrayOfPerson; // 變數必須是 protected 或 public!
}

class
Person extends SOAPable {
//任何資料
}

$client=new SoapClient("test.wsdl", array( 'soap_version'=>SOAP_1_2, 'trace'=>1, 'classmap' => array('Person' => "Person", 'PersonList' => "PersonList") ));

$PersonList=new PersonList;

// 一些操作

$PersonList->getAsSOAP();

$client->someMethod($PersonList);

?>

因此,每個要透過 SOAP 傳輸的類別都必須繼承自 SOAPable 類別。
如您在上面的程式碼中所見,函式 prepareSOAPrecursive 會在父物件或陣列中搜尋其他巢狀物件,如果找到,則會嘗試呼叫函式 getAsSOAP() 來準備巢狀物件,然後再透過 SoapVar 類別進行包裝。

所以在傳輸前的程式碼中,只需呼叫 $obj->getAsSOAP()
Ryan
16 年前
如果你遇到 SOAP 找不到實際存在的函式(即使在 wsdl 檔案中可以看到)的問題,這是因為 PHP 快取了 wsdl 檔案(一次一天)。要關閉此功能,請在每個使用 SOAP 的程式碼中加入以下這一行: ini_set("soap.wsdl_cache_enabled", "0"); 以停用快取功能。
Raphal Gertz
15 年前
僅供參考,以免浪費時間在 php-soap 協定和格式支援上。

至少在 php 5.2.9 之前,soap 擴充功能僅能理解 wsdl 1.0 和 1.1 格式。

自 2007 年 6 月起成為 W3C 建議的 wsdl 2.0,在 php soap 擴充功能中*不支援*。
(soap/php_sdl.c 原始碼無法處理 wsdl2.0 格式)

wsdl 2.0 只是重新命名的 1.2 版本,因為它與 WSDL 1.1 有很大的不同。

如果您不太在意,這兩種格式之間的差異可能並不明顯。

wsdl 1.0 格式結構(參見 http://www.w3.org/TR/wsdl
<definitions ...>
<types ...>
</types>
<message ...>
<part ...>
</message>
<portType ...>
<operation ...>
<input ... />
<output ... />
<fault ... />
</operation>
</portType>
<binding ...>
<operation ...>
<input ... />
<output ... />
<fault ... />
</operation>
</binding>
<service ...>
<port ...>
</service>
</definitions>

以及 wsdl 2.0 格式結構(參見 http://www.w3.org/TR/wsdl20/
<description ...>
<types ...>
</types>
<interface ...>
<fault ... />
<operation ...>
<input ... />
<output ... />
<fault ... />
</operation>
</interface>
<binding ...>
<fault ... />
<operation ...>
<input ... />
<output ... />
<fault ... />
</operation>
</binding>
<service ...>
<endpoint ...>
</service>
</description>

如果您提供 wsdl 2.0 格式檔案,典型的錯誤訊息如下
PHP 致命錯誤:SOAP-ERROR: 解析 WSDL: 在 'wsdl/example.wsdl' 中找不到 <definitions>,位於 /path/client.php 第 9 行
Luke
9 年前
之前像這樣呼叫 asmx 方法:$success=$x->AuthenticateUser($userName,$password),但它會回傳錯誤。

然而,我將它更改為將 userName 和 password 放入一個陣列中,現在就沒問題了…
moazzam at moazzam-khan dot com
15 年前
如果有人試圖用這個來存取 Sabre 的網路服務,那將行不通。 Sabre 會檢查請求標頭「Content-Type」是否為「text/xml」。如果不是 text/xml,它就會回傳錯誤。

您需要建立一個 Socket 連線,並使用它來發送請求。
stephenlansell at gmail dot com
14 年前
以下是一個 php 用戶端與 asmx 伺服器通訊的範例

<?php

$soapClient
= new SoapClient("https://soapserver.example.com/blahblah.asmx?wsdl");

// 準備 SoapHeader 參數
$sh_param = array(
'Username' => 'username',
'Password' => 'password');
$headers = new SoapHeader('http://soapserver.example.com/webservices', 'UserCredentials', $sh_param);

// 準備 Soap Client
$soapClient->__setSoapHeaders(array($headers));

// 設定 RemoteFunction 參數
$ap_param = array(
'amount' => $irow['total_price']);

// 呼叫 RemoteFunction ()
$error = 0;
try {
$info = $soapClient->__call("RemoteFunction", array($ap_param));
} catch (
SoapFault $fault) {
$error = 1;
print(
"
alert('抱歉,blah 回傳了以下錯誤: "
.$fault->faultcode."-".$fault->faultstring.". 我們現在將帶您回到首頁。');
window.location = 'main.php';
"
);
}

if (
$error == 0) {
$auth_num = $info->RemoteFunctionResult;

if (
$auth_num < 0) {
....

// 設定 OtherRemoteFunction() 參數
$at_param = array(
'amount' => $irow['total_price'],
'description' => $description);

// 呼叫 OtherRemoteFunction()
$trans = $soapClient->__call("OtherRemoteFunction", array($at_param));
$trans_result = $trans->OtherRemoteFunctionResult;
....
} else {
// 將交易錯誤記錄到資料庫中

// 斷開 Soap 連線
unset($soapClient);
}
}
}
}

?>
rafinskipg at gmail dot com
12 年前
透過新增這段程式碼到您的專案來支援 MTOM

<?php
類別 MySoapClient 繼承 SoapClient
{
公開函式
__doRequest($request, $location, $action, $version, $one_way = 0)
{
$response = parent::__doRequest($request, $location, $action, $version, $one_way);
// 解析 $response,擷取多部分訊息等等

//這部分移除一些內容
$start=strpos($response,'<?xml');
$end=strrpos($response,'>');
$response_string=substr($response,$start,$end-$start+1);
return(
$response_string);
}
}

?>

然後你可以這樣做
<?php
new MySoapClient($wsdl_url);
?>
To Top