PHP5 Soap Server

Recently I wrapped a class up and provided it as a SOAP service. Getting it working was a bit of a struggle and its clearly not something that people are doing a lot of, so here's a quick roundup of the main issues and how I tackled each one.

Start Small - Build and Check A Class

I firstly built some unit tests using PHPUnit (more about that another day perhaps, but let me say it is excellent and I tumbled to it really easily once I'd started), then wrote my class and verified the tests were passing. This was to avoid trying to debug the PHP functionality through the added layer of the SOAP.

Simple SOAP Starting Point

My next step was to get a working SOAP service. This isn't remotely tricky except that PHP can't generate its own WSDL file (for extremely valid reasons but that doesn't help me), so you either need to write it by hand or you need to generate it somehow.

As my starting point I took the whole working code from this fantastic example and checked that it worked for me.

SOAP setClass() and WSDL Fiddling

Having got this far I changed my SOAP server code to use the setClass() method and pointed it at my own original class. I then hand-edited the WSDL (one function at a time) to reflect the data types and arguments that would be moving through the service.

The actual service code looks like this:

require_once('lib/myClass.php');
ini_set("soap.wsdl_cache_enabled", "0");
 
$server = new SoapServer("service.wsdl");
$server->setClass("MyClass");
$server->handle();

The example WSDL supplied by the JimmyZ tutorial has a single function in it at the early stages, and I started with that, then adapted it for one single function from the class. This is perfectly valid providing you don't try calling anything else! The PHP function declaration took this form:

function getAccountStatus($accountID)

The function returns two variables - it passes back the account ID and also returns information about the number of credits on the account. The accountID is a string of up to 8 characters, the other variable is a number. Here is the WSDL adapted for this purpose:

<?xml version ='1.0' encoding ='UTF-8' ?>
   <definitions name='MyClass'     targetNamespace='urn:MyClassInventory'     xmlns:tns='urn:MyClassInventory'
     xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
     xmlns:xsd='http://www.w3.org/2001/XMLSchema'
     xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
     xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
     xmlns='http://schemas.xmlsoap.org/wsdl/'>
   <message name='getAccountStatusRequest'>
     <part name='accountID' type='xsd:string'/>
   </message>
   <message name='getAccountStatusResponse'>
     <part name='accountID' type='xsd:string'/>
     <part name='counter' type='xsd:float' />
   </message>
   <portType name='MyClassPortType'>
     <operation name='getAccountStatus'>
       <input message='tns:getAccountStatusRequest'/>
       <output message='tns:getAccountStatusResponse'/>
     </operation>
   </portType>
   <binding name='MyClassBinding' type='tns:MyClassPortType'>
     <soap:binding style='rpc'
       transport='http://schemas.xmlsoap.org/soap/http'/>
     <operation name='getAccountStatus'>
       <soap:operation soapAction='urn:xmethods-delayed-quotes#getAccountStatus'/>
       <input>
         <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'           encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
       </input>
       <output>
         <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
           encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
       </output>
     </operation>
   </binding>
   <service name='MyClassService'>
     <port name='MyClassPort' binding='tns:MyClassBinding'>
       <soap:address location='http://rivendell.local:10002/MyClassServiceServer.php'/>
     </port>
   </service>
   </definitions>

Once I discovered that WSDLs are best read from end to beginning, I was able to expand the example above for all the other various functions I needed.

Hopefully this helps someone get started. There are various tools available for generating the WSDL, in particular try either George's suggestion, the offering from phpclasses.org, or check out the automatic generator in ZDE. Certainly there are tools available, but I didn't manage to find one that did the trick for me.

If you are writing, or have written, a SOAP service in PHP5 then drop a comment and let me know - I certainly felt like I was in a minority on this project. Similarly if I've missed anything then I'd appreciate comments so I know for next time.

19 thoughts on “PHP5 Soap Server

  1. I'm glad you found my posts helpful.

    Great follow-up post. I'm glad you emphasized that the WSDL is best read from end to beginning. Once I discovered that, it made writing/modifying WSDLs much easier.

    • Hi Lorna Jane,

      Thanks for all this - the info on PHP and Soap on the Net is a total mess. Some choosing to to use nusoap.php - which now doesnt even exist anymore. Great work using this method I was up and running very quickly.

      However - this method only shows a call passing one parameter. What needs to change inorder for the server to accept more than one parameter from the client ?

      Kind Regards,
      Tyrone.

  2. I write on technical subjects on this site on a fairly regular basis, and nothing annoys me more than blog software which "eats" long lines of code or renders it in a difficult-to-read way. Happily Serendipity (or s9y for short) has a plugin for geshi.

  3. Just wanted to add that if you encounter connection problems to the server when using localhost then change "localhost" in the WSDL to "127.0.0.1".

  4. I could not figure out how to add a second function to the WSDL file. I always get an error when I want to call the second function. Could someone post an example please?

  5. There should be an easier way to generate the wsdl file. Isnt there any tool to do so. I am finding it diificult to get my head around this

  6. Nav: Generating a WSDL is inherently difficult to do properly in PHP - because the language is weakly typed so there is no information about what types each of the variables is expected to be. WSDL on the other hand is really strict, but it requires information that doesn't exist in PHP! I've seen some fairly good attempts at WSDL generation, but nothing that is either painless or simple. I'd love it is anyone could tell me otherwise though ...

  7. I recently had reason to write a REST server in PHP, which was very interesting. There aren't a whole lot of resources on this topic around so I thought I'd write an outline of what I did. There is quite a lot to it so I'm publishing in multiple section

  8. Andrew: Thanks for your comment - I had trouble getting the ZF version of the WSDL generator to work, but that was a couple of versions ago and I'd certainly give it another try if I had to do it again.

  9. Just to add on to this thread for posterity -- you can also use the Webservice Helper tool from http://www.jool.nl/new/

    This is a web application which lets you build your service using a class -> WSDL method, instead of the other way around.

    I had the SOAP service up and running in about half an hour using this tool. Very handy.

  10. Thank you for the useful article. After looking at numerous on-line tutorials and spending many hours testing code, your article, along with pointer to Jimmy Z's article/code, resulted in getting a basic web service running in 30 minutes. Thanks again!

  11. Thanks so much,
    This is still valid and, between you and Jimmy Z, I got this working in a few minutes. I have an iPad app that I built to consume .NET web services, and I've been trying to port it to a PHP version. Now I have something to work with.
    Cheers!

  12. Firstly i want to thank LornaJane for sharing info on php soap.
    I have done some basic examples after reading this post.
    Now i wanted to work on php soap for database (CURD) operations and having difficulties in writing the server class.
    Can you please help me out on this by giving me some good example or suggestions.

    thanks in advance and waiting for your reply.

  13. Not natively, because there isn't enough information present in PHP (as we already mentioned in this comment thread). There are some generators though, which read phpdocumentor-style comments to inform themselves of type information. I've recently used http://www.phpclasses.org/php2wsdl with good results, so you could give that a try?

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>