PHP Parse Soap Response Issue - SimpleXMLElement - php

I'm having problems using PHP SimpleXMLElement and simpleSMLToArray() function to parse a SOAP Response. I'm getting the SOAP response from my SOAP Server just fine. I'm writing both the SOAP Client and Server in this case. I'm using NuSoap for the server. To me, the soap response looks perfect, but the PHP5 Soap Client doesn't seem to parse it. So, as in the past, I'm using SimpleXMLElement and the function simpleXMLToArray() from PHP.NET (http://php.net/manual/en/book.simplexml.php), but can't seem to get an array.
<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/" xmlns:tns="urn:eCaseWSDL">
<SOAP-ENV:Body>
<ns1:registerDocumentByPatientResponse xmlns:ns1="urn:eCaseWSDL">
<returnArray xsi:type="tns:ReturnResult">
<id xsi:type="xsd:int">138</id>
<method xsi:type="xsd:string">registerDocumentByPatient</method>
<json xsi:type="xsd:string">0</json>
<message xsi:type="xsd:string">success</message>
<error xsi:type="xsd:string">0</error>
</returnArray>
</ns1:registerDocumentByPatientResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
PHP Code from my class ($this references apply to my library code).
// Define SimpleXMLElement
$xml_element = new SimpleXMLElement($response_string); // SOAP XML
$name_spaces = $xml_element->getNamespaces(true);
var_dump($name_spaces);
$soap = $xml_element->children('ns1');
var_dump($soap);
$soap_array = $this->simpleXMLToArray($soap);
var_dump($soap_array);
return $soap_array;
I can see the namespaces; ns1, etc. But, the array is not returned. SimpleXMLElement looks like it's returning an object, but empty.
<pre>array(3) {
["SOAP-ENV"]=>
string(41) "http://schemas.xmlsoap.org/soap/envelope/"
["ns1"]=>
string(13) "urn:eCaseWSDL"
["xsi"]=>
string(41) "http://www.w3.org/2001/XMLSchema-instance"
}
object(SimpleXMLElement)#23 (0) {
}
bool(false)
Anyone have any ideas as to what I'm doing wrong. I must not have drunk enough coffee this morning. I'm tempted to just parse it with regular expressions.

SimpleXML creates a tree object, so you have to follow that tree to get to the nodes you want.
Also, you have to use the actual namespace URI when accessing it, e.g.: urn:eCaseWSDL instead of ns1:
Try this:
$soap = $xml_element->children($name_spaces['SOAP-ENV'])
->Body
->children($name_spaces['ns1'])
->registerDocumentByPatientResponse
->children();
var_dump((string)$soap->returnArray->id); // 138

Related

Generating XML SOAP message in PHP

