PHP SoapServer (WSDL) 如何将 xml 命名空间设置为项目而不是 header?

PHP SoapServer (WSDL) How to set xml namespace to an item instead of header?

我有一个基于 wsdl 的小型 php soap 服务器,它可以处理 DLNA 请求。服务器代码看起来像其他数千个:

$srv = new SoapServer( "wsdl/upnp_av.wsdl" );
$srv->setClass( "ContentDirectory" );
$srv->handle();

并且有效。对于程序,它成功 returns SOAP 响应:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:schemas-upnp-org:service:ContentDirectory:1">
<SOAP-ENV:Body>
<ns1:GetSearchCapabilitiesResponse>
<SearchCaps>*</SearchCaps>
</ns1:GetSearchCapabilitiesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

这是绝对正确的 xml 语法。但我的大多数 DLNA 设备都不会接受这个答案(但东芝电视与它配合得很好)。所以我使用 Wireshark 并从其他 DLNA 服务器跟踪 xml,并发现所有这些服务器 return 略微另一个 xml,名称空间定义在 ns1 body,而不是信封。这是正确的示例行,所有设备都能很好地接受:

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:GetSearchCapabilitiesResponse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
<SearchCaps>*</SearchCaps>
</u:GetSearchCapabilitiesResponse>
</s:Body>
</s:Envelope>

所以“ContentDirectory”xmlns 刚从 header 移入一个块。两个 xml 在语法上都是正确的。

有些人也遇到了同样的问题:

Problem with WSDL

change soap prefixes in php

Soap Response Namespace issue

SoapServer maps functions incorectly when the wsdl messages have the same part name

PHP Soap Server response formatting

经过 2 天的研究,我想出了这个解决方法,将绑定从文档更改为 rpc 方法:

<soap:binding style="document"   -->   <soap:binding style="rpc"

但是当我这样做时,php 脚本崩溃了 [zend 引擎内部的某个地方?],所以我在 access.log 中有一行提到发生了 500 错误,但它没有显示在 error.log - 文件保持为空(当然,所有其他 500 错误都很好地转到 error.log)。

由于太大,我上传了WSDL文件:http://pastebin.com/ZNG4DqAn

还有其他方法可以解决这个问题吗?

请记住,TV 完全正确地处理此 xml 语法,并且一切都运行良好,但可能 android 电话会执行其他 xml 需要在该位置命名空间的解析器?就在现在,我已经准备好 preg_replaces() 将那个该死的 xmlns 移动到正确的位置 :),但我认为这不是 Jedies 的路径 :)

我的环境:PHP 5.4.20,Apache 2.2,Windows 2012

终于不成绝地武士了,手动替换成功了

function replace_xmlns( $soapXml )
{
$marker1 = "xmlns:ns1=";
$marker2 = "<ns1:";

$startpos = strpos( $soapXml, $marker1 );
$endpos   = strpos( $soapXml, "\"", $startpos + 14 );

$namespace = substr( $soapXml, $startpos, $endpos - $startpos + 1 );
$soapXml   = str_replace( $namespace, "", $soapXml );

$m2start = mb_strpos( $soapXml, $marker2 );
$m2end   = mb_strpos( $soapXml, '>', $m2start );

$soapXml = substr_replace( $soapXml, " " . $namespace, $m2end, 0 );

return $soapXml;
}