Клиент PHP SOAP, который понимает многочастные сообщения?

Есть ли такая битва? Простой SOAP-клиент, который поставляется с PHP, не понимает многочастных сообщений. Спасибо заранее.

Ответ 1

Собственный класс PHP SoapClient не поддерживает многостраничные сообщения (и сильно ограничен во всех вопросах WS- *), и я также я что ни PHP письменные библиотеки NuSOAP, ни Zend_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 для PHP. Первый и единственный, который приходит мне в голову, - это WSO2 WSF/PHP, в котором есть SOAP MTOM, WS-Addressing, WS-Security, WS-SecurityPolicy, WS-Secure Conversation и WS-ReliableMessaging за счет необходимости установки собственного расширения PHP.

Ответ 2

Использование второй идеи С. Герига работало здесь очень хорошо.

В большинстве случаев у вас есть только одно сообщение, упакованное в сообщение MIME MultiPart. В таких случаях исключение SoapFault: [Client] выглядит так, как будто у нас нет 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;
    }
}

Ответ 3

Следуйте советам rafinskipg из документации PHP:

Поддержка 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);
?>

Ответ 4

Просто добавьте больше света к предыдущим предложенным шагам. Вы должны получать ответ в следующем формате

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

Несмотря на то, что этот ответ уже дан здесь, я собрал общие решения, которые имеют в виду, что XML может прийти без оболочки.

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 с помощью опции trace => true.

Ответ 6

Код просто работал у меня с опцией "trace = > true".

Спасибо за обмен!