Parsing SOAP response with SimpleXML - php

I am trying to call a soap server method. Everything works fine except one thing. I get a respone from the server in XML format. So far so good. But the problem is that i need to get the values of the XML and normally i do that just with a foreach and get the values i need. But this time the name of the child i need to get data from is called: 'return'. So i can not reference to that in a foreach function.
Could someone tell me how i can reach the same result but with a different way?
My answer from the server:
<soap:envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:body>
<ns2:getauthresponse xmlns:ns2="http://dpd.com/common/service/types/LoginService/2.0" xmlns:ns3="http://dpd.com/common/service/exceptions">
<return>
<delisid>thedelisid</delisid>
<customeruid>thecustomerid</customeruid>
<authtoken>theauthenticationcode</authtoken>
<depot>thedepot</depot>
</return>
</ns2:getauthresponse>
</soap:body>
</soap:envelope>
the code i would normally use to get the result:
foreach($xml->return->authtoken as $authtoken)
{
print_r($authtoken);
}
The problem is the return sign here, php keeps seeing it as the return statement.
I also made it an array using new SimpleXMLElement.
And the error i get when i run the code is:
Invalid argument supplied for foreach()
How can i get the value of authtoken?
All the code:
$xml_getAuth = '
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="http://dpd.com/common/service/types/LoginService/2.0">
<soapenv:Header/>
<soapenv:Body>
<ns:getAuth>
<delisId>'.$delisId.'</delisId>
<password>'.$password.'</password>
<messageLanguage>'.$messageLanguage.'</messageLanguage>
</ns:getAuth>
</soapenv:Body>
<soapenv:Envelope>
';
$headers_getAuth = array(
"POST HTTP/1.1",
"Content-type: application/soap+xml; charset=\"utf-8\"",
"SOAPAction: \"http://dpd.com/common/service/LoginService/2.0/getAuth\"",
"Content-length: ".strlen($xml_getAuth)
);
$getAuth = curl_init('https://public-ws-stage.dpd.com/services/LoginService/V2_0/');
curl_setopt($getAuth, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($getAuth, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($getAuth, CURLOPT_POST, 1);
curl_setopt($getAuth, CURLOPT_HTTPHEADER, $headers_getAuth);
curl_setopt($getAuth, CURLOPT_POSTFIELDS, "$xml_getAuth");
curl_setopt($getAuth, CURLOPT_RETURNTRANSFER, 1);
$output_getAuth = curl_exec($getAuth);
//Gebruikernsaam en wachtwoord komen niet overeen
if(strpos($output_getAuth,'LOGIN_8') !== false)
{
echo "Verkeerde gebruikernsaam of wachtwoord, neem contact op met uw systeembeheerder voor meer informatie.";
exit;
}
$xml = new SimpleXMLElement($output_getAuth);
foreach($xml->return->authtoken as $authtoken)
{
print_r($authtoken);
}
Answer from the soap call:
stdClass Object ( [return] => stdClass Object ( [delisId] => delisid [customerUid] => custid [authToken] => authtoken [depot] => depot ) )

First of all, you should probably be using SoapClient instead of SimpleXML. For example:
$c = new SoapClient('https://public-ws-stage.dpd.com/services/LoginService/V2_0/?WSDL');
$res = $c->getAuth(array(
'delisId' => 'foo',
'password' => 'bar',
'messageLanguage' => 'en-us',
));
echo $res->result->authToken;
That said, using xpath solves many problems:
<?php
$response = <<<XML
<soap:envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:body>
<ns2:getauthresponse xmlns:ns2="http://dpd.com/common/service/types/LoginService/2.0" xmlns:ns3="http://dpd.com/common/service/exceptions">
<return>
<delisid>thedelisid</delisid>
<customeruid>thecustomerid</customeruid>
<authtoken>theauthenticationcode</authtoken>
<depot>thedepot</depot>
</return>
</ns2:getauthresponse>
</soap:body>
</soap:envelope>
XML;
$xml = simplexml_load_string($response);
foreach ($xml->xpath('//return') as $tmp) {
echo "authtoken = ", $tmp->authtoken, PHP_EOL;
}

Related

Parse curl response from SOAP

I successfully get response from soap webservice using php curl. I would like to know how can I parse the curl response so that I got each value separately in other to save into database.
my codes:
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "http://xxxxxx/WSAutorizaciones/WSAutorizacionLaboratorio.asmx?WSDL",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthenticationHeader xmlns="https://arssenasa.gob.do/">
<Cedula>001-0946651-5</Cedula>
<Password>xxxxxxx</Password>
<Proveedo>12077</Proveedo>
</AuthenticationHeader>
</soap:Header>
<soap:Body>
<ConsultarAfiliado xmlns="https://arssenasa.gob.do/">
<TipoDocumento>2</TipoDocumento>
<NumDocumento>021827151</NumDocumento>
</ConsultarAfiliado>
</soap:Body>
</soap:Envelope>',
CURLOPT_HTTPHEADER => array("content-type: text/xml"),
))
;
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
The result is displayed like this:
8013-0000655-6021827151MARGARET ADIRASANTANA LORENZO DE CABRAL08CONTRIBUTIVO22/11/197346FEMENINO08
the soap resonse is like this:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ConsultarAfiliadoResponse xmlns="https://arssenasa.gob.do/">
<ConsultarAfiliadoResult>
<Contrato>8</Contrato>
<Cedula>013-0000655-6</Cedula>
<Nss>021827151</Nss>
<Nombres>MARGARET ADIRA</Nombres>
<Apellidos>SANTANA LORENZO DE CABRAL</Apellidos>
<IdEstado>0</IdEstado>
<CodigoFamiliar>8</CodigoFamiliar>
<IdRegimen xsi:nil="true" />
<Regimen>CONTRIBUTIVO</Regimen>
<FechaNacimiento>22/11/1973</FechaNacimiento>
<Edad>46</Edad>
<Sexo>FEMENINO</Sexo>
<TipoDocumento>0</TipoDocumento>
<CodigoAfiliado>8</CodigoAfiliado>
<MensajeAfiliado />
</ConsultarAfiliadoResult>
</ConsultarAfiliadoResponse>
</soap:Body>
</soap:Envelope>
Here is a possible example of how you could go about getting the XML elements from your SOAP response (below) using SimpleXML which might be included in your PHP installation. Because I'm not sure what order of element data you need for the final output, you might need to rearrange the order of items in the output part below.
Also, in order for this to work, the $soapResponse variable in the code example needs to have no extra space before the start of the <?xml version="1.0" encoding="utf-8"?> line.
If you need to access other elements from the XML data, you should be able to do it with this pattern: $result->ConsultarAfiliadoResult->ElementNameHere.
<?php
$soapResponse = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ConsultarAfiliadoResponse xmlns="https://arssenasa.gob.do/">
<ConsultarAfiliadoResult>
<Contrato>8</Contrato>
<Cedula>013-0000655-6</Cedula>
<Nss>021827151</Nss>
<Nombres>MARGARET ADIRA</Nombres>
<Apellidos>SANTANA LORENZO DE CABRAL</Apellidos>
<IdEstado>0</IdEstado>
<CodigoFamiliar>8</CodigoFamiliar>
<IdRegimen xsi:nil="true" />
<Regimen>CONTRIBUTIVO</Regimen>
<FechaNacimiento>22/11/1973</FechaNacimiento>
<Edad>46</Edad>
<Sexo>FEMENINO</Sexo>
<TipoDocumento>0</TipoDocumento>
<CodigoAfiliado>8</CodigoAfiliado>
<MensajeAfiliado />
</ConsultarAfiliadoResult>
</ConsultarAfiliadoResponse>
</soap:Body>
</soap:Envelope>
XML;
// Remove <soap></soap> related tag information to get plain XML content
$xmlContent = preg_replace('/<soap:.*?>\n/', '', $soapResponse);
$xmlContent = preg_replace('/<\/soap:.*?>\n?/', '', $xmlContent);
// Note: there is an error with the xsi:nil="true" part, but that can be
// suppressed with the following line. If you need to deal with this error,
// more info here: https://www.php.net/manual/en/simplexml.examples-errors.php
libxml_use_internal_errors(true);
$result = new SimpleXMLElement($xmlContent);
// Print out results
printf(
"%s%s%s%s%s%s%s%s%s%s%s%s",
$result->ConsultarAfiliadoResult->Cedula,
$result->ConsultarAfiliadoResult->Nss,
$result->ConsultarAfiliadoResult->Nombres,
$result->ConsultarAfiliadoResult->Apellidos,
$result->ConsultarAfiliadoResult->IdEstado,
$result->ConsultarAfiliadoResult->CodigoFamiliar,
$result->ConsultarAfiliadoResult->Regimen,
$result->ConsultarAfiliadoResult->FechaNacimiento,
$result->ConsultarAfiliadoResult->Edad,
$result->ConsultarAfiliadoResult->Sexo,
$result->ConsultarAfiliadoResult->TipoDocumento,
$result->ConsultarAfiliadoResult->CodigoAfiliado
);
?>
Output:
$ php q22.php
013-0000655-6021827151MARGARET ADIRASANTANA LORENZO DE CABRAL08CONTRIBUTIVO22/11/197346FEMENINO08
After almost a journey of research I finally get the correct way to do it :
//The follow-up of my posting codes
.
.
.
$response = curl_exec($curl);
$response = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response);
$xml = new SimpleXMLElement($response);
$body = $xml->xpath('//soapBody ')[0];
$array = json_decode(json_encode((array)$body), TRUE);
// in the case I want to grab only one data
//echo $array['ConsultarAfiliadoResponse']['ConsultarAfiliadoResult']['Cedula'];
// to display all data in the array
function dispaly_array_recursive($array_rec){
if($array_rec){
foreach($array_rec as $value){
if(is_array($value)){
dispaly_array_recursive($value);
}else{
echo $value.'<br>';
}
}
}
}
dispaly_array_recursive($array);
No more problem to save into database now

