Well if you have followed the previous post on using NuSOAP to create an amazon web service then you might be interested in using NuSOAP to create a web service of your own (i.e. a server component rather than a client component). I decided to create one myself to allow me to create a .Net application to help me maintain my walks database.
As before, go get NuSOAP and download into a directory. Then create a file called “mywsdl.php” for example.
The first thing I did was to set a namespace for my web service. This makes my web service unique and identifiable. The namespace does not have to be a URL but if you make it a URL things can be a lot easier.
$namespace = "http://www.wackylabs.net/wsdl
Next we need to create the server object and start to program against it:
$server = new soap_server();
$server->debug_flag = false;
$server->wsdl->schemaTargetNamespace = $namespace;
Creating your data types
There are three main types of data you will be using. Built in types can be used without being declared. The other two are slightly more complicated, structures and arrays.
First lets look at an example structure:
'WalkId' => array('name' => 'WalkId',
'type' => 'xsd:int'),
'WalkTitle' => array('name' => 'WalkTitle',
'type' => 'xsd:string'),
'WalkDate' => array('name' => 'WalkDate',
'type' => 'xsd:date')
'WalkDescription' => array('name' => 'WalkDescription',
'type' => 'xsd:string')
This is quite a complicated function, and from the source code we see that the parameters are as follows:
- 1: name
- 2: typeClass (complexType|simpleType|attribute)
- 3: phpType: currently supported are array and struct (php assoc array)
- 4: compositor (all|sequence|choice)
- 5: restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
- 6: elements = array ( name = array(name=>”,type=>”) )
- 7: attrs = array(array(‘ref’ => “http://schemas.xmlsoap.org/soap/encoding/:arrayType”, “http://schemas.xmlsoap.org/wsdl/:arrayType” => “string”))
- 8: arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
The first is simply the name you want to define (in the context of the ‘targetNamespace’ defined above.
The next is the type. simpleType is usually based on another type with restrictions (e.g. a string with max length of 4 or some such other restriction), complexTypes usually have more than one subelement (as above).
The phpType, as specified is either array or struct.
The compositor is a way of defining how the subelements of the current element work, are they either all optional element, to be included in any order (all), optional but only to be allowed in the given order (sequence) or only one of them is allowed at any one time (choice).
The restrictionBase and attrs and arrayType we shall cover later when we talk about support for arrays.
The elements item is an array containing a list of subelement, each of which has a name and a type.
The above example defines a type called “Walk” which is effectively a struct, containing 4 fields, WalkId, WalkTitle, WalkDate and WalkDescription. It is a complex type and all elements can be included in any order. WalkId is a integer, WalkTitle and WalkDescription are strings and WalkDate is a date field.
What about list of walks
The next think you might want to do is return a list of walks matching some criteria (e.g. latest 10 walks). For this we use the array data type:
array('ref' => 'SOAP-ENC:arrayType',
'wsdl:arrayType' => 'tns:Walk')
Here the php type is array instead of struct. The compositor is blank and the restrictionBase is ‘SOAP-ENC:Array’. This tells the system that your complex type is based on the Array type defined within the soap-encoding namespace. The elements parameter is then a blank array and the attrs parameter is an array defining the type of the array and the parameter defines the type of the elements within the array (as you can see, these are usually the same except for the  part after the array definition.
Do some work!
Well so far we’ve defined the types of data (or some extra ones not already defined) that we want to pass in and out of your web service. Next we define the actual operation the web service will support.
$server->register('GetWalk', // method name
array('WalkId' => 'xsd:int'), // input parameters
array('return' => 'tns:Walk'), // output parameters
$namespace, // namespace
$namespace . '#GetWalk', // soapaction
'rpc', // style
'encoded', // use
'Get Specific Walk' // documentation
Here we define a method which will input a integer, defining the walk id and get passed back a Walk data struct (containing the id, title, description and date). We again define the namespace and I’ve set the action to the namespace + “#GetWalk” which is the method name.
We define a normal php function to actually do the work:
"WalkId" => $walkid,
"WalkTitle" => "Title of my long walk",
"WalkDate" => date("Y-m-d", time()),
"WalkDescription" => "Really long walk description"
Dates should be in ISO international format CCYY-MM-DD HH:MM:SS with an optional timezone attached at the end (or shorted as in this example).
Finally, we pass whatever data the php page receives into the soap processor and see what happens:
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA'])
? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
If you now browse to your completed webpage you should find you are presented with a nice page listing the operations supported and the parameters, as well as a link to the wsdl which can be used with code generation tools (such as wsdl.exe with .Net or the java equivalent) to generate client code for your wsdl.
Comments welcome as usual.