PHP: Exposing web services - Part 1

May 6, 2010 by PHP  

Web services are useful for a number of things, e.g. we can provide companies with data without needing to give them direct access to our databases.

One of the most important uses (in my opinion) is the interoperability it provides, which allows different platforms, devices etc to interact with each other.

In this post we're going to expose a web service in PHP using NuSphere's Soap library, which has been in development since 2002 - which like the name suggests relies on the SOAP protocol (XML based) and consume it in a C# application using WCF.

First of all you will need to include the library and instantiate a new soap_server object, like this:

include "lib/nusoap.php";

$namespace = "http://www.cstruter.com";
$server = new soap_server();
$server->soap_defencoding = 'UTF-8';
$server->configureWSDL("TestService", $namespace);
$server->wsdl->schemaTargetNamespace = $namespace;

It's quite important to set our soap_defencoding property to UTF-8, since this is the default encoding required by the WCF (Windows Communication Foundation)

We also need to register the functions we wish to expose against our soap_server object, like so:

$server->register('test', // function name
				array("name"=>"xsd:string"),  // parameters
				array('return'=>'xsd:string'), // return value type
				$namespace);

function test($name)
{
	return "Hello $name";
}

Once we're done, we tell our object to handle actions sent to our script like this:

$POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA']) 
				? $GLOBALS['HTTP_RAW_POST_DATA'] 
					: @file_get_contents("php://input");

$server->service($POST_DATA);

On the C# side (using Visual Studio 2008/10), right click on your project and click on Add Service Reference.


Notice the querystring "?wsdl" circled in the image above, passed along with the url to the reference, this tells the NuSoap library to output WSDL (Web Services Description Language) - which provides C# with all the information it needs to consume the web service (something I will discuss in the next part of this post).

Using the web service in C# looks something like this:

using System;
using cstruter.com.Service; // Namespace defined in the Add Service Reference dialog

namespace cstruter.com
{
    class Program
    {
        static void Main(string[] args)
        {
            TestServicePortTypeClient TestService = new TestServicePortTypeClient();
            String value = TestService.test("Jurgens");
            Console.WriteLine(value); // Outputs Hello Jurgens
        }
    }
}

Now thats pretty much the basics to get us up and running, but what If we want to do a bit more? Like passing/returning objects from/to the web service, we need to define types, like this:

$server->wsdl->addComplexType(
    'post',				// Name of the object
    'complexType',		// Object Type (Why? Since we've got an addSimpleType method?)
    'struct',			// Struct /Array (Multiple objects)
    'all',				// Composition
    '',					// Restriction Namespace
    array(
        'postID' => array('name' => 'postID', 'type' => 'xsd:int'),
        'Title' => array('name' => 'Title', 'type' => 'xsd:string'),
		'Body' => array('Body' => 'Body', 'type' => 'xsd:string')
    ) // Structure Defintion
);

Using the new defined object is very straightforward e.g. "tns:post":

$server->register('test2', 
					array("name"=>"tns:post"), 
					array('return'=>'xsd:string'), 
					$namespace);

function test2($value)
{
	return print_r($value, true);
}

On the C# side of things you will notice an auto-generated version of the object (post) we defined in our PHP script becomes available:

TestServicePortTypeClient TestService = new TestServicePortTypeClient();
post p = new post
{
    postID = 1,
    Title = "Test 1 2 3",
    Body = "Some test"
};

String value = TestService.test2(p);
Console.WriteLine(value);

If we wish to pass an array of objects e.g. post[], we need to add another complexType.

$server->wsdl->addComplexType(
	'posts', 			// Name of the object
	'complexType',		
	'array',			// Array since we're passing a set of objects
	'', 
	'SOAP-ENC:Array',
	array(),
	array(
		array('ref' => 'SOAP-ENC:arrayType', 'wsdl:arrayType' => 'tns:post[]')
	),
	'tns:post' // Child object
);

In the next snippet we pass an array of posts to the web service:

$server->register('test3', 
					array(), // Blank array if we don't have any parameters.
					array('return'=>'tns:posts'), // The array of objects.
					$namespace);

function test3()
{
	return array(array('postID'=>1, 
						'Title'=>'test 1', 
						'Body'=>'abc abc abc'), 
				 array('postID'=>2, 
						'Title'=>'test 2', 
						'Body'=>'123 123 123')
	);
}

And this is how we retrieve the array via C#:

TestServicePortTypeClient TestService = new TestServicePortTypeClient();
post[] ps = TestService.test3();
foreach (post p in ps)
{
    Console.WriteLine(String.Concat(p.postID, ":", p.Title, ":", p.Body));
}

In conclusion I feel its quite a nice, simple to use library written by the guys at NuSphere. There is quite a bit more to this library, but these examples should get you on your way.

In the next part of this post we're going to have a look at the SoapServer php extension.


Leave a Comment


cannot access the post object from the webservice September 14, 2013 by Gian

i cannot seem to access the object name post. I import the wsdl webservice. and i can access the simple function that sends a string and returns a string. Am using Visual Studio 2012.Great post.

February 12, 2011 by Anonymous

Thanks.

mr January 14, 2011 by george

thanks for the excellent explanation. :)


    Related Posts

    PHP: Exposing web services - Part 2

    December 11, 2010