web design
  • February 05, 2009 by admin

    PHP Soap call for WSDL Envelope and Payload

    In this tutorial I will show you how to make a PHP SOAP call without declaring the long array like other examples on PHP.net and show a little hack around their built in SOAP class. First we have to understand what a SOAP is. I am not gonna go into length about the history of it, but SOAP stands for Simple Object Access Protocol and handles its purpose like a remote procedure call. Conventionally, a SOAP request/response object has an Envelope and a Payload. An Envelope wraps around a payload or the payload is MIME attachment to a request. Some languages such as Java, its built-in functions allow the payload to pass as a MIME object. The envelope contains information such as security encryption, sessions, and all the header information of a SOAP request call. On the other hand, the payload contains parameters, variables’ values, and etc for this request in order for the server to process it. Usually a request calls to a function or a method on server so the payloads contain the parameters for the server to process . The returning result from a SOAP call is the response XML.

    Here is your Envelope:

    <?xml version='1.0' encoding='UTF-8'?>
    <SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:eb="http://www.ebxml.org/namespaces/messageHeader"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema">
    <SOAP-ENV:Header>
    <eb:MessageHeader SOAP-ENV:mustUnderstand="1" eb:version="2.0">
    <eb:Service eb:type="serviceXML">RunningBunnyRQ</eb:Service>
    <eb:Action>RunnyBunnyRQ</eb:Action>
    </eb:MessageHeader>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
    <eb:Manifest SOAP-ENV:mustUnderstand="1" eb:version="2.0">
    <eb:Reference xmlns:xlink="http://www.w3.org/1999/xlink"
    xlink:href="cid:rootelement"
    xlink:type="simple"/>
    </eb:Manifest>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    

    Here is your Payload:

    <BunnyDuration>
    <Time Length="1000"/>
    </BunnyDuration>
    

    You can merge the two together to get this:

    <SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:eb="http://www.ebxml.org/namespaces/messageHeader"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema">
    <SOAP-ENV:Header>
    <eb:MessageHeader SOAP-ENV:mustUnderstand="1" eb:version="2.0">
    <eb:Service eb:type="serviceXML">RunningBunnyRQ</eb:Service>
    <eb:Action>RunnyBunnyRQ</eb:Action>
    </eb:MessageHeader>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
    <RunningBunnyRQ>
    <BunnyDuration>
    <Time Length="1000"/>
    </BunnyDuration>
    </RunningBunnyRQ>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    

    Usually the header of a SOAP call is the same and does not change much so it is a waste of time turning it into a Multi-dimensional array. The default way of doing this in PHP is a multi-dimensional array with associations. If you want to save a lot of time just like me I went along and pass the whole envelope to make a request along with the payload. I can always change and parse the payload according to whatever I want using multi-dimensional array or REGEX because the payload is usually small and straightforward.

    Here is how the standard SOAP in PHP handles a request. First it takes your multidimensional associated array and turns it into an XML. It is pretty lame how it does it because it is a really simple XML so when you get an Envelope with a lengthy header it complicates thing for you to figure out the correct formatting for your array. If you are stuck in this situation, here is a simple hack around this problem:

    class feedSoap extends SoapClient
    {
    
    var $XMLStr = "";
    function setXMLStr ($value){$this->XMLStr = $value; }
    function getXMLStr(){return $this->XMLStr; }
    
    function __doRequest($request, $location, $action, $version) {
    $request = $this -> XMLStr;
    $dom = new DOMDocument('1.0');
    try {
    $dom->loadXML($request);
    } catch (DOMException $e) {
    die($e->code);
    }
    $request = $dom->saveXML();
    
    //doRequest
    return parent::__doRequest($request, $location, $action, $version);
    }
    function SoapClientCall($SOAPXML)
    {
    return $this -> setXMLStr ($SOAPXML);
    }
    }
    

    The class above allows you to pass directly an XML string into a Soap call. What I did is I overload the doRequest of the standard Soap call with an overload function that stops it from doing what it is suppose to do: pass the XML derived from the multidimensional array. Inside the original Soap library when a Soap request is called, it triggers doRequest automatically but the SoapClientCall is initialize before the call and set the $request value to our friendly XML string.

    The next step is a function to use this class:

    function soapCall($wsdlURL, $callFunction="", $XMLString)
    {
    $client = new feedSoap($wsdlURL, array('trace' => true));
    $reply = $client-> SoapClientCall($XMLString);
    $client->__call("$callFunction", array(), array());
    return $client -> __getLastResponse();
    }
    

    $wsdlURL is where the url of SOAP service is. It has to be in the format of a wsdl file or the PHP soap call will throw an error. The soapCall function about will return to us the getLastResponse of the Soap request. With a slight modification of the code above we can really do some serious Soap calls. Also note, the soap_feed call will also throw an error if the server complains. What we can do is to catch an exception.

    Stay tune to the next post on how to create your own WSDL server and exposing some services on your server to others.

     

    8 Comments

    1. Pingback: How To.. | PHP Soap call for WSDL Envelope and Payload | How To Remove

    2. Jesus says:
      February 5, 2009 at 9:10 am

      Hi Thy,

      Interesting hack.
      I have one more interesting, ¿how to send mime attachments with the SOAP extension?

      I have been looking for some info but there isn’t any useful documents.
      Do you think it would be possible?

    3. chhh says:
      February 21, 2009 at 6:48 am

      that looks nice, i’ll definitely try it.
      but i can’t find out what is the usual way in php_soap to construct the correct parameters array.. i need to change some values in the envelope headers, how is this done?

    4. Sanjay Raut says:
      April 19, 2009 at 8:48 pm

      This works for complex datatypes too. Only thing to be taken care is processing the XML response.

    5. Thy says:
      June 19, 2009 at 9:11 am

      This is very true. In some cases you have to take care of the XML response or you will get a Soap Error.

    6. Thy says:
      June 19, 2009 at 9:19 am

      For php, you have to know more about handling header request and response for mime envelope which is not even documented at all. You can take a look at the Soap library to see if you can use their function and overload it. The solution that I came up with is to plug in the mime attachment data into the payload. I hope that will help you.

    7. Tan-Tan says:
      October 14, 2009 at 1:58 am

      I try to release a PHP WSDL BPEL engine, base on PHP CLI application server.
      Any help would be appreciated.

      http://code.google.com/p/ezerphp/

    8. PaulF says:
      June 11, 2013 at 7:23 am

      You are a life-saver. This worked for me when all else failed. Thanks!

    Leave a Comment

    • required  
    • required  
    •