2024 年 PHP 日本会议

SOAP

添加注释

用户贡献的注释 7 条注释

nodkz at mail dot ru
16 年前
问题(在 PHP5 下使用 SOAP 扩展)传输包含对象或对象数组的对象。嵌套对象无法传输。

解决方案
此类是由我通过反复试验开发的。因此,对于大多数在 PHP5 下编写代码的开发人员来说,这 23 行代码解决了使用 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; // 变量必须是受保护的或公共的!
}

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 格式。

WSDL 2.0 自 2007 年 6 月成为 W3C 建议,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 错误:解析 WSDL:在 'wsdl/example.wsdl' 中找不到 <definitions>,位于 /path/client.php 的第 9 行
Luke
9 年前
当时正在调用类似 `$success=$x->AuthenticateUser($userName,$password)` 的 ASMX 方法,此方法返回了一个错误。

但是我修改了代码,将用户名和密码放在一个数组中,现在一切正常……
moazzam at moazzam-khan dot com
15 年前
如果有人尝试使用此方法访问 Sabre 的 Web 服务,则无效。Sabre 会检查请求头“Content-Type”是否为“text/xml”。如果不是 text/xml,则会返回错误。

您需要创建一个套接字连接并使用它来发送请求。
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 客户端
$soapClient->__setSoapHeaders(array($headers));

// 设置远程函数参数
$ap_param = array(
'amount' => $irow['total_price']);

// 调用远程函数 ()
$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) {
....

// 设置其他远程函数 () 参数
$at_param = array(
'amount' => $irow['total_price'],
'description' => $description);

// 调用其他远程函数 ()
$trans = $soapClient->__call("OtherRemoteFunction", array($at_param));
$trans_result = $trans->OtherRemoteFunctionResult;
....
} else {
// 将事务错误记录到数据库中

// 关闭 Soap 连接
unset($soapClient);
}
}
}
}

?>
rafinskipg at gmail dot com
12 年前
将此代码添加到您的项目中以支持 MTOM

<?php
class MySoapClient extends SoapClient
{
public function
__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