I've been a very busy time with webservices to whom should I call with PHP and today I have had to deal with SOAP headers. The truth is that it is a world quite dark and I met with many obstacles. I will tell you where and how I solved, but first let's look at some theory.
The web services have become the primary mode of exchange of information between applications regardless of platforms, operating systems and programming languages. SOAP is one of the protocols on which are exchanged data and is based on XML, so that the client polls the server with a XML format and receives the answer in another XML. To understand what we mean let's look at the structure of a SOAP request and response.
Call (request):
- encoding = "UTF-8" ?> <? Xml version = "1.0" encoding = "UTF-8"?>
- xmlns:ns1= "com.xplota.ws" > Xmlns:SOAP-ENV = "http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1= <SOAP-ENV:Envelope "com.xplota.ws">
- <SOAP-ENV:Header>
- <ns1:entity>
- <code> 1 </ Code>
- <Desc> </ Desc>
- </ Ns1: entity>
- <ns1:language>
- <code> 1 </ Code>
- <Desc> </ Desc>
- </ Ns1: language>
- <ns1:userId>
- <code> 1 </ Code>
- <Desc> </ Desc>
- </ Ns1: user>
- </ SOAP-ENV: Header>
- <SOAP-ENV:Body>
- </ SOAP-ENV: Body>
- </ SOAP-ENV: Envelope>
Answer (response):
- encoding = "utf-8" ?> <? Xml version = "1.0" encoding = "utf-8"?>
- xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd = "http://www.w3.org/2001/XMLSchema" > <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:Header>
- > <status Xmlns = "com.xplota.ws">
- <code> 0 </ Code>
- <Desc> Ok </ Desc>
- </ Status>
- </ Soap: Header>
- <soap:Body>
- </ Soap: Body>
- </ Soap: Envelope>
As seen in previous listings, both the request and the response consists of two XML nodes, header and body. The commonly used is the body (which I left blank because we are not interested at this time) and which contain both the parameters that are sent to the webservice in the request as returned in the response.
Sending soap headers
In the present case should send certain parameters in the header and read from there potential error codes if there had been. The shipment, despite being a structure instead of a simple parameter, was simple, you define a class with the appropriate parameters and is sent directly. The PHP SOAP engine is responsible for the translation. Consider a case study.
- / / Define the class headers
- wsHeader class
- (
- = 0 ; public $ Code = 0;
- = ” ; public $ Desc = ";
- $code , $desc ) { public function __construct ($ code, $ desc) (
- = $code ; $ This -> Code = $ code;
- = $desc ; $ This -> Desc = $ desc;
- )
- )
- / / An instance of the SOAP client
- SoapClient ( "http://midominio.com/ws?wsdl" , $par ) ; $ Client = new SoapClient ("http://midominio.com/ws?wsdl", $ par);
- / / Add the headers to requests
- = new SoapHeader ( "com.xplota.ws" , 'entity' , new wsHeader ( 1 , ” ) ) ; $ Headers [] = new SoapHeader (com.xplota.ws ", 'entity', new wsHeader (1"));
- = new SoapHeader ( "com.xplota.ws" , 'language' , new wsHeader ( 1 , ” ) ) ; $ Headers [] = new SoapHeader (com.xplota.ws', 'language', new wsHeader (1 "));
- = new SoapHeader ( "com.xplota.ws" , 'userId' , new wsHeader ( 1 , ” ) ) ; $ Headers [] = new SoapHeader (com.xplota.ws', 'userId', new wsHeader (1 "));
- $headers ) ; $ Client -> __setSoapHeaders ($ headers);
- / / Launch the call to the method of ws
- -> TuMetodo ( $parametros ) ; $ Result = $ client -> TuMetodo ($ params);
As you can see is quite simple to understand. By adding a header must indicate the namespace it belongs to the SOAP engine knows how to treat it, is given a name and the object that contains it.
With this we have solved the delivery side of our heads and have a SOAP request as we indicated in the first XML.
Receiving SOAP headers
Now that the method in our webservice says with some other headers that we know how to interpret the XML response as the second listing. Then we have a very big problem. There is no way to get these headers, the SOAP engine of PHP only returns the body, never headers.
According to the PHP manual method __soapCall SOAP client to define an array which will return these headers, but I was not able to run the invocation of a webservice method with this syntax while invoking them directly on the client (how documentation states that can be done) I worked it perfectly. That is, the theory says that the first method I can get headers but I worked while I worked the second but it returns the headers and there is no way to recover them.
After a long quarrel with SOAP and research functions but not yet arrived at any conclusion, it is as if it had happened to anyone, I did not find anything useful. I only had a solution, make my own class from the SOAP original response to process the XML by hand to obtain the data needed. Said and done. Let the solution.
First I create my own kind of SOAP and I check if I can do what I want.
- SoapClient { XSoapClient class extends SoapClient (
- $wsdl , $options ) { public function __construct ($ wsdl, $ options) (
- , $options ) ; parent:: __construct ($ wsdl, $ options);
- )
- $request , $location , $action , $version ) { public function __doRequest ($ request, $ location, $ action, $ version) (
- $request , $location , $action , $version ) ; $ Response = parent:: __doRequest ($ request, $ location, $ action, $ version);
- ; return $ response;
- )
- )
- XSoapClient ( "http://midominio.com/ws?wsdl" , $par ) ; $ Client = new XSoapClient (http://midominio.com/ws?wsdl ", $ par);
Think I'll be lucky if I try this new SOAP client works perfectly, but also if I check the contents of $ response I see that contains the full XML webservice response. How you see the only thing that changes is that it happened instantiate the name of the new class. Good start, if I play my cards right I can get the headers in the method __doRequest
.
Let us since this XML to get what we want. Thanks to the functions DOM and XPath in PHP is very simple. This is the end result of my client recovery SOAP headers:
- SoapClient class SoapClient extends XSoapClient
- (
- $wsdl , $options ) { public function __construct ($ wsdl, $ options) (
- , $options ) ; parent:: __construct ($ wsdl, $ options);
- )
- $request , $location , $action , $version ) { public function __doRequest ($ request, $ location, $ action, $ version) (
- $request , $location , $action , $version ) ; $ Response = parent:: __doRequest ($ request, $ location, $ action, $ version);
- DOMDocument; $ Dom = new DOMDocument;
- ( $response , LIBXML_NOWARNING ) ; $ Dom -> loadXML ($ response, LIBXML_NOWARNING)
- DOMXPath ( $dom ) ; $ Path = new DOMXPath ($ dom);
- ( 'soap' , 'http://schemas.xmlsoap.org/soap/envelope/' ) ; $ Path -> registerNamespace ('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
- -> query ( '//soap:Header/*' ) ; $ Xml = $ path -> query ('/ / soap: Header / *');
- = $this -> headers2array ( $xml ) ; $ This -> responseHeaders = $ this -> headers2array ($ xml);
- ; return $ response;
- )
- getResponseHeaders public function () (
- -> responseHeaders ; return $ this -> responseHeaders;
- )
- $response ) { headers2array private function ($ response) (
- $response as $node ) { foreach ($ response as $ node) (
- $node -> hasChildNodes ( ) ) { if ($ node -> hasChildNodes ()) (
- $node -> nodeName ] = $this -> headers2array ( $node -> childNodes ) ; $ Headers [$ node -> nodeName] = $ this -> headers2array ($ node -> childNodes);
- { Else ()
- $node -> nodeName ] = $node -> nodeValue ; $ Headers [$ node -> nodeName] = $ node -> nodeValue;
- )
- )
- ; return $ headers;
- )
- )
- = new XSoapClient ( "http://midominio.com/ws?wsdl" , $par ) ; lang= <pre "php"> $ client = new XSoapClient (http://midominio.com/ws?wsdl ", $ par);
- -> TuMetodo ( $parametros ) ; $ Result = $ client -> TuMetodo ($ params);
- -> getResponseHeaders ( ) ; $ Soapheaders = $ client -> getResponseHeaders ();
Problem solved and quite elegant. If anyone knows how to get the headers without assembling all this mess you tell me please.










3 users have commented on "Webservices: Dealing with SOAP headers in PHP"
Feed comments for this entry TrackbackIn the form
$ Client-> __soapCall (someFunction ", array ($ a, $ b, $ c), NULL,
SoapHeader new (), $ output_headers)
should work, otherwise you will be due to some peculiarity of the service on the server side.
http://www.php.net/manual/es/soapclient.soapcall.php
Bellzebu Indeed, the theory is good
[...] Dealing with SOAP headers in PHP (2) PHP, Programming, Technical Following the previous article explaining how to read the headers in a SOAP response, I have discovered how to make [...]
Leave a response