Я пытаюсь настроить SOAP-сервис в php. Я объявил серверную php-функцию, и я могу вызвать эту функцию с HTTP-запросом типа SOAP, где контент – это мой SOAP-конверт.
XML-контент тела SOAP является аргументом функции, которую я предполагаю, но я не знаю, как получить доступ к информации в ней в моем PHP-коде.
Я заметил, что аргумент функции является экземпляром stdClass
по умолчанию, и я действительно задаюсь вопросом, почему он не накладывается на объект XML
или DOM
по php – это SOAP-вызов, не так ли? Но все в порядке, теперь мне stdClass
, чтобы получить информацию из объекта, что непросто, потому что для stdClass
нет методов, поэтому это должны быть стандартные функции php. Поэтому я попробовал serialize
, но это дало мне немного мусора, а не строку XML, которую я ожидал.
Что делать?
РЕДАКТИРОВАТЬ
обратите внимание на то, что ниже нет кода примера того, что я хочу сделать – получить некоторые подробные данные из XML-содержимого запроса SOAP – потому что я не знаю, как закодировать его из объекта stdClass
По просьбе Дэвида, вот некоторые подробности.
PHP-код:
<?php function mi102($arg) { $txt = serialize ($arg); $result = new SoapVar ($txt, XSD_ANYXML); return($result); } ini_set( "soap.wsdl_cache_enabled", "0"); $server = new SoapServer ("test.wsdl"); $server -> addFunction ("mi102"); try { $server -> handle(); } catch (Exception $e) { $server -> fault ('Client', $e -> getMessage()); } ?php>
http-запрос создается приложением, которое я использую; заголовок http и оболочка мыла + тело генерируются вокруг XML, я его кормлю:
Содержимое тела запроса SOAP:
<mi102 xmlns="http://pse"> <cdhead cisprik="21"/> <instr> <insid> <bcdt>20120930</bcdt> </insid> </instr> </mi102>
Используемый WSDL выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://pse/" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="PSE" targetNamespace="http://pse/"> <types> <xs:schema> <xs:import namespace="http://pse/" schemaLocation="PSE.xsd"/> </xs:schema> </types> <message name="MI102Req"> <part name="cdhead" type="tns:cdhead_T"/> <part name="instr" type="tns:instr_T"/> </message> <message name="Res"> <part name="cdhead" type="tns:cdhead_T"/> </message> <portType name="MIPortType"> <operation name="mi102"> <input message="tns:MI102Req"/> <output message="tns:Res"/> </operation> </portType> <binding name="MIBinding" type="tns:MIPortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="mi102"> <soap:operation soapAction="http://testServerURL/test_soap.php#mi102"/> <input> <soap:body use="literal" namespace="http://pse/"/> </input> <output> <soap:body use="literal" namespace="http://pse/"/> </output> </operation> </binding> <service name="PSE"> <port name="MIPortType" binding="tns:MIBinding"> <soap:address location="http://testServerURL/test_soap.php"/> </port> </service> </definitions>
И полученный XML (опять же, извлеченный из тела SOAP приложением, который я использую), является
Ответ SOAP:
<?xml version="1.0" encoding="UTF-8"?> <ns1:mi102Response xmlns:ns1="http://pse/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">O:8:"stdClass":2:{s:7:"cisprik";i:21;s:7:"version";s:2:"13";}</ns1:mi102Response>
Не хорошо.
В итоге я нашел ответ в других потоках на SO, например get-receiveœ-xml-from-php-soap-server
Решение состоит в том, чтобы использовать следующее:
$inp = file_get_contents ('php://input');
Примечание. Я не мог найти какую-либо функцию, которая может действовать на входном аргументе stdClass
и может извлекать из него содержимое XML SOAP Body.
Поэтому лучшим вариантом является использование стандартной входной переменной php. Обратите внимание, что это имеет следующую структуру: Envelope/Body/..inputXML..
, который является точным содержимым HTTP-запроса, которое отправляется на сервер.
Примечание: http_get_request_body
тоже может работать, но мой php-сервер не поддерживал эту функцию. Я думаю, что file_get_contents
поддерживается на каждом сервере php с некоторой версии и далее.
Это не будет начато как полный ответ, но я хотел форматировать. Пожалуйста, уточните, что вы создали. Как правило, у вас будет PHP-метод с регулярными аргументами (а не с XML), которые вы хотите открыть в качестве веб-службы. Основной пример того, как это сделать, можно найти здесь:
http://www.phpeveryday.com/articles/Web-Services-WSDL-Creating-SOAP-Server-P484.html
XML-контент тела SOAP является аргументом функции, которую я предполагаю
Нет, XML-контент тела SOAP представляет собой представление метода с вашими аргументами, но ваши аргументы – все, что вы хотите. Вам не нужно иметь дело с XML вручную, если вы установите его с помощью SoapServer и SoapClient от PHP.
EDIT: вы принимаете свой аргумент, который представляет собой простое представление массива PHP вашего тела запроса SOAP, сериализуя его и отправляя обратно в ответ (это то, что вы наблюдаете). Это то, что вы хотите сделать? Разве вы не хотите что-то делать с данными запроса? Кроме того, можете ли вы опубликовать схему, импортированную из WSDL?
У вас есть это «нехорошее» представление объекта, потому что вы возвращаете объект, сериализованный (Сериализация преобразует объект и его состояние в строковое представление). Если вы хотите иметь xml-представление возвращаемого объекта, вы должны изменить тип возвращаемого параметра функции на объект. Потому что теперь возвращает строку.
Я бы рекомендовал вам использовать компоненты Zend_Soap_Server и Zend_Soap_Autodiscover структуры zend.
С помощью Zend_Soap_Autodiscover вы можете генерировать определение веб-службы (wsdl) динамически, просто написав докблоки своих функций. И Zend_Soap_Server тоже довольно круто.
Если вы используете эти компоненты и документируете свои типы и свою функцию для возврата определенного типа без его сериализации, вы получите представление xml в соответствии с определением wsdl. Также каждый создаваемый вами тип автоматически преобразуется Zend_Soap_Autodiscover в ComplexType в сгенерированном wsdl.
Образец:
public class Person{ public $id; public $name; } public class MyService { /** * * @param integer $UserID * @return Person */ function mi102($UserID) { $output = new Person(); $output->id = 2; $output->name = 'Peter'; return $output; } } // Generate WSDL relevant to code if (isset($_GET['wsdl'])){ $autodiscover = new Zend_Soap_AutoDiscover(); $autodiscover->setClass('MyService'); $autodiscover->handle(); } else { $server = new Zend_Soap_Server($serviceURL . "?wsdl"); $server->setClass('MyService'); $server->setObject(new MyService()); $server->handle(); }