PHP 日本大会 2024

SOAP 函数

目录

添加注释

用户贡献的注释 30 条注释

5
Norman Clarke <norman at dontblink dot com>
19 年前
请注意,如果您需要设置 SOAP 请求的超时时间,可以使用 ini_set 更改 default_socket_timeout 的值。我之前使用的是 NuSOAP,其 soap 客户端类具有超时选项,我花了一段时间才弄清楚 PHP 的 soap 使用与其他所有内容相同的套接字选项。
5
ckl at ecw dot de
18 年前
要使用 SoapServer()、WSDL 文件和 Zend Studio 客户端/服务器调试 SOAP 服务,您必须将 ?start_debug=1&amp;debug_port=10000 附加到服务位置
--- 省略 ---
... 方法/服务定义 ....

<service name="SOAPService">
<port
name="SOAPServicePort"
binding="typens:SOAPServiceBinding">
<soap:address
location="$URL?start_debug=1&amp;debug_port=10000"/>
</port>
</service>
--- 省略 ---
4
Darryl
19 年前
使用 WSDL 模式下的 PHP SoapServer 通过 SOAP 传递复杂类型时遇到问题?解码不正确?这可能是您正在寻找的解决方案!

在 WSDL 文件的 schema 部分使用 ComplexType 时,您需要采取额外步骤来告诉 PHP SOAP 如何编码对象。第一种方法是将对象明确封装在 SoapVar 对象中 - 告诉 PHP 使用通用的 SOAP 编码规则(将所有 ComplexType 编码为结构)。但是,如果客户端期望根据 WSDL 的模式对对象进行编码,则此方法无效。因此,实际的方法是

* 首先,定义一个特定的 PHP 类,它实际上只是一个数据结构,包含各种属性以及 WSDL 中相应的 ComplexType。

<?php
class MyComplexDataType {
public
$myProperty1;
public
$myProperty2;
}
?>
<complexType name="MyWSDLStructure">
<sequence>
<element name="MyProperty1" type="xsd:integer"/>
<element name="MyProperty2" type="xsd:string"/>
</sequence>
</complexType>

* 接下来,在初始化 SoapServer 时告诉它将这两个结构映射在一起。

<?php
$classmap
= array('MyWSDLStructure' => 'MyComplexDataType');
$server = new SoapServer("http://MyServer/MyService.wsdl", array('classmap' => $classmap))
?>

* 最后,让您的方法直接返回类的实例,并让 SoapServer 处理编码!

<?php
public function MySoapCall() {
$o = new MyComplexDataType();

$o->myProperty1 = 1;
$o->myProperty2 = "MyString";

return
$o
}
?>
3
匿名用户
17 年前
处理 wsdl 和 flash soap 与 php 时
(不完全是 php,而是正确的 wsdl - 我花了几个小时才弄清楚它在 flash webservice 中正常工作)

命名定义时,
不要使用“tns:”而使用“typens:”

确保您的“definitions/targetNamespace”
与您的“soap:body”命名空间相同
示例:“urn:mynamespace”

确保您的“binding/type”使用“typens”声明

确保您的 service/port/binding 设置为 'typens:...'

如果您没有正确操作,最终会得到
WSDL.UnrecognizedNamespace - 在 flash 中
但在 php soapclient 中似乎没问题……

编码愉快 :)
希望这能帮助您节省在 wsdl 上的时间 :)
3
kroesjnov at hotmail dot com
17 年前
如果您不想手动维护 classmap,请确保为您的 PHP 对象类和 WSDL complexTypes 使用相同的名称,并使用以下代码

$classmap = array();
$tmpClient = new SoapClient("soapserver.wsdl");

foreach($tmpClient->__getTypes() as $type)
{
$array = split(" ", $type);
if($array[0] == "struct" && class_exists($array[1]))
{
$classmap[$array[1]] = $array[1];
}
}
unset($tmpClient);

$server = new SoapServer("soapserver.wsdl", array("classmap" => $classmap));
unset($classmap);
$server->setClass("someclass");
$server->handle();
3
dirk at waferthin dot com
17 年前
我希望这能节省一些人的时间。在开发和测试您的 SOAP 服务器时,请记住在客户端和服务器中都禁用 WSDL 缓存

