Ошибка неправильной версии PHP Soap Client с сервером SOAP, возвращающим правильный ответ

У меня проблема с SOAP-запросом при подключении к веб-службе.

Во-первых, это мой код:

$soapClient = new NewSoapClient(null, [
        'location' =>
            "https://www.phobs.net/test/webservice/pc/service.php",
        'uri'      => "http://www.opentravel.org/OTA/2003/05",
        'trace'    => 1,
        "soap_version" => SOAP_1_1,
    ]);


    $ns_wsse = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
    $password_type = 'ns2:http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText';

    // Creating WSS identification header using SimpleXML
    $root = new \SimpleXMLElement('<root/>');

    $security = $root->addChild('ns2:Security', null, $ns_wsse);

    $usernameToken = $security->addChild('ns2:UsernameToken', null, $ns_wsse);
    $usernameToken->addChild('ns2:Username', 'username', $ns_wsse);
    $usernameToken->addChild('ns2:Password', 'pass', $ns_wsse)->addAttribute('xsi:xsi:type', $password_type);
    $root->registerXPathNamespace('ns2', $ns_wsse);
    $full = $root->xpath('/root/ns2:Security');
    $auth = $full[0]->asXML();

    $auth = str_replace(' xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"','', $auth);

    $soapClient->__setSoapHeaders(new \SoapHeader($ns_wsse, 'Security', new \SoapVar($auth, XSD_ANYXML), true));

    try {

        $response = $soapClient->__soapCall("OTA_RoomRateListRQ",[
            new \SoapVar('<ns1:HotelInfo HotelCode="' . 'ATL476' . '" DestinationSystemCode="' . 'ATLANTIS' . '" />', XSD_ANYXML)
        ]);

    } catch (\SoapFault $exception)
    {

        var_dump($exception);
        //die();
    }


    $response = json_decode(json_encode((array)simplexml_load_string($soapClient->__getLastResponse())),1);

И у меня есть оболочка для собственного класса PHP Soap Client:

class NewSoapClient extends \SoapClient

{

public function __doRequest($request, $location, $action, $version, $one_way = 0)
{

    $string = '<?xml version="1.0" encoding="UTF-8"?>';

    $request = str_replace($string , '', $request);

    $request = str_replace('xmlns:xsd="http://www.w3.org/2001/XMLSchema"', 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"', $request);

    $request = str_replace('xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"', '', $request);

    $request = str_replace('xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >', 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">', $request);

    $request = trim($request);


    return parent::__doRequest($request, $location, $action, $version, $one_way); // TODO: Change the autogenerated stub
}

}

Таким образом, в основном он подключается к веб-службе SOAP (без WSDL) и извлекает некоторые данные. Большая часть этого кода предназначена только для манипуляций со строками (или XML), поэтому запрос может выглядеть точно так же, как в документации веб-сервиса SOAP. Окончательный запрос (после всех доработок) выглядит так:

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://www.opentravel.org/OTA/2003/05"
xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
    <ns2:Security>
        <ns2:UsernameToken>
            <ns2:Username>username</ns2:Username>
            <ns2:Password xsi:type="ns2:http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pass</ns2:Password>
        </ns2:UsernameToken>
    </ns2:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
    <ns1:OTA_RoomRateListRQ>
        <ns1:HotelInfo HotelCode="ATL476" DestinationSystemCode="ATLANTIS" />
    </ns1:OTA_RoomRateListRQ>
</SOAP-ENV:Body>

So basically my request is the same as the request in documentation. When I trigger this code I get SoapFault exception with message "Wrong version" and fault code "VersionMismatch" and with faultcodens "http://schemas.xmlsoap.org/soap/envelope/".

Важно отметить, что если я оборачиваю вызов SOAP в блоки try/catch и не добавляю никакой логики, которая реагирует на исключение (оставляя блок catch пустым), ответ будет возвращен с кодом состояния 200 и будет проанализирован. нормально, и мой скрипт завершит выполнение без каких-либо ошибок.

Исключение определенно выбрасывается, но если я не реагирую на него, жизненный цикл запроса завершается успешно. В чем причина этой ошибки? Как справиться с этим? Должен ли я просто оставить блок catch открытым без какой-либо логики? Есть ли лучшее решение?

Еще немного информации о системе. Версия SOAP такая же, как в документации (1.1). Моя версия PHP 7.2, у меня нет доступа к серверу SOAP, поэтому версия, которая там работает, неизвестна...

Спасибо


person Andrija Glavas    schedule 26.11.2018    source источник


Ответы (1)


РЕДАКТИРОВАНИЕ после решения: обязательно ознакомьтесь с обсуждением в комментариях под моим ответом. Оказалось, что сам сервис возвращает не SOAP, а XML, что и вызывает исключение!

Старый ответ:

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

В противном случае мое дикое предположение заключается в том, что служба теперь может ожидать конверт версии SOAP 1.2 (без его надлежащего обновления в рассматриваемой документации), и вы отправляете версию 1.1, поэтому вы можете попробовать изменить:

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

to xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"

и посмотреть, что происходит. Стоит попробовать... Подобный вопрос уже обсуждался здесь , ищите больше подсказок.

person Plamen Petrov    schedule 27.11.2018
comment
Я использую Postman для тестирования веб-службы SOAP. Как я уже говорил ранее, запрос SOAP из документации, а также из моего сценария (запросы идентичны) действительны, служба SOAP их принимает, я получаю ответ с кодом состояния 200 (через Postman), так что проблем нет. Итак, я начал разрабатывать клиент SOAP на PHP, и мне удалось создать идентичный запрос с использованием клиента PHP Soap (код выше). Когда я запускаю запросы от клиента PHP Soap, я действительно получаю правильный ответ, просто клиент PHP Soap выдает исключение VersionMismatch. - person Andrija Glavas; 27.11.2018
comment
Если я обработаю это исключение или просто оставлю его пустым (блок перехвата), я смогу получить ответ. Получение ответа — последняя строка в первом сниппете. Итак, реальный вопрос заключается в том, почему PHP Soap Client генерирует исключения, если запрос передан и получен ответ? Я также попытался изменить версию на SOAP1.2, в этом случае я не получаю ответа, поэтому это должен быть SOAP1.1. Вот такие подробности, как конечная точка и полный запрос: pastebin.com/TWyp8RYN Я был бы очень рад, если бы вы могли дать это взгляд. Спасибо - person Andrija Glavas; 27.11.2018
comment
Привет, @Andria, у меня нет полной настройки и я не могу правильно отладить, но не могли бы вы запустить wireshark, чтобы доказать, что то, что вы отправляете, действительно идентично тому, что отправляете через Postman? Я попытался поиграть с предоставленным запросом, и я заметил, что полученный ответ не является полностью действительным SOAP, а представляет собой обычный xml. Может дело в этом, а не в самом запросе? - person Plamen Petrov; 27.11.2018
comment
Да, ответ несет ответственность за ошибку. Клиент PHP Soap ожидает действительный ответ SOAP с конвертом и другими частями. В противном случае будет выдано исключение, как указано во внутренних компонентах PHP Soap: rel="nofollow noreferrer">github.com/GoogleCloudPlatform/appengine-php/blob/ Спасибо, что указали мне правильное направление. - person Andrija Glavas; 28.11.2018