Simple NuSOAP Server

In the previous post, we examined the client side of NuSOAP. In this post, we examine a very simplistic approach to building a server. In this example, it is going to use a very basic set up, and will return only a string. No complex data will be returned, and it will be a quick look at how to create a NuSOAP server. The more complex approaches will come later.

Using the previous information in the post, we have a client that we can text the service on. Before I complete the webservice server, I always do some quick testing of the functionality before sending it to the web service. In this example, we will use one of the services built previously:
showPhrases – Phrases from Shakespeare plays that replace the names in the phrase with the passed in name/string

This webservice requires 2 items to be passed:
id – A number from 0 to 4 (In this example I only used 5 phrases)
name – A name or variable that can be used to replace the names in the phrases

The first thing we should always do, is map out the plan for this function.

This webservice will take the ID and the name, and then return the phrase that has been ID’d, with the personalization of the name. So the first thing we need is the phrases, then we need to set up a function to do this.

So with the phrases, I took 5 different Shakespeare phrases, and removed the names, and put in a placeholder value that is uniform throughout the phrases. These phrases are listed below:

$phrases = array(
	'O NnnnnnnnnN, NnnnnnnnnN! wherefore art thou NnnnnnnnnN?',
	'But NnnnnnnnnN, If you prick us, do we not bleed? if you tickle us, do we not laugh? if you poison us, do we not die? and if you wrong us, shall we not revenge?',
	'Will all great NnnnnnnnnN\'s ocean wash this blood clean from my hand? No, this my hand will rather the multitudinous seas incarnadine, making the green one red',
	'Love looks not with the eyes, but with the mind, NnnnnnnnnN, and therefore is winged Cupid painted blind',
	'Men at some time are masters of their fates: The fault, dear NnnnnnnnnN, is not in our stars, but in ourselves, that we are underlings',
);

Next we need to create the function for this. Since this series of posts are about the webservices and not general PHP security, logic, or structure, we will quickly pass over this.
1. We want to make sure that the ID is between 0 and 4.
2. We want to replace all the placeholder values with the passed in name
3. We want to format the response to the client that lets them know it is either a success or failure

So with this function, it could look something like this:

function showPhrases($id, $name){
	// Set up the phrases
	$phrases = array(
		'O NnnnnnnnnN, NnnnnnnnnN! wherefore art thou NnnnnnnnnN?',
		'But NnnnnnnnnN, If you prick us, do we not bleed? if you tickle us, do we not laugh? if you poison us, do we not die? and if you wrong us, shall we not revenge?',
		'Will all great NnnnnnnnnN\'s ocean wash this blood clean from my hand? No, this my hand will rather the multitudinous seas incarnadine, making the green one red',
		'Love looks not with the eyes, but with the mind, NnnnnnnnnN, and therefore is winged Cupid painted blind',
		'Men at some time are masters of their fates: The fault, dear NnnnnnnnnN, is not in our stars, but in ourselves, that we are underlings',
	);
	
	// place all validation code here
	if ( ($id < 0) || ($id > 4)  ){
		// return an error
		$fin_data['status'] = "Error!";
		$fin_data['phrase'] = "The ID was outside of the allowed range.";		
		return $fin_data;
	}
	
	// replace all the needles with the name
	$phrase = preg_replace("/NnnnnnnnnN/", $name, $phrases[$id]);

	$fin_data['status'] = "Success!";
	$fin_data['phrase'] = $phrase;

	return $fin_data;
}

We can do a quick test to make sure this works:

// Good call
$test1 = showPhrases(0, "HEY YOU GUYS!");
// Will return an error
$test2 = showPhrases(30, "Alexander the Great");

echo "<pre>";
print_r($test1);
print_r($test2);
echo "</pre>";

OK, we know the function works. In the real world, you would want to sanitize the string a little better and make sure there is no other attempts to grab data, or compromise your application. Now we can start to build the actual server.

We need to set up some basic stuff in the server, namely, we need to include the libraries, set the WSDL to the proper address, and register the new function. I have set this WSDL server at the following location:
http://www.hirdweb.com/webservice/20100707_server.php

$server = new soap_server();
// Create the WSDL 
$wsdl_addr = 'http://www.hirdweb.com/webservice/20100707_server.php';
// Set the name that will be displayed in the WSDL, and the namespace
$server->configureWSDL('HirdWeb Basic Webservice Example','HirdWeb Basic Webservice Example', $wsdl_addr);

One of the most important things to remember when creating WSDLs, either manually (or using Zend Studio’s tool), or by using a library such as NuSOAP, is that you need to start from the bottom and work your way up. The bottom of the WSDL will always be the most base, and working up it will get more complex.

