PHP SOAP client that understands multi-part messages?

后端 未结 7 565
死守一世寂寞
死守一世寂寞 2020-12-03 03:27

Is there such a beastie? The simple SOAP client that ships with PHP does not understand multi-part messages. Thanks in advance.

相关标签:
7条回答
  • 2020-12-03 04:01

    Just to add more light to previous suggested steps. You must be getting response in following format

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

    Just use following code (I am not that great with regex so using string functions)

     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;
    }
    
    0 讨论(0)
  • 2020-12-03 04:07

    Even though this answer has been given a lot here already, I have put together a general solutions, that keeps in mind, that the XML can come without the wrapper.

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

    This only works if you initialize the SoapClientExtended with the option trace => true.

    0 讨论(0)
  • 2020-12-03 04:13

    Using S. Gehrig second idea worked just fine here.

    In most cases, you have just a single message packed into a MIME MultiPart message. In those cases a "SoapFault exception: [Client] looks like we got no XML document" exception is thrown. Here the following class should do just fine:

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-03 04:18

    The code just worked for me with the option "trace => true" too.

    Thanks for sharing!

    0 讨论(0)
  • 2020-12-03 04:21

    A little bit more simple IMHO

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-03 04:22

    Follow the advice of rafinskipg from the PHP documentation:

    Support for MTOM addign this code to your project:

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

    Then you can do this

    <?php
      new MySoapClient($wsdl_url);
    ?>
    
    0 讨论(0)
提交回复
热议问题