$ini = ini_set("soap.wsdl_cache_enabled", 0);
3
Dominik
16 年前
如果您正在
- 本地主机上
- 在 WSDL 模式下
尝试使用 soap 客户端连接 soap 服务器时遇到以下错误

致命错误:未捕获的 SoapFault 异常:[HTTP] 无法连接到主机……

然后在您的 WSDL 文件中将“localhost”更改为“127.0.0.1”
<soap:address location='http://127.0.0.1/soap-server.php'/>
3
mini at freebsd dot org
18 年前
wokan at cox dot net 对通过 URI 传递到 HTTPS URI 的值的安全性说法是不正确的。HTTPS 连接是 SSL 内部的 HTTP —— 所有 HTTP 流量,包括请求,都已加密。
2
Bob
19 年前
如果您正在苦思冥想为什么 NuSOAP 在 PHP 5.x 上不起作用,原因是此内置 SOAP 扩展使用与 Nusoap 相同的 soapclient() 类名。

将 nusoap.php 中的“soapclient”替换为“soapclient_xxx”,您就可以开始了……
2
jochen dot munz at municons dot com
17 年前
遇到这样的错误消息时

[faultstring] => 此服务的无效方法 ("yourMethod") 函数

虽然WSDL等文件中存在,但请注意PHP为了提高性能会将wsdl缓存在本地。您可以通过php.ini/.htaccess完全禁用缓存,或者删除缓存文件(如果您使用的是Linux,则为/tmp/wsdl-..),以强制重新生成它。
2
ChrisB
19 年前
对于任何使用PHP Soap + Sessions + PEAR DB类的人员的提示。

每次通过soap客户端调用您的Web服务时,您的PEAR DB会话都会被挂起,并且默认情况下不会在下一个请求中唤醒。

为了解决这个问题,我只是在我的$soap->handle()之后调用了我特定的数据库关闭调用ifx_close()。
2
albert at jool dot nl
17 年前
对于在Windows配置下使用SOAP证书的人员的说明:似乎需要提供证书文件的完整路径 - 并且不要添加前缀'file://'。

<?php

$wsdl
= "test.wsdl";
$local_cert = "c:\htdocs\mycert.pem";
$passphrase = "xyz";

