PHP SOAP client that understands multi-part messages?

The native PHP SoapClient class does not support multipart messages (and is strongly limited in all WS-* matters) and I also I think that neither the PHP written libraries NuSOAP nor Zend_Soap can deal with this sort of SOAP messages.

I can think of two solutions:

  • extend the SoapClient class and overwrite the SoapClient::__doRequest() method to get hold of the actual response string which you can then parse at your whim.

    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 could be somewhat tricky though - but worth a try.

  • use a more sophisticated SOAP client library for PHP. The first and only one that comes into my mind is WSO2 WSF/PHP which features SOAP MTOM, WS-Addressing, WS-Security, WS-SecurityPolicy, WS-Secure Conversation and WS-ReliableMessaging at the cost of having to install a native PHP extension.


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.