Parsing XML request - php

I'm very very new to being on the Server side of things. I need to set up a simple server.php to receive xml requests.
I'm not even sure how to start with this. I am used to the normal Post/Get variables from forms.
Here's an example of what I'm listening for, and needing to respond to:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<authenticate xmlns="http://someplace.someplace.com/">
<strUserName xsi:type="xsd:string">username</strUserName>
<strPassword xsi:type="xsd:string">password</strPassword>
</authenticate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Obviously there's a username/password I can see inside.
Validating the user/pass is the easy part, but how do I parse that out?

You can also use DOM element to access your desired values:
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<authenticate xmlns="http://someplace.someplace.com/">
<strUserName xsi:type="xsd:string">username</strUserName>
<strPassword xsi:type="xsd:string">password</strPassword>
</authenticate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
$dom = new DOMDocument();
$dom->loadXML( $xml );
$username = $dom->getElementsByTagName('strUserName')->item(0)->nodeValue;
$password = $dom->getElementsByTagName('strPassword')->item(0)->nodeValue;

Give it a try with SimpleXML, you have a few examples here:
SimpleXML examples

You should probably use existing API when parsing a SOAP request. This will not only automatically get rid of your parsing problems but also generate correct SOAP output.
Example:
$request = '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<authenticate xmlns="http://someplace.someplace.com/">
<strUserName xsi:type="xsd:string">foo</strUserName>
<strPassword xsi:type="xsd:string">bar</strPassword>
</authenticate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
$s = new SoapServer(NULL, array('uri' => 'http://someplace.someplace.com/'));
$s->setClass("Auth");
$s->handle($request);
class Auth
{
public function authenticate($strUserName, $strPassword)
{
return "U: $strUserName; P: $strPassword";
}
}
Note: If you do not pass an argument to handle() it will use POST data.

Related

Parsing JSON inside XML response php

<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:getRatesResponse xmlns:ns1="urn:rpxwsdl">
<return xsi:type="xsd:string">{"RPX":{"TITLE":"Rates From Jakarta (JAK) TO Denpasar (DPS), Weight 1 Kg","DATA":[{"SERVICE":"PAS Reguler (PSR)","FREIGHT_CHARGE":"27723","TOT_CHARGE":"27723","PRICE":"27723","DISCOUNT":"0","ETF":"N\/A","ETD":"N\/A"},{"SERVICE":"","FREIGHT_CHARGE":"0","TOT_CHARGE":"0","PRICE":"0","DISCOUNT":"0","ETF":"0","ETD":"0"}]}}</return>
</ns1:getRatesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I have a json inside an xml response. however how do i retrieve it from the response.
Use the DOM classes to get the relevant text content. This will handle the entities. Then you can simply use json_decode.
For example (demo):
<?php
declare(strict_types=1);
$xml = <<<XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:getRatesResponse xmlns:ns1="urn:rpxwsdl">
<return xsi:type="xsd:string">{"RPX":{"TITLE":"Rates From Jakarta (JAK) TO Denpasar (DPS), Weight 1 Kg","DATA":[{"SERVICE":"PAS Reguler (PSR)","FREIGHT_CHARGE":"27723","TOT_CHARGE":"27723","PRICE":"27723","DISCOUNT":"0","ETF":"N\/A","ETD":"N\/A"},{"SERVICE":"","FREIGHT_CHARGE":"0","TOT_CHARGE":"0","PRICE":"0","DISCOUNT":"0","ETF":"0","ETD":"0"}]}}</return>
</ns1:getRatesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML;
$doc = new DOMDocument('1.0', 'ISO-8859-1');
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('ns1', 'urn:rpxwsdl');
$item = $xpath->query('/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getRatesResponse/return');
if ($item->length > 0) {
print_r(
json_decode($item->item(0)->textContent, true, 512, JSON_THROW_ON_ERROR)
);
}

How filter through XML response from CURL HTTP POST Request