remove soap headers from response before turning into simplexml object

I'm using Curl to execute a soap request.
Now it looks like there is a mistake returned in the headers that prevents me from turning the returned string into a simplexml object with the function simplexml_load_string. Below you can find the part of the response that fails in the simplexml function:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Header><SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/><ds:Reference URI="#Body"><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue></ds:Reference><ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue></ds:SignedInfo></ds:Signature></SOAP-SEC:Signature></SOAP-ENV:Header><SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body">
Is there a way to isolate the soap body content and parsing only that part with the simplexml_load_string?
Below the curl request:
$headers = array(
"Content-type: text/xml;charset=\"utf-8\"",
"Accept: text/xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"Content-length: ".strlen($xml_post_string),
);
$url = $soapUrl;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$response = curl_exec($ch);
curl_close($ch);
$xml = simplexml_load_string(html_entity_decode($response), 'SimpleXMLElement', LIBXML_NOCDATA);
echo $xml->asXML();
if ($xml === false) {
echo "Failed to load XML: ";
foreach(libxml_get_errors() as $error) {
echo "<br>", $error->message;
}
} else {
var_dump($xml);
}
I don't have an answer for you right now, but you first need to separate curl from XML processing. You should start with logging your result from curl and making sure it is sane and what you expect. If it is, then move on to parsing it. curl should never break/change your data in any way, but the request itself (headers, etc.) might change the server's response.
Since I can't validate your server, I'm just going to go off of what you've provided. I've closed the <SOAP-ENV:Body> tag and converted the XML to readable, but otherwise it is untouched. This code parses the XML without a problem and then emits it exactly as expected.
$response = <<<'TAG'
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Header>
<SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1" />
<ds:Reference URI="#Body">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue>
</ds:Reference>
<ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue>
</ds:SignedInfo>
</ds:Signature>
</SOAP-SEC:Signature>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body"></SOAP-ENV:Body>
</SOAP-ENV:Envelope>
TAG;
$xml = simplexml_load_string(html_entity_decode($response), 'SimpleXMLElement', LIBXML_NOCDATA);
echo '<pre>';
print_r(htmlspecialchars($xml->asXML()));
echo '</pre>';
The output is exactly the same as the input except it includes the XML directive and converts the body tag to self-closing:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Header>
<SOAP-SEC:Signature xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
<ds:Reference URI="#Body">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>HV+/cOkUjNCdH5xuiLlGSHVgkUo=</ds:DigestValue>
</ds:Reference>
<ds:SignatureValue>MCwCFHXmoMrDUOScwMQ5g76OfxouICjBAhQtGKAorJLUQ0bA0UaKIe1gtmQPgA==</ds:SignatureValue>
</ds:SignedInfo>
</ds:Signature>
</SOAP-SEC:Signature>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body"/>
</SOAP-ENV:Envelope>
So use this as a baseline. Write your curl response to a text file before doing anything else, and then read that text file back in and perform logic. Any transformation you apply to the string XML should also be logged and compared to make sure it is doing what you expected. On production you'd skip that but this just helps during the debugging.
Also, I'm not really sure what the point of html_entity_decode is in this. If you are receiving XML (as your request mime type specifies) then it shouldn't have any escape sequences applied to it, but maybe you have an exceptional case, too.
Just to give some example XML content, this will vary for any file but just shows how you can access the data...
<SOAP-ENV:Body
xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"
SOAP-SEC:id="Body">
<BodyContent>SomeData</BodyContent>
<OtherContent>2</OtherContent>
</SOAP-ENV:Body>
Then it would be a case of using XPath to find the <SOAP-ENV:Body> tag
$xml->registerXPathNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
$bodyBlock = $xml->xpath("//SOAP-ENV:Body")[0];
(note that as xpath() returns a list of matches, using [0] just uses the first one).
This next part depends on the message being processed, but as the example I gave has child elements with no namespace prefix, then you can extract these using ->children() and this eases access to the contents. The main part is that at this point the $bodyBlock contains this...
<SOAP-ENV:Body xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12" SOAP-SEC:id="Body">
<BodyContent>SomeData</BodyContent>
<OtherContent>2</OtherContent>
</SOAP-ENV:Body>
So to put that together in your original code...
$xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($xml === false) {
echo "Failed to load XML: ";
foreach(libxml_get_errors() as $error) {
echo "<br>", $error->message;
}
} else {
// Search for the Body element (this is in the SOAP-ENV namespace)
$xml->registerXPathNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
$bodyBlock = $xml->xpath("//SOAP-ENV:Body")[0];
// If the content does not have a namespace, extract the children from the default namespace
$body = $bodyBlock->children();
// You can now access the content.
echo $body->BodyContent.PHP_EOL;
echo $body->OtherContent;
}
which outputs the two values in the body....
SomeData
2