I need help generating XML SOAP message in PHP. I'm using BeSimpleSoap extension. I've tried many different ways to generate SOAP message.
Message should look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://apis-it.hr/umu/2015/types/kp" xmlns:gsb="http://apis-it.hr/umu/2013/types/gsb">
<soapenv:Header/>
<soapenv:Body>
<gsb:SendMessageRequest>
<gsb:GsbEnvelope>
<gsb:MessageHeader>
<gsb:SenderId>1</gsb:SenderId>
<gsb:ServiceId>126</gsb:ServiceId>
<gsb:MessageId>c4413331-1cff-11e2-f516-242d656ac4b3</gsb:MessageId>
<gsb:SenderTimeStamp>2015-05-31T12:00:00</gsb:SenderTimeStamp>
</gsb:MessageHeader>
<gsb:Content>
<gsb:MimeType>aaa</gsb:MimeType>
<gsb:Data encoding="EMBEDDED">
<tns:Upit>
<tns:IdPosiljatelja>1</tns:IdPosiljatelja>
<tns:TipPoruke>1</tns:TipPoruke>
<tns:IdUpita>732262f1-063f-11e2-892e-0812200c9f68</tns:IdUpita>
<tns:DatumVrijemeUpita>2015-03-26T15:33:29.371+01:00</tns:DatumVrijemeUpita>
</tns:Upit>
</gsb:Data>
</gsb:Content>
</gsb:GsbEnvelope>
</gsb:SendMessageRequest>
</soapenv:Body>
</soapenv:Envelope>
I have tried to generat XML with this:
$encodded = new SoapVar("<tns:Upit>
<tns:IdPosiljatelja>196</tns:IdPosiljatelja>
<tns:TipPoruke>$TipPoruke</tns:TipPoruke>
<tns:IdUpita>$UUID</tns:IdUpita>
<tns:DatumVrijemeUpita>$date_time</tns:DatumVrijemeUpita>
</tns:Upit>", XSD_ANYXML);
$par_envelope=array( "GsbEnvelope" =>
array( "MessageHeader" =>
array("SenderId" => "24",
"ServiceId" => "$ServiceId",
"MessageId" => $UUID,
"SenderTimeStamp" => $date_time),
"Content" => array("MimeType" =>"application/xml","Data" =>array("any"=>$encodded,"encoding"=>"EMBEDDED"))));
$par_WSDL=array("trace"=>TRUE,
"exceptions"=>TRUE,
'location'=>$SERVICE_TEST,
"local_cert" =>$SOAP_cert,
'uri'=>$NAMESPACE_URI,
"passphrase"=>$cert_password,
"connection_timeout" => 60);
$client = new BeSimple\SoapClientSoapClient("GSBService.wsdl",$par_WSDL);
$result=$client->sendMessage($par_envelope);
But that only generated part of a XML message that looks like:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://apis-it.hr/umu/2013/types/gsb">
<SOAP-ENV:Body>
<ns1:SendMessageRequest>
<ns1:GsbEnvelope>
<ns1:MessageHeader>
<ns1:SenderId>1</ns1:SenderId>
<ns1:ServiceId>1</ns1:ServiceId>
<ns1:MessageId>34578b73-988a-4727-bee4-a287218cc0a1</ns1:MessageId>
<ns1:SenderTimeStamp>2015-10-01T09:07:25+02:00</ns1:SenderTimeStamp>
</ns1:MessageHeader>
<ns1:Content>
<ns1:MimeType>application/xml</ns1:MimeType>
<ns1:Data/>
</ns1:Content>
</ns1:GsbEnvelope>
</ns1:SendMessageRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
EDIT Here you can see WSDL and XSD files.
It seems that the library adds its own namespace prefixes. This is not a problem. In XML the following 3 examples have the same meaning:
<ns1:SendMessageRequest xmlns:ns1="http://apis-it.hr/umu/2013/types/gsb">
<gsb:SendMessageRequest xmlns:gsb="http://apis-it.hr/umu/2013/types/gsb">
<SendMessageRequest xmlns="http://apis-it.hr/umu/2013/types/gsb">
The XML parser will resolve all 3 to an element node with the local name SendMessageRequest in the namespace http://apis-it.hr/umu/2013/types/gsb.
So the changed prefix is not a problem. The library can do this to generate/optimize the output.
But, your XML Soap variable is not valid XML. You did not add the namespace definition. If an element has a prefix you will need a namespace definition for this prefix on the element node or one of its ancestors.
$encoded = new SoapVar(
"<tns:Upit xmlns:tns='http://apis-it.hr/umu/2015/types/kp'>
<tns:IdPosiljatelja>196</tns:IdPosiljatelja>
<tns:TipPoruke>$TipPoruke</tns:TipPoruke>
<tns:IdUpita>$UUID</tns:IdUpita>
<tns:DatumVrijemeUpita>$date_time</tns:DatumVrijemeUpita>
</tns:Upit>",
XSD_ANYXML
);
I would advise you to only use array or objects to generate the request that is simply pass as parameter to your SoapClient. And not mix xml strings and Objects.
For example, if ou use a WSDL to php generator, you'll only deal with PHP objects and the XML request will be generated natively by the SoapClient in order to send it to the SOAP Server.
If I can advise you some good WSDL to php generator:
wsdltophp.com
PackageGenerator

returning soap xml response for a soap server php

I am trying to create a soap service in php using native php soap server. I have already prepared the wsdl file.
There are basically four methods that can be called with the soap service. The input soap request for one of the request ShowRemittanceDetail is shown below.
<soap-env:body>
<ns1:showremittancedetailrequest>
<username>admin</username>
<password>pass</password>
<refno>USA1956127848</refno>
</ns1:showremittancedetailrequest>
</soap-env:body>
Anyway the soap request does not have a header and I have just shown the body here. I have no problem parsing the soap request. The response should look like this
<?xml version="1.0" encoding="ISO-8859-1"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns2:responseType xmlns:ns2="http://tempuri.org/response">
<code>00</code>
<message>Transaction does not exist or is not available</message>
<responseBody>
<responseStr>4</responseStr>
</responseBody>
</ns2:responseType>
</soapenv:Body>
</soapenv:Envelope>
This is a particular response which is generated when the transaction with the reference number is not available in the server.
I have received the soap request and evaluated it. However I have a problem with the return type of the soap response. I cannot generate a valid response. What type of response should a soap server return?
Things I have tried:
I have tried returning an xml string. But the soap client request throws an exception with the following message.
looks like we got no xml document.
I have also tried returing a native php SoapVar() with the same result.
I have tried returning an object response that is specified in the classmap fo the soap server.
e.g. for the example above, I have tried returning a ShowRemittanceDetailResponse object with the same result. (looks like we got no xml document).
I have tried returning a DomDocument Object . The exception thrown in this case is
the encoded object does not have a responseStr property.
I have tried returning an stdClass object with the same fields as the response expects with similar result.
Please help me.
Thanks in advance.
The solution I found was returning a SoapVar object. I didnt have soapui and the client I wrote in php was incorrect. Hence, I had problem verifying the returned xml as the php soap client was throwing an exception. The correct way for me was to return a SoapVar.

Returning a JSON object from PHP SoapServer

How can I force my PHP SoapServer to send a JSON object as a response instead of an XML doc?
Thanks.
That is not SOAP, so no. It can incorporate a jsonstring in some xml node, that's about it. You may want just a REST server serving json.
You can bastardize it though, making it by definition NOT SOAP, but some weird hybrid:
<?php
class ThisIsNotASoapServer extends SoapServer {
}
function test(){
//should have a return
//return range(1,9);
//but totally breaks it by:
echo json_encode(range(1,9));
//the exit here is needed
exit;
}
$server = new ThisIsNotASoapServer(null, array('uri' => 'http://test-uri/','soap_version' => 1));
$server->addFunction("test");
$server->handle('<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:Test xmlns:m="Some-URI"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>');
?>
... so, technically this is possible, but I suspect there is not a single client which understands this.
Take a look at http://www.sinatrarb.com its very easy to create a restful web service to return a json object.
depends on your requirements - SOAP is a xml request it doesnt mean the format for the return also needs to be SOAP (XML) you can easily post back a JSON string.
Maybe if you can provide more information we can help more?

Problems in using PHP Soap Client

I have this web service to access with this kind of configuration:
<?xml version="1.0" encoding="utf-8"?>
<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:Body>
<Executar xmlns="http://localhost/I9ProWebService">
<Servico>string</Servico>
<conteudoXML>string</conteudoXML>
</Executar>
</soap:Body>
</soap:Envelope>
So I tried this:
$client = new soapclient('https://domain/webservice/I9ProWebService.asmx?WSDL');
printf($client->Executar("ListarTomador","<i9proerp><listar_tomador id_pessoa_corretor =\"205\" /></i9proerp>"));
it shows this error:
System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.NullReferenceException: Object reference not set to an instance of an object. at I9ProWebService.Executar(String Servico, String conteudoXML) --- End of inner exception stack trace ---
Have you tried using htmlentities or similar to encode the XML you are sending as your second parameter? That might be causing problems with the XML sent by the SOAP client.
EDIT: In order to see what XML the PHP SOAP client is sending and what it's getting back, you can use $client->__getLastRequest() and $client->__getLastResponse() and compare the results with your soapUI call.
I found the solution of my problem.
$client = new SoapClient("http://domain/webservice/I9ProWebService.asmx?WSDL", array("features" => SOAP_SINGLE_ELEMENT_ARRAYS, "encoding" => "utf-8","trace"=> TRUE));
$strVariavel = "<ns1:conteudoXML><i9proerp><listar_tomador id_pessoa =\"999\"/></i9proerp></ns1:conteudoXML>";
$soapvar = new SoapVar($strVariavel, 147);
$xml = $client->ExecutarXML(array('Servico'=>'ListarTomador','conteudoXML'=>$soapvar));
print_r($xml);
and voilá
The problem is that it returns and object and not a XML as I expected...
It returns:
stdClass Object
(
[ExecutarXMLResult] => stdClass Object
(
[any] => <i9proerp xmlns=""><listatomador id_pessoa="5251" nm_pessoa="nome1" nr_cnpj_cpf="132132121332"/><listatomador id_pessoa="939" nm_pessoa="nome2" nr_cnpj_cpf="3213213123213"/></i4proerp>
)
)
So, I have to discover how to deal with it. Is it a case to open another question?

parse an XML with SimpleXML which has multiple namespaces [duplicate]

This question already has answers here:
Reference - How do I handle Namespaces (Tags and Attributes with a Colon in their Name) in SimpleXML?
(2 answers)
Closed 3 years ago.
I have this ugly XML which has alot of namespaces on it, when I try to load it with simpleXML if i indicate the first namespace I'd get an xml object ,but following tags with other namespaces would not make it to the object.
How can I parse this XML ?
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header>
<eb:MessageHeader xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" eb:version="1.0" soap-env:mustUnderstand="1">
<eb:From>
<eb:PartyId eb:type="URI">wscompany.com</eb:PartyId>
</eb:From>
<eb:To>
<eb:PartyId eb:type="URI">mysite.com</eb:PartyId>
</eb:To>
<eb:CPAId>something</eb:CPAId>
<eb:ConversationId>moredata.com</eb:ConversationId>
<eb:Service eb:type="compXML">theservice</eb:Service>
<eb:Action>theaction</eb:Action>
<eb:MessageData>
<eb:MessageId>a certain messageid</eb:MessageId>
<eb:Timestamp>2009-04-11T18:43:58</eb:Timestamp>
<eb:RefToMessageId>mid:areference</eb:RefToMessageId>
</eb:MessageData>
</eb:MessageHeader>
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext">
<wsse:BinarySecurityToken valueType="String" EncodingType="wsse:Base64Binary">an impresive binary security toekn</wsse:BinarySecurityToken>
</wsse:Security>
</soap-env:Header>
<soap-env:Body>
<SessionCreateRS xmlns="http://www.opentravel.org/OTA/2002/11" version="1" status="Approved">
<ConversationId>the goodbye token</ConversationId>
</SessionCreateRS>
</soap-env:Body>
</soap-env:Envelope>
im trying to parse it with the following code
<?php
$xml = simplexml_load_string($res,NULL,NULL,"http://schemas.xmlsoap.org/soap/envelope/");
?>
but the $xml object would only contain the following
SimpleXMLElement Object
(
[Header] => SimpleXMLElement Object
(
)
[Body] => SimpleXMLElement Object
(
)
)
I think you need to register the namespacing and access with XPath. Something like the following should get you going (I haven't the facility to test this).
$xml = simplexml_load_string($res, NULL, NULL, "http://schemas.xmlsoap.org/soap/envelope/");
$xml->registerXPathNamespace('soap-env', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('eb', 'http://www.ebxml.org/namespaces/messageHeader');
$xml->registerXPathNamespace('wsse', 'http://schemas.xmlsoap.org/ws/2002/12/secext');
Then you can do something like:
foreach($xml->xpath('//eb:MessageHeader') as $header)
{
var_export($header->xpath('//eb:CPAId')); // Should output 'something'.
}
You may not need to register the namespacing, thinking about it, as they are alredy present in the XML. Not sure on this though, would need to test.
Hope this helps.
1) Do not use print_r and friends to see what is "in" a SimpleXML object. See https://github.com/IMSoP/simplexml_debug for explanation and alternatives.
2) Namespace support in SimpleXML is provided by the ->children() and ->attributes() methods.
For example you could get the PartyId of the From node like this:
$from_party = (string)$xml->children('soap-env', true)->Header->children('eb', true)->MessageHeader->From->PartyId;
For anyone else that comes across this I scratched my head trying to return the correct data and although the top answer was extremely close it still took me a while to find the answer. Eventually used this page to help: https://www.w3schools.com/php/func_simplexml_registerxpathnamespace.asp
I believe the for loop can directly access what you need. i.e.
foreach($xml->xpath('//eb:CPAId') as $header)
{
echo $header; // Should output 'something'.
}
That's a soap-envelope. You might want to use a soap-client to abstract all the xml-parsing away. PHP comes with a rather good soap-client included as default.
Try this
$soap_url = 'http://path/wsdl/somefile.wsdl';
$soap_client = new SoapClient($soap_url);
var_dump($soap_client->__getFunctions());
For more detail read here

Categories