3

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.

  • I wish to know the same. See my question `http://stackoverflow.com/questions/12692797/how-do-i-catch-data-from-the-xml-content-of-a-soap-request-in-a-php-soapserver` where I ask how I can get data from the input XML (which seems to be cast on a `stdClass` object) and of course also return some XML (possibly the input one, but modified as you wish to do) - but I cannot find anything useful on this anywhere. I hope your question gets answered! – Maestro13 Oct 03 '12 at 15:29
  • I made some progress. Getting the data from the input starts with using `file_get_contents ('php://input')`, see `http://stackoverflow.com/questions/10835336/parsing-soap-response-via-wsdl-soapserver/10955907#10955907`. But I still ca't create the return XML as I wish to - I get some standard return value that seems to be generated by soapServer, using defs from the WSDL but strangely enough not returning the top level as specified in the message, but with a name equal to the input one + "Response". I will let you know when I discover how to do that. – Maestro13 Oct 04 '12 at 20:16
  • @Maestro13 Yep, thanks - I used this question [link](http://stackoverflow.com/questions/6895187/get-recieved-xml-from-php-soap-server) to help me parse XML from client, but still no idea how to create and modify XML on server side. I guess we can figure both our problems out, let's discuss it, just email me any of your contact info to supervodka (at) gmail dot com, thanks:) –  Oct 05 '12 at 05:39

1 Answers1

0

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>
Community
  • 1
  • 1
Maestro13
  • 3,656
  • 8
  • 42
  • 72