$client = new SoapClient($wsdl, array('local_cert' => $local_cert, 'passphrase' => $passphrase);

?>
2
flobee at gmail dot com
19 年前
哇,实际上是一个很酷的程序,而且soap对我来说是新的。
我发现了一些我无法调试的东西,因为脚本在没有任何错误消息或提示的情况下就退出了。 :-(

您可能会遇到内存问题,尤其是在服务器负载很高的情况下,在“共享服务器”上尤其如此。
有时脚本可以完成工作,有时它会在任何未知点停止。
这些是我的脚本执行的步骤
* 从远程服务器获取数据(约4.5 MB)
* 解析请求的对象并将数据存储到数据库中。

带有调试消息的返回值很有趣
-> 检查内存限制:30M
-> $client = new new SoapClient($url_wsdl, $options);
-> 内存使用量:185888
-> $client->[requested_method_to_get_data]();
-> 检查:__getLastResponseHeaders() -之后
-> HTTP/1.1 200 OK // 远程服务器对我来说没问题 :-)
-> Content-Length: 4586742 // 我得到了数据
-> 检查:现在的内存使用量:23098872 // 哎呀!!!这不可能是真的!!

所以,如果现在服务器上的某人占用剩余的RAM,则遍历数据就会中断 :-(

所以,我需要存储XML树($client->client->__last_response)并通过经典方式解析它。(如果您请求更多RAM,如果您更频繁地运行这样的脚本,则可能会遇到管理员的麻烦!(在共享服务器上)
2
AL13N
17 年前
这可能会有所帮助,因为我花了相当长的时间才发现这一点

如果您使用的是一些.wsdl,并且存在可以多次出现的序列(即:maxOccurs > 1),如果您有多个项目,则可以为其指定一个非关联数组;或者,如果只有一个项目,则可以只指定该项目。

<?php
'items' => array(
array(
'itemId' => 5,
'name' => 'some name',
),
array(
'itemId' => 6,
'name' => 'some other name',
),
),
?>

这也适用

<?php
'items' => array(
'itemId' => 5,
'name' => 'some name',
),
?>
2
kucerar at hhmi dot org
19 年前
这里有73个测试用例,详细说明了PHP5目前支持的模式类型以及您应该插入其中的结构,作为服务的返回值。比猜测好得多!

http://cvs.php.net/co.php/pecl/soap/tests/schema

您可以通过更改下面URL中的主索引来循环浏览列表,而无需进出页面

http://cvs.php.net/co.php/pecl/soap/tests/schema/schema052.phpt?r=1.2

我用这个下载了全部内容,CVS也可能有效。
http://www.httrack.com/

下载完成后,我用Textpad浏览它们。
1
adm
18 年前
想知道为什么您刚刚添加到WSDL文件中的函数无法用于您的SOAP客户端?关闭WSDL缓存,(如文档中所述)默认情况下它是开启的。

在脚本顶部使用

$ini = ini_set("soap.wsdl_cache_enabled","0");
0
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()
0
rlee at melbournechapter dot net
16 年前
关于“DTD未识别...”错误的说明。检查以确保您的wsdl文件包含

<?xml version ='1.0' encoding ='UTF-8' ?>

还要确保您使用完整路径到您的服务(在wsdl、客户端和服务器中)
...
<wsdlsoap:address location='http://www.mysite.com.au/web_services/myserver.php' />
...
<?php
// SOAP服务器
$server = new SoapServer('http://www.mysite.com.au/web_services/hello.wsdl');
...
...
?>

<?php
// SOAP客户端
$client = new SoapClient('http://www.mysite.com.au/web_services/hello.wsdl');
...
...
?>

FYI,我不是SOAP专家,但我希望这对某些人有所帮助;)
0
Drydenmaker
16 年前
与第三方服务合作时,我收到错误消息:“SOAP-ERROR: Parsing Schema: unexpected <text> in restriction”

我认为分享一下值得。它的意思是某个位置存在一些无效文本。C#似乎忽略了它,如果你使用nusoap,它也不会注意到它。但导致我问题的原因是这样的
<types>
<schema ...

<simpleType name="some type">
<restriction base="xsd:string">
<enumeration value="foo"/>;
</restriction>
</simpleType>

注意分号(;)。过滤掉它就可以了。
0
james at mercstudio dot com
17 年前
如果你使用wsdl,

请确保正确定义输入。
如果你的方法不包含任何输入参数,
你必须确保:

- 不要为输入创建消息标签。
- 不要在porttype/operation中放置输入。
- 不要在binding/operation中放置输入。

否则,你会收到错误
[客户端] 看起来我们没有收到XML

d***,我花了几个小时才找出原因……
0
brephophagist
17 年前
对于那些使用充满了复杂类型的wsdl,只想获得一个类结构来挂载代码,并且不想担心输入冗长的参数列表(或创建脚本来执行此操作)的人来说:wsdl2php是一个极好的省时工具。它会生成一个结构,这样你就可以添加所需的验证和特殊数据处理: http://www.urdalen.no/wsdl2php/

为你自己点赞,Knut。
0
Olaf Krische
18 年前
如果你使用带有证书和密码身份验证的SSL

$wsdl = "https://ws.ecopatz.de/ProductInfo?wsdl";
$pass = 'a password';
$certFile = "./mycert.pem";

$client = new SoapClient($wsdl,
array(
'local_cert' => $certFile,
'passphrase' => $pass
)
);

如果你遇到类似这样的证书文件问题

Warning: SoapClient::__construct(): Unable to set local cert chain file `./mycert.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in productinfo.php on line 27

那么证书文件可能格式错误(可能是PHP的错误格式)。当我将私钥文件和证书文件的内容追加到单个文件“mycert.pem”中时,它对我有用。

cat mycert.key >mycert.pem # mycert.key 是私钥
cat mycert.crt >>mycert.pem # mycert.crt 是已签名的证书

感谢某位作者,他指出了“curl --cert”,其中提到了这个“非常不重要”的依赖项。
0
nico
18 年前
如果你想为Microsoft Office的客户端(如Microsoft Office Research Service)构建SOAP服务器,你需要重写SOAP的命名空间

<?php
// (...)

$server = new SoapServer($wsdl, array('uri' => $uri, 'classmap' => $classmap));
$server->setClass($class);
function
callback($buffer)
{
$s = array('<ns1:RegistrationResponse>', 'ns1:', 'xmlns:ns1="urn:Microsoft.Search"');
$r = array('<RegistrationResponse xmlns="urn:Microsoft.Search">', '', '');
return (
str_replace($s, $r, $buffer));
}
ob_start('callback');
$server->handle();
ob_end_flush();

// (...)
?>

此URL中有一个完整的示例: http://touv.ouvaton.org/article.php3?id_article=104
0
Rui Martins
18 年前
以下是如何传递ArrayOfAnyType参数的示例
包含复杂类型。

假设你的WSDL文件定义了 "http://any.url.com/" 作为默认命名空间和复杂类型"SomeComplexType"。

如果你想调用一个接受"SomeComplexType"的ArrayOfAnyType参数的Web服务,你需要执行以下操作

<?php
// complexTypes 是一个包含多个 SomeComplexType 实例的数组

myWSParameter = array();
foreach (
complexTypes as ct)
{
// 不要拼错类型或命名空间。还要注意,php不会假设WSDL文件中定义的默认命名空间。
myWSParameter []= new SoapVar(ct, 0, "SomeComplexType", "http://any.url.com/");
}
?>

另一方面,当Web服务返回ArrayOfAnyType时,你需要执行以下操作来访问其每个元素。

<?php
// 在这里,我们将输出每个返回项
$res = $someWS->myFunction($myArgs)

// 如果只返回一个元素,则不会构建数组
if (is_array(myFunctionResult->anyType))
{
foreach (
myFunctionResult->anyType as $soapVar)
{
echo
$soapVar->enc_value;
}
}
else
{
echo
myFunctionResult->anyType->enc_value;
}
?>

所有这些都已使用.NET Web服务进行了测试。
0
Jim Plush
19 年前
如果你尝试通过SSL使用自定义PEM文件来使用SOAP扩展,你需要这样做

$client->_local_cert = "C:\\path\myCert.pem";
0
OrionI
19 年前
如果你在调用.NET web服务时遇到问题,请查看https://php.net/soap_soapclient_soapcall(__soapCall方法)上的评论。
0
wokan at cox dot net
19 年前
在URI中传递用户名和密码并不是良好的安全实践,因为SSL的目的是防止这些信息被拦截。将这些信息放在URI中会使其可被拦截。HTTPS发布的值是安全的,因为在标头中传递的值是在SSL握手完成之后发送的。
0
mikx at mikx dot de
20年前
我花了一段时间才通过Windows/Apache1.3上的https正确建立受密码保护的客户端连接。这是我的简要指南

1. SOAP扩展默认情况下未激活(PHP5 RC1)。只需将“extension=php_soap.dll”添加到php.ini中,并不要忘记正确设置extension_dir(在大多数情况下为“c:\php\ext”)。

2. 将“extension=php_openssl.dll”添加到php.ini中。此模块依赖于libeay32.dll和ssleay32.dll - 将它们从你的php文件夹复制到你的system32文件夹。

3. 重启apache

4. 源代码

$client = new SoapClient("https://yourLogin:[email protected]/bar.wsdl", array(
"login" => "yourLogin",
"password" => "yourPassword",
"trace" => 1,
"exceptions" => 0));

$client->yourFunction();

print "<pre>\n";
print "Request: \n".htmlspecialchars($client->__getLastRequest()) ."\n";
print "Response: \n".htmlspecialchars($client->__getLastResponse())."\n";
print "</pre>";

目前似乎需要在uri和options数组中同时添加你的登录名和密码。不确定这是否是预期的行为。
-1
vIceBerg
16 年前
我的电脑上安装的是PHP 5.2.5。我得到以下结果

数组
(
[0] => stdClass 对象
(
[客户端] => stdClass 对象
(
[Nom] => LeNom:00000
[Prenom] => LePrenom:00000
)

)

我的主机使用的是5.1.6,相同的调用返回以下结果
数组
(
[0] => stdClass 对象
(
[客户端] => 数组
(
[0] => stdClass 对象
(
[Nom] => LeNom:00000
[Prenom] => LePrenom:00000

)

5.2.5是好的结构。

注意你使用的版本。更改所有代码可能需要大量工作
-1
johnjawed at gmail dot com
19 年前
对于那些想知道如何在PHP5 SOAP中设置节点属性的人,可以这样做

<... soap env/header>
<foo bar="blah">12345</foo>

array("foo" => array("_" => 12345, "bar" => "blah"));
To Top