有这样的野兽吗? PHP附带的简单SOAP client不了解多部分消息。提前谢谢。
答案 0 :(得分:12)
本机PHP SoapClient
类不支持多部分消息(并且在所有WS- *事务中受到很大限制)而且我认为既不是PHP编写的库NuSOAP也不是{{3}可以处理这种SOAP消息。
我可以想到两个解决方案:
扩展SoapClient
类并覆盖SoapClient::__doRequest()
方法以获取实际的响应字符串,然后您可以随意解析。
class MySoapClient extends SoapClient
{
public function __doRequest($request, $location, $action, $version, $one_way = 0)
{
$response = parent::__doRequest($request, $location, $action, $version, $one_way);
// parse $response, extract the multipart messages and so on
}
}
虽然这可能有点棘手 - 但值得一试。
为PHP使用更复杂的SOAP客户端库。第一个也是唯一一个我想到的是Zend_Soap,其中包括SOAP MTOM,WS-Addressing,WS-Security,WS-SecurityPolicy,WS-Secure Conversation和WS-ReliableMessaging,代价是必须安装本机PHP扩展。
答案 1 :(得分:3)
使用S. Gehrig的第二个想法在这里工作得很好。
在大多数情况下,您只有一条消息打包到MIME MultiPart消息中。在这些情况下,“ SoapFault异常:[客户端]看起来我们没有XML文档”抛出异常。这里下面的课应该做得很好:
class MySoapClient extends SoapClient
{
public function __doRequest($request, $location, $action, $version, $one_way = 0)
{
$response = parent::__doRequest($request, $location, $action, $version, $one_way);
// strip away everything but the xml.
$response = preg_replace('#^.*(<\?xml.*>)[^>]*$#s', '$1', $response);
return $response;
}
}
答案 2 :(得分:3)
遵循PHP文档中rafinskipg的建议:
支持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);
// parse $response, extract the multipart messages and so on
//this part removes stuff
$start=strpos($response,'<?xml');
$end=strrpos($response,'>');
$response_string=substr($response,$start,$end-$start+1);
return($response_string);
}
}
?>
然后你可以这样做
<?php
new MySoapClient($wsdl_url);
?>
答案 3 :(得分:2)
尽管这里已经给出了很多答案,但我已经把一个通用的解决方案放在一起,记住,XML可以没有包装器。
<html>
<head>
<script>
function toggle_visibility(id) {
var e = document.getElementById('hamburgermenu');
if(e.style.display == 'block')
e.style.display = 'none';
else
e.style.display = 'block';
}
</script>
<style>
#hamburgermenu {
display: none;
position: absolute;
z-index: 1000000;
height: 100%;
width: 100%;
margin-top: 50px;
background-color: rgba(0,0,0,.7);
}
</style>
</head>
<body>
<!-- HTML BUTTON FOR HIDE AND SHOW -->
<button onclick="toggle_visibility('hamburgermenu');">
<span class="glyphicon glyphicon-option-horizontal"></span>
</button>
<!-- HTML BUTTON FOR HIDE AND SHOW -->
<!-- HTML MOBILE MENU -->
<div id="hamburgermenu" >
<ul class="mobilemenu">
<li><a href="#">PROJECTEN</a></li>
<li><a href="#">SKILLSET</a></li>
<li><a href="#">STAGE</a></li>
<li><a href="#">OVER MIJ</a></li>
<li><a href="#">CONTACT</a></li>
</ul>
</div>
<!-- END HTML MOBILE MENU -->
</body>
这仅适用于使用选项class SoapClientExtended extends SoapClient
{
/**
* Sends SOAP request using a predefined XML
*
* Overwrites the default method SoapClient::__doRequest() to make it work
* with multipart responses.
*
* @param string $request The XML content to send
* @param string $location The URL to request.
* @param string $action The SOAP action. [optional] default=''
* @param int $version The SOAP version. [optional] default=1
* @param int $one_way [optional] ( If one_way is set to 1, this method
* returns nothing. Use this where a response is
* not expected. )
*
* @return string The XML SOAP response.
*/
public function __doRequest(
$request, $location, $action, $version, $one_way = 0
) {
$result = parent::__doRequest($request, $location, $action, $version, $one_way);
$headers = $this->__getLastResponseHeaders();
// Do we have a multipart request?
if (preg_match('#^Content-Type:.*multipart\/.*#mi', $headers) !== 0) {
// Make all line breaks even.
$result = str_replace("\r\n", "\n", $result);
// Split between headers and content.
list(, $content) = preg_split("#\n\n#", $result);
// Split again for multipart boundary.
list($result, ) = preg_split("#\n--#", $content);
}
return $result;
}
}
初始化SoapClientExtended
。
答案 4 :(得分:1)
只是为之前建议的步骤添加更多亮点。您必须以下列格式获得回复
--uuid:eca72cdf-4e96-4ba9-xxxxxxxxxx+id=108
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body> content goes here </s:Body></s:Envelope>
--uuid:c19585dd-6a5a-4c08-xxxxxxxxx+id=108--
只需使用以下代码(我使用正则表达式并不是那么好,所以使用字符串函数)
public function __doRequest($request, $location, $action, $version, $one_way = 0)
{
$response = parent::__doRequest($request, $location, $action, $version, $one_way);
// strip away everything but the xml.
$response = stristr(stristr($response, "<s:"), "</s:Envelope>", true) . "</s:Envelope>";
return $response;
}
答案 5 :(得分:0)
该代码也适用于我,选项“trace =&gt; true”。
感谢分享!
答案 6 :(得分:0)
更简单的恕我直言
class SoapClientUnwrappedXml extends SoapClient
{
const SOAP_ENVELOPE_REGEXP = '/^<soap:Envelope[^>]*>(.*)<\/soap:Envelope>/m';
/**
* Sends SOAP request using a predefined XML.
*
* Overwrites the default method SoapClient::__doRequest() to make it work
* with multipart responses or prefixed/suffixed by uuids.
*
* @return string The XML Valid SOAP response.
*/
public function __doRequest($request, $location, $action, $version, $one_way = 0): string
{
$result = parent::__doRequest($request, $location, $action, $version, $one_way);
$headers = $this->__getLastResponseHeaders();
if (preg_match('#^Content-Type:.*multipart\/.*#mi', $headers) !== 0) {
preg_match_all(self::SOAP_ENVELOPE_REGEXP, $result, $resultSanitized, PREG_SET_ORDER, 0);
$result = $resultSanitized[0][0] ?? $result;
}
return $result;
}
}