Response from CURL request:
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:header>
<soap-env:body>
<ipgapi:ipgapiorderresponse xmlns:ipgapi="http://ipg-online.com/ipgapi/schemas/ipgapi" xmlns:a1="http://ipg-online.com/ipgapi/schemas/a1" xmlns:v1="http://ipg-online.com/ipgapi/schemas/v1">
<ipgapi:approvalcode>Y:761862:4515799310:PPXP:0037</ipgapi:approvalcode>
<ipgapi:avsresponse>PPX</ipgapi:avsresponse>
<ipgapi:brand>VISA</ipgapi:brand>
<ipgapi:country>GBR</ipgapi:country>
<ipgapi:commercialserviceprovider>BOSMS</ipgapi:commercialserviceprovider>
<ipgapi:orderid>A-966025d3-81a2-453a-820e-bb145e8390d1</ipgapi:orderid>
<ipgapi:ipgtransactionid>84515799310</ipgapi:ipgtransactionid>
<ipgapi:paymenttype>CREDITCARD</ipgapi:paymenttype>
<ipgapi:processorapprovalcode>761862</ipgapi:processorapprovalcode>
<ipgapi:processorccvresponse>P</ipgapi:processorccvresponse>
<ipgapi:processorreferencenumber>761862</ipgapi:processorreferencenumber>
<ipgapi:processorresponsecode>00</ipgapi:processorresponsecode>
<ipgapi:processorresponsemessage>AUTH CODE:761862</ipgapi:processorresponsemessage>
<ipgapi:tdate>1521047872</ipgapi:tdate>
<ipgapi:tdateformatted>2018.03.14 18:17:52 (CET)</ipgapi:tdateformatted>
<ipgapi:terminalid>21400371</ipgapi:terminalid>
<ipgapi:transactionresult>APPROVED</ipgapi:transactionresult>
<ipgapi:transactiontime>1521047872</ipgapi:transactiontime>
</ipgapi:ipgapiorderresponse>
</soap-env:body>
</soap-env:header>
</soap-env:envelope>
I've tried the following:
$responseXML = '<?xml version="1.0" encoding="UTF-8"?>
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:header>
<soap-env:body>
<ipgapi:ipgapiorderresponse xmlns:ipgapi="http://ipg-online.com/ipgapi/schemas/ipgapi" xmlns:a1="http://ipg-online.com/ipgapi/schemas/a1" xmlns:v1="http://ipg-online.com/ipgapi/schemas/v1">
<ipgapi:approvalcode>Y:761862:4515799310:PPXP:0037</ipgapi:approvalcode>
<ipgapi:avsresponse>PPX</ipgapi:avsresponse>
<ipgapi:brand>VISA</ipgapi:brand>
<ipgapi:country>GBR</ipgapi:country>
<ipgapi:commercialserviceprovider>BOSMS</ipgapi:commercialserviceprovider>
<ipgapi:orderid>A-966025d3-81a2-453a-820e-bb145e8390d1</ipgapi:orderid>
<ipgapi:ipgtransactionid>84515799310</ipgapi:ipgtransactionid>
<ipgapi:paymenttype>CREDITCARD</ipgapi:paymenttype>
<ipgapi:processorapprovalcode>761862</ipgapi:processorapprovalcode>
<ipgapi:processorccvresponse>P</ipgapi:processorccvresponse>
<ipgapi:processorreferencenumber>761862</ipgapi:processorreferencenumber>
<ipgapi:processorresponsecode>00</ipgapi:processorresponsecode>
<ipgapi:processorresponsemessage>AUTH CODE:761862</ipgapi:processorresponsemessage>
<ipgapi:tdate>1521047872</ipgapi:tdate>
<ipgapi:tdateformatted>2018.03.14 18:17:52 (CET)</ipgapi:tdateformatted>
<ipgapi:terminalid>21400371</ipgapi:terminalid>
<ipgapi:transactionresult>APPROVED</ipgapi:transactionresult>
<ipgapi:transactiontime>1521047872</ipgapi:transactiontime>
</ipgapi:ipgapiorderresponse>
</soap-env:body>
</soap-env:header>
</soap-env:envelope>';
$xml = simplexml_load_string($responseXML);
print_r($xml);
// Returns empty object
I've also tried the following:
$xml = new SimpleXMLElement($responseXML);
print_r($xml);
// This also returns empty object
Could someone help me figure out what's going wrong with this?
Using print_r(); with a SimpleXMLElement usually doesn't give anything useful. Instead you should use asXML() which outputs the original XML.
$xml = simplexml_load_string($responseXML);
echo $xml->asXML();
Which gives
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:header>
<soap-env:body>
...
You can access the data by using something like...
$xml = simplexml_load_string($responseXML);
$body = $xml->xpath("//soap-env:body");
$bodyData = $body[0]->children("ipgapi", true);
echo $bodyData->ipgapiorderresponse->approvalcode;
So $bodyData is the <ipgapi:ipgapiorderresponse ...> element and so accessing each part of that is by using the last line. You can use the element name (minus the namespace prefix ipgapi as this is taken care of with the children() call earlier). That line outputs
Y:761862:4515799310:PPXP:0037

Remove automatically applied namespace in php's SimpleXML

