Question

A question about PHP's SoapClient and SoapServer, WSDL mode.

I need, let's say, create a digest of a certain part of XML with the data in it. With SoapClient it's easy. I overload __doRequest() method from class SoapClient, make hash of certain elements and attach it as the element <Hash></Hash> within <SOAP-ENV:Header/>. Then I send the resulting XML to the SOAPServer calling parent::__doRequest().

I need to do the same with the response XML. On Server's side I have difficulties. Seems like the Server can only send data as nested arrays or objects, and that somehow is inserted into the response XML on Client's side. I tried sending XML with SoapServer's response, then it returns empty XML.

I really need to parse and modify the XML on Server's side (make hash, digital signature, etc) but so far I haven't found the answer how to do it no matter where I search so I would really really appreciate your help. Thanks.

Was it helpful?

Solution

You will have to get an XML string without XML declaration and parse that with SoapVar.
See how-return-custom-xml-response-in-soapserver-response for details.

In short, it comes to this.
You construct a DOMDocument from your input and any other stuff you need to put into it. XSLT is a nice way to parse and change XML (see above link again for a simple example on how to use xslt in php).
Then you select the DOMNode from the DOMDocument you wish to return, and apply saveXML with this node as parameter. This saves the wanted XML as a string without the declaration. Plain saveXML() without parameter would have saved the root node as a string including the declaration. Thus:

$nodes = $dom -> getElementsByTagName ('chooseTheElementYouWishToReturn');
$node = $nodes -> item(0);

$result = new SoapVar ($dom -> saveXML($node), XSD_ANYXML);
return ($result);

This also works of course, when you wish to return the root element:

$result = new SoapVar ($dom -> saveXML($dom -> documentElement), XSD_ANYXML);
return ($result);

ADDITION

I noticed that you wish to add something to the SOAP header instead of to the body.
This is a little tricky too but it can be achieved - I hope the below will fit your needs.

First, adding header details can only be done within the function script, and then the function will have to declare the server variable as global in order to refer to the globally (outside the function) declared one, as follows:

<?php   
    class mySOAPclass {
        function xxx ($arg) {
            global $server;

            // your code for the header part
            // example
            $auth = array();
            $auth['UserName'] = 'user';
            $auth['Password'] = 'pw';
            $header = new SoapVar ($auth, SOAP_ENC_OBJECT);
            // end example

            $header = new SoapHeader ('http://schemas.xmlsoap.org/soap/header/', 'credentials', $header, false);
            $server -> addSoapHeader ($header);

            // your code for the body part, assuming it results in a DOM $dom

            $result = new SoapVar ($dom -> saveXML($dom -> documentElement), XSD_ANYXML);

            return ($result);
        }

    ini_set( "soap.wsdl_cache_enabled", "0");
    $server = new SoapServer ("yourOwn.wsdl");
    $server -> setClass ('mySOAPclass');
    $server -> setObject (new mySOAPclass());
    $server -> handle();
?>

Note that it is required to first construct a SoapVar from the array; if you feed the array to the header directly you get ugly item/key and item/value nodes.

The above leads to the following return structure:

<SOAP-ENV:Envelope 
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ns1="http://schemas.xmlsoap.org/soap/header/">
    <SOAP-ENV:Header>
        <ns1:credentials>
            <UserName>user</UserName>
            <Password>pw</Password>
        </ns1:credentials>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
        ...
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top