I'm trying to call a SOAP method using PHP.
Here's the code I've got:
$data = array('Acquirer' => array( 'Id' => 'MyId', 'UserId' => 'MyUserId', 'Password' => 'MyPassword' )); $method = 'Echo'; $client = new SoapClient(NULL, array('location' => 'https://example.com/ExampleWebServiceDL/services/ExampleHandler', 'uri' => 'http://example.com/wsdl', 'trace' => 1)); $result = $client->$method($data);
Here's the request it creates:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://example.com/wsdl" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <ns1:Echo> <param0 xsi:type="ns2:Map"> <item> <key xsi:type="xsd:string">Acquirer</key> <value xsi:type="ns2:Map"> <item> <key xsi:type="xsd:string">Id</key> <value xsi:type="xsd:string">mcp</value> </item> <item> <key xsi:type="xsd:string">UserId</key> <value xsi:type="xsd:string">tst001</value> </item> <item> <key xsi:type="xsd:string">Password</key> <value xsi:type="xsd:string">test</value> </item> </value> </item> </param0> </ns1:Echo> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
And here's what I want the request to look like:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://example.com/wsdl" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <Echo> <Acquirer> <Id>MyId</Id> <UserId>MyUserId</UserId> <Password>MyPassword</Password> </Acquirer> </Echo> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
To make SOAP requests to the SOAP API endpoint, use the "Content-Type: application/soap+xml" request header, which tells the server that the request body contains a SOAP envelope. The server informs the client that it has returned a SOAP envelope with a "Content-Type: application/soap+xml" response header.
A Quick Overview of SOAPSOAP relies exclusively on XML to provide messaging services. Microsoft originally developed SOAP to take the place of older technologies that don't work well on the internet such as the Distributed Component Object Model (DCOM) and Common Object Request Broker Architecture (CORBA).
SOAP uses XML to package the data passed to a method, or received as a response. SOAP itself is nothing more than a set of rules that define how to describe method calls and return values using XML syntax. XML merely describes data, without consideration for the way that the data is processed or presented.
There are a couple of ways to solve this. The least hackiest and almost what you want:
$client = new SoapClient( null, array( 'location' => 'https://example.com/ExampleWebServiceDL/services/ExampleHandler', 'uri' => 'http://example.com/wsdl', 'trace' => 1, 'use' => SOAP_LITERAL, ) ); $params = new \SoapVar("<Acquirer><Id>MyId</Id><UserId>MyUserId</UserId><Password>MyPassword</Password></Acquirer>", XSD_ANYXML); $result = $client->Echo($params);
This gets you the following XML:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://example.com/wsdl"> <SOAP-ENV:Body> <ns1:Echo> <Acquirer> <Id>MyId</Id> <UserId>MyUserId</UserId> <Password>MyPassword</Password> </Acquirer> </ns1:Echo> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
That is almost exactly what you want, except for the namespace on the method name. I don't know if this is a problem. If so, you can hack it even further. You could put the <Echo>
tag in the XML string by hand and have the SoapClient not set the method by adding 'style' => SOAP_DOCUMENT,
to the options array like this:
$client = new SoapClient( null, array( 'location' => 'https://example.com/ExampleWebServiceDL/services/ExampleHandler', 'uri' => 'http://example.com/wsdl', 'trace' => 1, 'use' => SOAP_LITERAL, 'style' => SOAP_DOCUMENT, ) ); $params = new \SoapVar("<Echo><Acquirer><Id>MyId</Id><UserId>MyUserId</UserId><Password>MyPassword</Password></Acquirer></Echo>", XSD_ANYXML); $result = $client->MethodNameIsIgnored($params);
This results in the following request XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <Echo> <Acquirer> <Id>MyId</Id> <UserId>MyUserId</UserId> <Password>MyPassword</Password> </Acquirer> </Echo> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Finally, if you want to play around with SoapVar and SoapParam objects, you can find a good reference in this comment in the PHP manual: http://www.php.net/manual/en/soapvar.soapvar.php#104065. If you get that to work, please let me know, I failed miserably.
First off, you have to specify you wish to use Document Literal style:
$client = new SoapClient(NULL, array( 'location' => 'https://example.com/path/to/service', 'uri' => 'http://example.com/wsdl', 'trace' => 1, 'use' => SOAP_LITERAL) );
Then, you need to transform your data into a SoapVar; I've written a simple transform function:
function soapify(array $data) { foreach ($data as &$value) { if (is_array($value)) { $value = soapify($value); } } return new SoapVar($data, SOAP_ENC_OBJECT); }
Then, you apply this transform function onto your data:
$data = soapify(array( 'Acquirer' => array( 'Id' => 'MyId', 'UserId' => 'MyUserId', 'Password' => 'MyPassword', ), ));
Finally, you call the service passing the Data parameter:
$method = 'Echo'; $result = $client->$method(new SoapParam($data, 'Data'));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With