I am trying to create a SOAP request for a paypal express checkout with SimpleXML. However, I am experiencing a behaviour I don't yet understand.
The envelope and its header are generated this way:
$envelope = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:ebay:apis:eBLBaseComponents"
xmlns:ns2="urn:ebay:api:PayPalAPI"
/>
');
$header = $envelope->addChild('SOAP-ENV:Header');
$requesterCredentials = $header->addChild('ns2:RequesterCredentials');
$credentials = $requesterCredentials->addChild('ns1:Credentials');
$credentials->addChild('ns1:Username', 'foo');
$credentials->addChild('ns1:Password', 'bar');
Which yields the following output:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:ebay:apis:eBLBaseComponents"
xmlns:ns2="urn:ebay:api:PayPalAPI">
<SOAP-ENV:Header>
<SOAP-ENV:RequesterCredentials>
<SOAP-ENV:Credentials>
<SOAP-ENV:Username>foo</SOAP-ENV:Username>
<SOAP-ENV:Password>bar</SOAP-ENV:Password>
</SOAP-ENV:Credentials>
</SOAP-ENV:RequesterCredentials>
</SOAP-ENV:Header>
</SOAP-ENV:Envelope>
Every node is now prefixed with SOAP-ENV, which is not what I want. Only the root node and header should be prefixed with SOAP-ENV, the other tags should get the defined namespace prepended in addChild().
The desired output should be:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:ebay:apis:eBLBaseComponents"
xmlns:ns2="urn:ebay:api:PayPalAPI">
<SOAP-ENV:Header>
<ns2:RequesterCredentials>
<ns1:Credentials>
<ns1:Username>foo</ns1:Username>
<ns1:Password>bar</ns1:Password>
</ns1:Credentials>
</ns2:RequesterCredentials>
</SOAP-ENV:Header>
</SOAP-ENV:Envelope>
What am I doing wrong here?
addChild takes the namespace as the third parameter:
$requesterCredentials = $header->addChild('RequesterCredentials', null, 'urn:ebay:api:PayPalAPI');
$credentials = $requesterCredentials->addChild('Credentials', null, 'urn:ebay:apis:eBLBaseComponents');
$credentials->addChild('Username', 'foo', 'urn:ebay:apis:eBLBaseComponents');
$credentials->addChild('Password', 'bar', 'urn:ebay:apis:eBLBaseComponents');

Strip SOAP Envelope for Saving Response to XML File

I have a SOAP response that I want to save to an XML file. When the response is written to the file, the SOAP envelope is written with it, making the XML file useless due to the error:
XML declaration allowed only at the start of the document in ...
In this case, XML is being declared twice:
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body><ns1:NDFDgenResponse xmlns:ns1="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
<dwmlOut xsi:type="xsd:string">
<?xml version="1.0"?>
...
Is there a good way to strip out this SOAP envelope and just save what's between it?
Here's how I'm writing the response to the file:
$toWrite = htmlspecialchars_decode($client->__getLastResponse());
$fp = fopen('weather.xml', 'w');
fwrite($fp, $toWrite);
fclose($fp);
The problem is the htmlspecialchars_decode(). The envelope document contains other XML documents as text nodes. If you decode the entities in the XML document you will destroy it. Never use htmlspecialchars_decode() on an XML document.
Load the (envelope) XML into a DOM and read the needed value from it.
$xml = <<<'XML'
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:NDFDgenResponse
xmlns:ns1="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
<dwmlOut xsi:type="xsd:string">
<?xml version="1.0"?>
<weather>XML</weather>
</dwmlOut>
</ns1:NDFDgenResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML;
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
$xpath->registerNamespace('ndfd', 'http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl');
$innerXml = $xpath->evaluate(
'string(/soap:Envelope/soap:Body/ndfd:NDFDgenResponse/dwmlOut)'
);
echo $innerXml;
Output:
<?xml version="1.0"?>
<weather>XML</weather>

php SoapClient - make a call with multiple root tags in request

Here's the xml structure that I want to achieve:
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:method>
<auth>
...
</auth>
<data>
...
</data>
</ns1:method>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</XML>
My code:
<?php
$client = new SoapClient(null, array('location' => "http://www.test.com/soap.php",
'uri' => "http://tempuri.org/",
'trace' => true,'exceptions' => true,'cache_wsdl' => WSDL_CACHE_NONE));
$request = new stdClass();
$request->auth = new stdClass();
$request->data = new stdClass();
$client->__soapCall("method", array($request));
Please note: SoapClient doesn't allow me to insert anything other than array in second param to the __soapCall method.
So here's what I'm getting:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:method>
<param0 xsi:type="SOAP-ENC:Struct">
<auth xsi:type="SOAP-ENC:Struct"/>
<data xsi:type="SOAP-ENC:Struct"/>
</param0>
</ns1:method>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
As you can see, php added a root tag for my request - param0. Is there a way I can escape this? I need to have 2 "root" elements in that request parameter. How can I achieve that?
did you try this way : $client->__soapCall("method", $request);?
Thanks all for answering. I solved the issue with the help of SoapParam:
$client->__soapCall("method", array(
new SoapParam($request->auth, "auth"),
new SoapParam($request->data, "data"),
));

Categories