In this example, we are using a pseudo-complex/simplistic structure. The service is returning an array, but a non-complex array that does not need much, other than strings. So we need to register the function with the server first, then move to the more complex items.

First, I like to set variables for registration, this way I know what needs to go where, and what it needs to call. It is basically in this vein:
register(
    Function Name / Name of service provided
    What needs to be passed in
    What is going to be passed back
    Namespace
    SOAP Action to do this
    RPC
    Encoded / Encoding
    Documentation on this service function
)
Translating that to code, and I have this:

// Set up all the items to register the function
$in = array(
	'id' => 'xsd:string',
	'name' => 'xsd:string',
);
$out = array('return' => 'tns:showPhrases');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showPhrases';
$doc = 'Shows a phrase from Shakespeare and replaces the name with the supplied name. ID is a number from 0 - 4';

$server->register('showPhrases', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc); 

Now close the service and exit so only the service is exposed.

$server->service($HTTP_RAW_POST_DATA);
exit; 

But, we are not completed. If you notice the $out variable, it is setting the returned values as an array set to
tns:showPhrases

Which means we have our first complex type. If we want to just return a phrase, then we could have just left it at
xsd:string
However, I have found that by doing that, it can leave an opening in understanding what is being returned. Has the service worked, it returned a phrase, so it must be correct, right? Maybe, not sure. I always find it a good practice to make sure you tell the clients whether or not the call was successful. It just cuts down on the possibility of returning bad data.

We now have to create a type that can be returned. The naming convention should mirror that of the function. In the function, we have two named array elements:
status
phrase

We need to create a complex type that defines these elements. Using the $server object, we can add a complex type, defined as “showPhrases”. This function is called in the WSDL class:
$server->wsdl->addComplexType();
The parameters for this function are (taken straight from the code):
* @param string $name
* @param string $typeClass (complexType|simpleType|attribute)
* @param string $phpType currently supported are array and struct (php assoc array)
* @param string $compositor (all|sequence|choice)
* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
* @param array $elements e.g. array ( name => array(name=>”,type=>”) )
* @param array $attrs e.g. array(array(‘ref’=>’SOAP-ENC:arrayType’,’wsdl:arrayType’=>’xsd:string[]’))
* @param string $arrayType as namespace:name (xsd:string)
* @see nusoap_xmlschema
* @access public

For our complex type, we need to use the name, complexType, struct, all, ” (or default), our array setup
We will use the defaults for any items after our array.

$server->wsdl->addComplexType('showPhrases','complexType','struct','all','',
    array(
        'status' => array('name' => 'status', 'type' => 'xsd:string'),
        'phrase' => array('name' => 'message', 'type' => 'xsd:string')
    )
);

So the entire service looks like this:

// Instantiate the server
$server = new soap_server();
// Create the WSDL 
$wsdl_addr = 'http://www.hirdweb.com/webservice/20100707_server.php';
$server->configureWSDL('HirdWeb Basic Webservice Example','HirdWeb Basic Webservice Example', $wsdl_addr);
$server->wsdl->addComplexType('showPhrases','complexType','struct','all','',
    array(
        'status' => array('name' => 'status', 'type' => 'xsd:string'),
        'phrase' => array('name' => 'message', 'type' => 'xsd:string')
    )
);
// Set up all the items to register the function
$in = array(
	'id' => 'xsd:string',
	'name' => 'xsd:string',
);
$out = array('return' => 'tns:showPhrases');
$namespace = 'uri:hirdwebservice';
$soapaction = 'uri:hirdwebservice/showPhrases';
$doc = 'Shows a phrase from Shakespeare and replaces the name with the supplied name. ID is a number from 0 - 4';
$server->register('showPhrases', $in, $out, $namespace, $soapaction, 'rpc', 'encoded', $doc); 
$server->service($HTTP_RAW_POST_DATA);
exit; 

And now the webservice server is ready to be tested using the client, which we created a sample previously.
Make sure that you update the WSDL to point to the server we created today.
The entire file for the server, and the function can be found at
http://www.hirdweb.com/webservice/20100707_server.txt

I created a test page that will show the results of the call:
http://www.hirdweb.com/webservice/20100707.php
The client makes 6 calls to the server, 0-5. It returns 5 good results, and 1 error.

Next we will examine two services provided by a webservice service. We will have the one we created today, and add a more complex type, the showTaxes service (which we saw briefly in the client example), and expand the status message with a little more information and provide a dynamic ability for error messages.

5 thoughts on “Simple NuSOAP Server”

  1. Thanks for this easy step-by-step example. I’m limited to PHP4 and NuSoap (along with your post) was the quickest to get a proof of concept idea up and running.

Comments are closed.