PHP SoapClient: неизвестное расширение WSDL

Я пытаюсь реализовать веб-службу, запущенную в системе SAP PI. WSDL, который я получил, выглядит так:

<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="request_SO" targetNamespace="http://company.ch/orstest/jason_test" xmlns:p1="http://company.ch/orstest/jason_test" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <wsdl:documentation/> <wsp:UsingPolicy wsdl:required="true"/> <wsp:Policy wsu:Id="OP_request_SO"/> <wsdl:types> <xsd:schema targetNamespace="http://company.ch/orstest/jason_test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://company.ch/orstest/jason_test"> <xsd:element name="request" type="request"/> <xsd:element name="response" type="response"/> <xsd:complexType name="request"> <xsd:annotation> <xsd:appinfo source="http://sap.com/xi/VersionID">a8b7948ac2e211e2b2380000001f0d6a</xsd:appinfo> </xsd:annotation> <xsd:sequence> <xsd:element name="body" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="response"> <xsd:annotation> <xsd:appinfo source="http://sap.com/xi/VersionID">bf49af09c36c11e299790000001f0d6a</xsd:appinfo> </xsd:annotation> <xsd:sequence> <xsd:element name="body" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:schema> </wsdl:types> <wsdl:message name="request"> <wsdl:documentation/> <wsdl:part name="request" element="p1:request"/> </wsdl:message> <wsdl:message name="response"> <wsdl:documentation/> <wsdl:part name="response" element="p1:response"/> </wsdl:message> <wsdl:portType name="request_SO"> <wsdl:documentation/> <wsdl:operation name="request_SO"> <wsdl:documentation/> <wsp:Policy> <wsp:PolicyReference URI="#OP_request_SO"/> </wsp:Policy> <wsdl:input message="p1:request"/> <wsdl:output message="p1:response"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="request_SOBinding" type="p1:request_SO"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/> <wsdl:operation name="request_SO"> <soap:operation soapAction="http://sap.com/xi/WebService/soap1.1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/> <wsdl:input> <soap:body use="literal" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/> </wsdl:input> <wsdl:output> <soap:body use="literal" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="request_SOService"> <wsdl:port name="HTTP_Port" binding="p1:request_SOBinding"> <soap:address location="http://qa1100ap601.company.car.web:50000/XISOAPAdapter/MessageServlet?senderParty=&amp;senderService=BS_ORS&amp;receiverParty=&amp;receiverService=&amp;interface=request_SO&amp;interfaceNamespace=http://company.ch/orstest/jason_test" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/> </wsdl:port> <wsdl:port name="HTTPS_Port" binding="p1:request_SOBinding"> <soap:address location="https://qas.soa.subcompany.company.ch/XISOAPAdapter/MessageServlet?senderParty=&amp;senderService=BS_ORS&amp;receiverParty=&amp;receiverService=&amp;interface=request_SO&amp;interfaceNamespace=http://company.ch/orstest/jason_test" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/> </wsdl:port> </wsdl:service> </wsdl:definitions> 

Мой PHP-файл выглядит так (в нем больше ничего нет):

 <?php $client = new SoapClient('test.wsdl'); ?> 

Когда я запускаю свой скрипт, я получаю следующую ошибку:

 Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Unknown required WSDL extension 'http://schemas.xmlsoap.org/ws/2004/09/policy' in /srv/www/htdocs/wsdl.php:2 Stack trace: #0 /srv/www/htdocs/wsdl.php(2): SoapClient->SoapClient('test.wsdl') #1 {main} thrown in /srv/www/htdocs/wsdl.php on line 2 

Я попытался найти ошибку в google и StackOverflow, а также проверить комментарии на php.net, но я не могу понять, что мне нужно изменить, чтобы запустить эту службу. Я также пытался открыть URL-адрес расширения WSDL, похоже, существует.

Может ли кто-нибудь бросить мне кость? Я попытался удалить URL-адрес расширения, что приводит к следующей ошибке:

 Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Unexpected WSDL element <UsingPolicy> in /srv/www/htdocs/wsdl.php:2 Stack trace: #0 /srv/www/htdocs/wsdl.php(2): SoapClient->SoapClient('test.wsdl') #1 {main} thrown in /srv/www/htdocs/wsdl.php on line 2 

Единственное решение, о котором я могу думать, это обновить тэг UsePolicy:

Измените тег:

 <wsp:UsingPolicy wsdl:required="true"/> 

к этому:

 <wsp:UsingPolicy wsdl:required="false"/> 

Это не совсем правильный ответ в среде SAP. В URL-адресе WSDL вы увидите /ws_policy/ – измените это на /standard/ и вы сможете использовать класс PHP SoapClient для использования веб-службы без необходимости поддерживать локальную модифицированную копию WSDL. Вы можете увидеть то же самое в блоге SAP здесь (логин, возможно, требуется).

Для новых версий URL-адрес больше не содержит «ws_policy», вместо этого существует 0 (стандартная) или 1 (политика)

Пример:

…. wsdl / flv_10002A1 1 1AD1 / bndg_url / …. (ws_policy)

…. wsdl / flv_10002A1 0 1AD1 / bndg_url / …. (стандарт)

Кредиты Рафа Мартинесу

Кажется, это ошибка в PHP SOAPServer или недостающая совместимость с расширением, и она еще не решена, по крайней мере, в PHP 5.6.31.

Единственное решение, которое я смог найти, – установить требуемую UsingPolicy в false , как это было предложено в принятом ответе:

 <wsp:UsingPolicy wsdl:required="false" /> 

Но клиенты могут получить доступ к службе SOAP без аутентификации, что является серьезной проблемой безопасности. Итак, я попытался вручную проверить, что данные безопасности отправляются клиентом.

 $soapEnvelope = new DOMDocument(); $soapEnvelope->loadXML(file_get_contents("php://input"), LIBXML_DTDATTR); $wsseNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; if ($soapEnvelope->getElementsByTagNameNS($wsseNamespace, 'Security')->length == 0) { throw new SoapFault("auth", 'Authentication error - Missing wsse:Security node'); } if ($soapEnvelope->getElementsByTagNameNS($wsseNamespace, 'UsernameToken')->length == 0) { throw new SoapFault("auth", 'Authentication error - Missing UsernameToken node'); } if ($soapEnvelope->getElementsByTagNameNS($wsseNamespace, 'Username')->length == 0) { throw new SoapFault("auth", 'Authentication error - Missing Username node'); } if ($soapEnvelope->getElementsByTagNameNS($wsseNamespace, 'Password')->length == 0) { throw new SoapFault("auth", 'Authentication error - Missing Password node'); } // SOAPServer handle requests method $server->handle(); 

Это грязный трюк, но он работает.