Get body content from xml in php curl request

I am using below code for SOAP request.
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://example.com?WSDL",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://Xyz.Abc\" xmlns:ns2=\"http://tempuri.org/\"><SOAP-ENV:Body><ns2:GetStatus><ns1:ReferenceNo>12345</ns1:ReferenceNo></ns2:GetStatus></SOAP-ENV:Body></SOAP-ENV:Envelope>",
CURLOPT_HTTPHEADER => array(
"Content-Type: text/xml"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
Response:
Getting below response when I set header('Content-type: application/xml'); in php script which is correct.
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Header>...</env:Header>
<env:Body>
<GetStatusResponse xmlns:s1="http://Xyz.Abc" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://tempuri.org/" xmlns="http://tempuri.org/">
<s1:StatusResponse>
<s1:Test ResponseCode="INPROGRESS" ResponseMessage="Reference no. 12345"/>
</s1:StatusResponse>
</GetStatusResponse>
</env:Body>
</env:Envelope>
How can I extract Body values from the response without just printing on browser?
Here is what I tried
Remove xml header and parse response string by simplexml_load_string method.
$xml = simplexml_load_string($response);
echo $xml;
$json = json_encode($response);
$arr = json_decode($json,true);
print_r($arr);
I also tried with SimpleXMLElement, but, it's printing empty response:
$test = new SimpleXMLElement($response);
echo $test;
But, it's printing empty result.
SimpleXML is an object. It isn't the full XML string as you might think. Try this.
//Cast to string to force simpleXml to convert into a string
$xmlString = $xml->asXML();
echo $xmlString . "\n";
I'm pretty sure you can't do this because $response is XML. Trying to json_encode it doesn't make sense.
$json = json_encode($response);
I did this:
<?php
$x = '<?xml version="1.0" ?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Header>...</env:Header>
<env:Body>
<GetStatusResponse xmlns:s1="http://Xyz.Abc" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://tempuri.org/" xmlns="http://tempuri.org/">
<s1:StatusResponse>
<s1:Test ResponseCode="INPROGRESS" ResponseMessage="Reference no. 12345"/>
</s1:StatusResponse>
</GetStatusResponse>
</env:Body>
</env:Envelope>';
$xml = simplexml_load_string($x);
echo $xml->asXml();
echo "\n";
And I get this output:
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Header>...</env:Header>
<env:Body>
<GetStatusResponse xmlns:s1="http://Xyz.Abc" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://tempuri.org/" xmlns="http://tempuri.org/">
<s1:StatusResponse>
<s1:Test ResponseCode="INPROGRESS" ResponseMessage="Reference no. 12345"/>
</s1:StatusResponse>
</GetStatusResponse>
</env:Body>
</env:Envelope>
This explains how to specify namespaces.
https://www.php.net/manual/en/simplexmlelement.attributes.php
$xml->registerXPathNamespace('e', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('s', 'http://Xyz.Abc');
$result = $xml->xpath('//s:Test');
$response = $result[0]->attributes();
echo "Response Code = " . $response['ResponseCode'] . "\n";
echo "Response Message = " . $response['ResponseMessage'] . "\n";

PHP eBay Call Issues

Im trying to get the shipping info of a product, this is my code (I have hidden my app-id).
$endpoint2 = "http://open.api.ebay.com/shopping";
$xmlrequest2 = "<?xml version='1.0' encoding='utf-8'?>\n";
$xmlrequest2 .= "<GetShippingCostsRequest xmlns='urn:ebay:apis:eBLBaseComponents'>\n";
// $xmlrequest2 .= "<DestinationCountryCode>GB</DestinationCountryCode>\n";
// $xmlrequest2 .= "<IncludeDetails>true</IncludeDetails>\n";
$xmlrequest2 .= "<ItemID>".$id."</ItemID>\n";
$xmlrequest2 .= "</GetShippingCostsRequest>\n";
$session2 = curl_init($endpoint2); // create a curl session
curl_setopt($session2, CURLOPT_POST, true);
var_dump($xmlrequest2);
curl_setopt($session2, CURLOPT_POSTFIELDS, $xmlrequest2); // set the body of the POST
curl_setopt($session2, CURLOPT_RETURNTRANSFER, true);
$headers2 = array(
'X-EBAY-API-APP-ID:'.getsetting(2),
'X-EBAY-API-VERSION:849',
'X-EBAY-API-SITE-ID:3',
'X-EBAY-API-CALL-NAME:GetShippingCosts',
'X-EBAY-API-REQUEST-ENCODING:XML',
);
print_r($headers2);
// create a curl session
curl_setopt($session2, CURLOPT_HTTPHEADER, $headers2); //set headers using the above array of headers
$responseXML = curl_exec($session2);
// send the request
//echo $responseXML;
curl_close($session2);
return $responseXML;
And this is the output/errors i get.
string(162) "<?xml version='1.0' encoding='utf-8'?>
<GetShippingCostsRequest xmlns='urn:ebay:apis:eBLBaseComponents'>
<ItemID>300903657321</ItemID>
</GetShippingCostsRequest>
"
Array
(
[0] => X-EBAY-API-APP-ID:1234
[1] => X-EBAY-API-VERSION:849
[2] => X-EBAY-API-SITE-ID:3
[3] => X-EBAY-API-CALL-NAME:GetShippingCosts
[4] => X-EBAY-API-REQUEST-ENCODING:XML
)
<?xml version="1.0" encoding="UTF-8"?>
<GetShippingCostsResponse xmlns="">
<ns1:Ack xmlns:ns1="urn:ebay:apis:eBLBaseComponents">Failure</ns1:Ack>
<ns2:Errors xmlns:ns2="urn:ebay:apis:eBLBaseComponents">
<ns2:ShortMessage>Input data is invalid.</ns2:ShortMessage>
<ns2:LongMessage>Input data for the given tag is invalid or missing. Please check API documentation.</ns2:LongMessage>
<ns2:ErrorCode>1.22</ns2:ErrorCode>
<ns2:SeverityCode>Error</ns2:SeverityCode>
<ns2:ErrorParameters ParamID="0">
<ns2:Value>XML document structures must start and end within the same entity.</ns2:Value>
</ns2:ErrorParameters>
<ns2:ErrorClassification>RequestError</ns2:ErrorClassification>
</ns2:Errors>
<ns3:Build xmlns:ns3="urn:ebay:apis:eBLBaseComponents">E853_CORE_APILW_16579549_R1</ns3:Build>
<ns4:Version xmlns:ns4="urn:ebay:apis:eBLBaseComponents">853</ns4:Version>
</GetShippingCostsResponse>
Any ideas? I can't work out at all what the problem is. Nothing on their documentation seems to help. If i copy and paste the XML into their API Test Tool it works no problems.
I had the same problem with every call of eBay Shopping API. You can fix it adding Content-Type: text/xml;charset=UTF-8 to your headers (this fix the problem for me).
I don't see your credentials listed anywhere. The API tool they give you is a bit deceptive in that it wraps your calls for you with the credentials. http://developer.ebay.com/DevZone/guides/ebayfeatures/Basics/Call-StandardCallData.html#StandardOutputData
<?xml version="1.0" encoding="utf-8"?>
<GeteBayOfficialTimeRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<RequesterCredentials>
<eBayAuthToken> Token goes here </eBayAuthToken>
</RequesterCredentials>
<Version>383</Version>
</GeteBayOfficialTimeRequest>

Send XML with php via post

I know there are any number of similar questions to this on SO, but I've tried messing around with all the solutions and haven't seemed to be able to make it work. I am trying to post xml directly to a web service and get a response back. Technically I am trying to connect to freightquote.com, the documentation for which you can find in the upper right hand corner of this page under documentation. I only mention that because I see the term SOAP a lot in their xml and it might make a difference. Anyway what I want is the ability to send xml to some url and get a response back.
So if I had the following
$xml = "<?xml version='1.0' encoding='utf-8'?>
<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<soap:Body>
<GetRatingEngineQuote xmlns='http://tempuri.org/'>
<request>
<CustomerId>0</CustomerId> <!-- Identifier for customer provided by Freightquote -->
<QuoteType>B2B</QuoteType> <!-- B2B / eBay /Freightview -->
<ServiceType>LTL</ServiceType> <!-- LTL / Truckload / Groupage / Haulage / Al -->
<QuoteShipment>
<IsBlind>false</IsBlind>
<PickupDate>2010-09-13T00:00:00</PickupDate>
<SortAndSegregate>false</SortAndSegregate>
<ShipmentLocations>
<Location>
<LocationType>Origin</LocationType>
<RequiresArrivalNotification>false</RequiresArrivalNotification>
<HasDeliveryAppointment>false</HasDeliveryAppointment>
<IsLimitedAccess>false</IsLimitedAccess>
<HasLoadingDock>false</HasLoadingDock>
<IsConstructionSite>false</IsConstructionSite>
<RequiresInsideDelivery>false</RequiresInsideDelivery>
<IsTradeShow>false</IsTradeShow>
<IsResidential>false</IsResidential>
<RequiresLiftgate>false</RequiresLiftgate>
<LocationAddress>
<PostalCode>30303</PostalCode>
<CountryCode>US</CountryCode>
</LocationAddress>
<AdditionalServices />
</Location>
<Location>
<LocationType>Destination</LocationType>
<RequiresArrivalNotification>false</RequiresArrivalNotification>
<HasDeliveryAppointment>false</HasDeliveryAppointment>
<IsLimitedAccess>false</IsLimitedAccess>
<HasLoadingDock>false</HasLoadingDock>
<IsConstructionSite>false</IsConstructionSite>
<RequiresInsideDelivery>false</RequiresInsideDelivery>
<IsTradeShow>false</IsTradeShow>
<IsResidential>false</IsResidential>
<RequiresLiftgate>false</RequiresLiftgate>
<LocationAddress>
<PostalCode>60606</PostalCode>
<CountryCode>US</CountryCode>
</LocationAddress>
<AdditionalServices />
</Location>
</ShipmentLocations>
<ShipmentProducts>
<Product>
<Class>55</Class>
<Weight>1200</Weight>
<Length>0</Length>
<Width>0</Width>
<Height>0</Height>
<ProductDescription>Books</ProductDescription>
<PackageType>Pallets_48x48</PackageType>
<IsStackable>false</IsStackable>
<DeclaredValue>0</DeclaredValue>
<CommodityType>GeneralMerchandise</CommodityType>
<ContentType>NewCommercialGoods</ContentType>
<IsHazardousMaterial>false</IsHazardousMaterial>
<PieceCount>5</PieceCount>
<ItemNumber>0</ItemNumber>
</Product>
</ShipmentProducts>
<ShipmentContacts />
</QuoteShipment>
</request>
<user>
<Name>someone#something.com</Name>
<Password>password</Password>
</user>
</GetRatingEngineQuote>
</soap:Body>
</soap:Envelope>";
(I edited this to contain my actual xml since it may lend some perspective
I'd want to send it to http://www.someexample.com and get a response. Also, do I need to encode it? I've done a lot of sending xml back and forth with android, and never had to but that might be part of my problem.
My attempt to send the information currently looks like this
$xml_post_string = 'XML='.urlencode($xml->asXML());
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://b2b.Freightquote.com/WebService/QuoteService.asmx');
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close($ch);
If you are walking around SOAP services, I strongly recommend you to learn basics once, and then use this great tool again and again. There are many features you can just use, or you will be reinventing the wheel and struggling with generating xml files, parsing xml files, faults etc. Use prepared tools and your life will be easier and your code better (less bugs).
Look at http://www.php.net/manual/en/soapclient.soapcall.php#example-5266 how to consume SOAP webservice. It is not so hard to understand.
Here is some code how you can analyze webserivce. Then map types to classes and just send and receive php objects. You can look for some tool to generate classes automatically (http://www.urdalen.no/wsdl2php/manual.php).
<?php
try
{
$client = new SoapClient('http://b2b.freightquote.com/WebService/QuoteService.asmx?WSDL');
// read function list
$funcstions = $client->__getFunctions();
var_dump($funcstions);
// read some request obejct
$response = $client->__getTypes();
var_dump($response);
}
catch (SoapFault $e)
{
// do some service level error stuff
}
catch (Exception $e)
{
// do some application level error stuff
}
If you will use wsdl2php generating tool, everything is very easy:
<?php
require_once('./QuoteService.php');
try
{
$client = new QuoteService();
// create request
$tracking = new TrackingRequest();
$tracking->BOLNumber = 67635735;
$request = new GetTrackingInformation();
$request->request = $tracking;
// send request
$response = $client->GetTrackingInformation($request);
var_dump($response);
}
catch (SoapFault $e)
{
// do some service level error stuff
echo 'Soap fault ' . $e->getMessage();
}
catch (Exception $e)
{
// do some application level error stuff
echo 'Error ' . $e->getMessage();
}
Generated php code for QuoteService.php you can see here: http://pastie.org/8165331
This is captured communication:
Request
POST /WebService/QuoteService.asmx HTTP/1.1
Host: b2b.freightquote.com
Connection: Keep-Alive
User-Agent: PHP-SOAP/5.4.17
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://tempuri.org/GetTrackingInformation"
Content-Length: 324
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/">
<SOAP-ENV:Body>
<ns1:GetTrackingInformation>
<ns1:request>
<ns1:BOLNumber>67635735</ns1:BOLNumber>
</ns1:request>
</ns1:GetTrackingInformation>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Response
HTTP/1.1 200 OK
Date: Mon, 22 Jul 2013 21:46:06 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Content-Length: 660
Set-Cookie: BIGipServerb2b_freightquote_com=570501130.20480.0000; path=/
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetTrackingInformationResponse xmlns="http://tempuri.org/">
<GetTrackingInformationResult>
<BOLNumber>0</BOLNumber>
<EstimatedDelivery>0001-01-01T00:00:00</EstimatedDelivery>
<TrackingLogs />
<ValidationErrors>
<B2BError>
<ErrorType>Validation</ErrorType>
<ErrorMessage>Unable to find shipment with BOL 67635735.</ErrorMessage>
</B2BError>
</ValidationErrors>
</GetTrackingInformationResult>
</GetTrackingInformationResponse>
</soap:Body>
</soap:Envelope>
First, if your code is written like this, I doubt this works be cause of the quotes...
You should use double quote around your xml:
$my_xml = "<?xml version='1.0' standalone='yes'?>
<user>
<Name>xmltest#freightquote.com</Name>
<Password>XML</Password>
</user>";
Also, you could use poster, a firefox addon (there is probably the equivalent on chrome), to help you with your requests, especially if you use WebServices. That way, you will be able to see if the error is server-side or client-side.
This should help you debugging.
I use this command-line script to test SOAP call:
#!/usr/bin/php
<?php
//file client-test.php
$xml_data = file_get_contents('php://stdin');
$ch = curl_init('http://example.com/server/');
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('SOAPAction', 'MySoapAction'));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
print_r($output);
Usage like this (in command line) :
$ client-test.php < yourSoapEnveloppe.xml
In this example the yourSoapEnveloppe.xml file is the content of your $xml variable.
You can use stream_context_create and file_get_contents to send xml in post.
$xml = "<your_xml_string>";
$send_context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => 'Content-Type: application/xml',
'content' => $xml
)
));
print file_get_contents($url, false, $send_context);

Categories