PHP SOAP客户端可以理解多部分消息吗?

2ul0zpep  于 2023-06-04  发布在  PHP
关注(0)|答案(8)|浏览(644)

有这样的野兽吗?PHP附带的简单SOAP client不能理解多部分消息。先谢谢你了。

clj7thdc

clj7thdc1#

尽管在这里已经给出了很多答案,但我还是提出了一个通用的解决方案,它要记住,XML可以没有 Package 器。

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;
    }
}

只有在使用选项trace => true初始化SoapClientExtended时,此操作才有效。

w9apscun

w9apscun2#

使用格里克的第二个想法在这里工作得很好。
大多数情况下,您只有一条消息打包成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;
    }
}
jckbn6z7

jckbn6z73#

遵循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);
?>
siotufzp

siotufzp4#

只是为了给以前建议的步骤增加更多的光。您必须以以下格式获得响应

--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;
}
hsgswve4

hsgswve45#

恕我直言,再简单一点

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;
    }
}
b5buobof

b5buobof6#

这段代码在我使用“trace => true”选项时也能正常工作。
感谢分享!

jgovgodb

jgovgodb7#

我在这里工作

class MySoapClient extends SoapClient

{ public function __doRequest($request,$location,$action,$version,$one_way = 0){ $response = parent::__doRequest($request,$location,$action,$version,$one_way);//去掉除了XML之外的所有内容。$response = preg_replace('#^.(<?xml.>)[^>]*$#s','$1',$response); return $response;{\fnSimHei\bord1\shad1\pos(200,288)}

3zwtqj6y

3zwtqj6y8#

原生PHP SoapClient类不支持多部分消息(并且在所有WS-* 事务中受到严格限制),我也认为PHP编写的库NuSOAPZend_Soap都不能处理这种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
    }
}

这可能有点棘手,但值得一试。

  • 使用更复杂的SOAP客户端库。我想到的第一个也是唯一一个是WSO2 WSF/PHP,它具有SOAP MTOM,WS-Addressing,WS-Security,WS-SecurityPolicy,WS-Secure Conversation和WS-ReliableMessaging,但必须安装原生PHP扩展。

相关问题