Question

I am trying to set up a SOAP service in php. I declared a server php function and I am able to call that function with a SOAP type http request where the content is my SOAP envelope.

The XML content of the SOAP body is the argument of the function I assume, but I don't know how to access the information in it in my php code.

I noticed that the function argument is an instance of stdClass by default, and I actually wonder why it is not casted on an XML or DOM object by php - it's a SOAP call isn't it? But all right, now it's up to me to get the information out of the object, which is not easy because there's no methods assigned to stdClass, so it'll have to be standard php functions. So I tried serialize, but this gave me some rubbish, not the XML string I expected.

What to do?

EDIT

note that below has no example code of what I wish to do - get some detail data from the XML content of the SOAP request - because I don't know how to code getting it from the stdClass object

On request of david, here's some details.

php code:

<?php
    function mi102($arg) {
        $txt = serialize ($arg);
        $result = new SoapVar ($txt, XSD_ANYXML);
        return($result);
    }
    ini_set( "soap.wsdl_cache_enabled", "0");
    $server = new SoapServer ("test.wsdl");
    $server -> addFunction ("mi102");
    try {
        $server -> handle();
    }
    catch (Exception $e) {
        $server -> fault ('Client', $e -> getMessage());
    }
?php>

http request is constructed by an application that I use; the http header and the soap envelope + body are generated around the XML I feed it:

SOAP request body content:

<mi102 xmlns="http://pse">
  <cdhead cisprik="21"/>
  <instr>
    <insid>
      <bcdt>20120930</bcdt>
    </insid>
  </instr>
</mi102>

The WSDL used is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://pse/" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="PSE" targetNamespace="http://pse/">
    <types>
        <xs:schema>
            <xs:import namespace="http://pse/" schemaLocation="PSE.xsd"/>
        </xs:schema>
    </types>
    <message name="MI102Req">
        <part name="cdhead" type="tns:cdhead_T"/>
        <part name="instr" type="tns:instr_T"/>
    </message>
    <message name="Res">
        <part name="cdhead" type="tns:cdhead_T"/>
    </message>
    <portType name="MIPortType">
        <operation name="mi102">
            <input message="tns:MI102Req"/>
            <output message="tns:Res"/>
        </operation>
    </portType>
    <binding name="MIBinding" type="tns:MIPortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="mi102">
            <soap:operation soapAction="http://testServerURL/test_soap.php#mi102"/>
            <input>
                <soap:body use="literal" namespace="http://pse/"/>
            </input>
            <output>
                <soap:body use="literal" namespace="http://pse/"/>
            </output>
        </operation>
    </binding>
    <service name="PSE">
        <port name="MIPortType" binding="tns:MIBinding">
            <soap:address location="http://testServerURL/test_soap.php"/>
        </port>
    </service>
</definitions>

And the resulting XML (again, extracted from the SOAP body by the application I use), is

SOAP response:

<?xml version="1.0" encoding="UTF-8"?>
<ns1:mi102Response xmlns:ns1="http://pse/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">O:8:"stdClass":2:{s:7:"cisprik";i:21;s:7:"version";s:2:"13";}</ns1:mi102Response>

Not nice.

Was it helpful?

Solution

I eventually found the answer in other threads on SO, like get-recieved-xml-from-php-soap-server

The solution is to use the following:

$inp = file_get_contents ('php://input');

Note: I could not find any function that can act on the stdClass input argument and can retrieve the XML SOAP Body contents from it.
So the best option is to use the standard php input variable. Note that this has the following structure: Envelope/Body/..inputXML.., which is the exact http request content that is posted to the server.

Note: http_get_request_body may work too, but my php server did not support this function. I think that file_get_contents is supported on every php server from some version onwards.

OTHER TIPS

This will not start out as a complete answer, but I wanted the formatting. Please elaborate on what you've set up. Generally, you will have a PHP method with regular arguments (not XML) that you want to expose as a web service. A basic example on how to do this is here:

http://www.phpeveryday.com/articles/Web-Services-WSDL-Creating-SOAP-Server-P484.html

The XML content of the SOAP body is the argument of the function I assume

No, the XML content of the SOAP body is the representation of the method with your arguments, but your arguments are whatever you want. You should not have to deal with XML manually if you set it up with PHP's SoapServer and SoapClient.

EDIT: You are taking your argument, which is a simple PHP array representation of your SOAP request's body, serializing it and sending it back as a response (which is what you observe). Is this what you want to do? Don't you want to do something with the request data? Also, can you post the schema that's imported from the WSDL?

You are having that "not nice" representation of an object because you are returning the object serialized(Serialization is converting the object and its state to a string representation). If you want to have an xml representation of the returned object you should change your function's return parameter type to an object. Because now is returning a string.

I would recommend you to use the Zend_Soap_Server and Zend_Soap_Autodiscover components of the zend framework.

With Zend_Soap_Autodiscover you can generate your web service definition (wsdl) dynamically , just by writing the docblocks of your functions. And Zend_Soap_Server is pretty cool too.

If you use those components and document your types and your function to return an specific type without serializing it, then you are going to receive the xml represention according to the wsdl definition. Also each type you create is automatically converted by Zend_Soap_Autodiscover to a ComplexType in the wsdl generated.

Sample:

 public class Person{
         public $id;
         public $name;
    }

    public class MyService {
     /**
     *
     * @param integer $UserID
     * @return Person
     */
    function mi102($UserID) {

         $output = new Person();
         $output->id = 2;
         $output->name = 'Peter';        

        return $output;
    }
}


// Generate WSDL relevant to code
if (isset($_GET['wsdl'])){

    $autodiscover = new Zend_Soap_AutoDiscover();
    $autodiscover->setClass('MyService');
    $autodiscover->handle();

} else {

    $server = new Zend_Soap_Server($serviceURL . "?wsdl");
    $server->setClass('MyService');
    $server->setObject(new MyService());
    $server->handle();

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top