Web Services

The following example shows a remote call to a method "answerMe" which takes one parameter and returns a string to the client. Server and client communicate by using a WSDL file, which can be publicly accessed by the client. The WSDL file describes the method (called "operation" in the WSDL file), the data type of the input/output parameters (called "message parts"), and the details of how this is transmitted (using "soap" and "rpc" via the http protocol).

The server

class WorldService {
  private $worldattributes = array("1" => "brave", "2" => "new");
  function answerMe($whatKindOfWorld) {
    return "Hello ".$this->worldattributes[$whatKindOfWorld]." World";    
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache 
$server = new SoapServer("helloworld.wsdl");                                        

1.1 Exercise

1) Save this file as "helloserver.php" (permission 755). Look at it through the browser. If you get a "parse error", this means there is a syntax error in your file. Fix the error before proceeding to the next exercise below. If you see "WSDLSOAP-ERROR: Parsing WSDL: Couldn't load from 'helloworld.wsdl'", your file is probably ok. It is complaining about a missing WSDL file because you have not yet created it. A "500 Internal Service Error" can also be an indication that it is working ok at this point.

1.2 The WSDL file

Ideally the WSDL file should be generated by a script, not by hand. There are some PHP functions for automatically generating this file but they are not (yet) included in the standard PHP distribution.
<?xml version ='1.0' encoding ='UTF-8' ?> 
<definitions name='HelloWorld' 
  xmlns:tns=' http://example.org/HelloWorld ' 

<message name='getHelloWorldRequest'> 
  <part name='whatKindOfWorld' type='xsd:string'/>
<message name='getHelloWorldResponse'> 
  <part name='Result' type='xsd:string'/> 

<portType name='HelloWorldPortType'> 
  <operation name='answerMe'> 
    <input message='tns:getHelloWorldRequest'/> 
    <output message='tns:getHelloWorldResponse'/> 

<binding name='HelloWorldBinding' type='tns:HelloWorldPortType'> 
  <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> 
  <operation name='answerMe'> 
    <soap:operation soapAction='urn:localhost-HelloWorld#answerMe'/> 
      <soap:body use='encoded' namespace='urn:localhost-HelloWorld' 
      <soap:body use='encoded' namespace='urn:localhost-HelloWorld' 

<service name='HelloWorldService'> 
  <port name='HelloWorldPort' binding='HelloWorldBinding'> 
    <soap:address location='http://YOURSERVER/~USERNAME/php/helloserver.php'/> 

1.3 Exercise

2) Save the file as helloworld.wsdl (permission 644). Replace "YOURSERVER" and "USERNAME". Looking at the file through the browser just shows the XML code. Now look at helloserver.php through your browser. If you get an error "WSDLSOAP-ERROR: Parsing WSDL: Couldn't load from .." this means there is a problem with the WSDL file. Fix the problem. If you see "SOAP-ENV:ServerBad Request. Can't find HTTP_RAW_POST_DATA" the server and the WSDL file are probably ok. It is complaining about missing RAW data because you haven't send any client data to it so far. A "500 Internal Service Error" can also be an indication that it is working ok at this point.

Test your wsdl file using a generic client.

1.4 Non-WSDL client

A client does not have to use WSDL in order to communicate (although it is usually better to use WSDL). Here is a simple client:

$client = new SoapClient(NULL, array(
        "location" => "http://YOURSERVER/~USERNAME/php/helloserver.php",
        "uri"      => "something",
        "style"    => SOAP_RPC,
        "use"      => SOAP_ENCODED

print($client->__soapCall("answerMe", array(new SoapParam("2","whatKindOfWorld"))));

1.5 Exercise

3) Implement the client. Replace "YOURSERVER" and "USERNAME". If you get an error "DTD are not supported by SOAP" that means that the URL of the server is incorrect. If you get a "parse error", this means there is a syntax error in your file. Change the parameter from "2" to "1" and observe what happens.

1.6 A client using WSDL

The client below accesses the server locally via the local URL "helloworld.wsdl". In real applications the client would be on a different server, thus a non-local URL ("http://...") would be used to access the server. The client catches errors. This isn't necessary, but good programming style.
ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache 

try {  
  $client = new SoapClient("helloworld.wsdl");
  $result = $client->answerMe("1"); 
} catch (SoapFault $exception) {  
  echo $exception;  


1.7 Exercise

4) Implement the client.

5) Display the SOAP XML data:
If you change the client constructor to

$client = new SoapClient("helloworld.wsdl",array("trace"=>1));
and print this after the result:
print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."<p>"; 
print "Response:\n".htmlspecialchars($client->__getLastResponse())."<p>"; 
you can display the raw SOAP XML.

6) Add a second method that prints "Have a nice day!", "Have a brave day!", etc. In order to do this you need to change the server, the WSDL file and the client.
In the server: add the second method into the existing class.
In the WSDL file: create two more messages (for input/output) and a second operation.
In the client: have the client call one message after the other. Note: you can echo additional HTML code (eg <br>) in your client file in order to format the display of the output.