You've tried your hand at building mashups, experimented with a few RESTful Web services, maybe even started your own. Sure, you've got data sharing working. But how do you make your Web applications really talk to each other?

In this tutorial, I'll show you how to take your Web applications to the next level with SOAP, the "powerhouse of Web services", building high-end Web services with pure PHP.

SOAP 101

SOAP is a protocol for applications and servers to communicate with each other. Its primary use in PHP is exposing Web services and building Web service clients. As a protocol, it can exchange messages over HTTP/HTTPS, which helps it get around firewalls that would block other protocols (eg, Remote Procedure Call). As an application layer protocol, SOAP is also entirely platform independent — your PHP Web application can talk to a Java database server, for example, as long as they both speak SOAP.

SOAP messages are simply XML with some custom namespaces, so they're fully machine-readable. Libraries are available for every major language, and working with SOAP Web services is quick, easy and fast.

SOAP for PHP

Today we're going to take a look at one of these libraries, NuSOAP. PHP has a few options for SOAP, including a PHP 5 extension, a PEAR package, and an independent (but very popular) library called NuSOAP. NuSOAP is the simplest way to get up and running with SOAP, but we could just as well have used PEAR::SOAP or the extension, and all three are interoperable — you can consume PEAR::SOAP exposed services with NuSOAP and vice versa, and scripts using either can happily run alongside each other.

Getting started with NuSOAP

To begin using NuSOAP, first head to the project page and download a copy of libraries — I'm using version 0.7.2. All examples should be forwards-compatible, but API changes happen, so check your library version if you encounter any errors. Drop the contents of the archive into a folder on your Web server — using /soap under my docroot. The latest version is compatible with the SOAP extension, but if you experience "class already declared" errors just disable the SOAP extension or rename the class in nusoap.php.

Your first SOAP request!

We'll start with the SOAP client. SOAP works with servers and clients; servers expose services and clients consume them. We'll start with a demo of a simple Web service that takes an argument and returns an array — but with the power of SOAP, we get that array data locally, almost as if the client was the server, and SOAP takes care of all the information in between.

Fire up your favourite text editor and type out the following:

<?php
include("lib/nusoap.php");
$soap = new soapclient("http://127.0.0.1/soap/hello_world_server.php");

$output = $soap->call("hello_world", array("name" => "Josh"));
print_r($output);

Save it as hello_world.php in the folder you created earlier. It can be anywhere, as long as the lib/nusoap.php reference still points to your NuSOAP library. Do the same for the server:

<?php
include("lib/nusoap.php");
$srv = new soap_server();
$srv->register("hello_world");
function hello_world($name)
{
    return array("data"=>"Hello World, {$name}!");
}
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : "";
$srv->service($HTTP_RAW_POST_DATA);

Save this as hello_world_server.php in the same folder. If it can't be accessed at that URL in the client script (localhost/soap/...), change the reference in the client code as needed.

Then load up your Web browser, point it to the SOAP client — eg, http://localhost/soap/hello_world.php — and run the script. You should see the following:

Array
(
    [data] => Hello World, Josh!
)

That's perfectly normal print_r output — precisely what you would expect if you returned the array within the same PHP script. Except that our server script is separate, could be on a different server and could be running on a totally different platform — SOAP helps gets data from the server to the client as smoothly as possible.

The Server

Let's examine the server for a moment. Here's the code we used to build our server:

<?php
include("lib/nusoap.php");
$srv = new soap_server();

$srv->register("hello_world");
function hello_world($name)
{
    return array("data"=>"Hello World, {$name}!");
}

In this example, we first load up the NuSOAP library and register the service we want to expose, naming it "hello_world". We then define this service as a standard PHP function. At the moment, it does nothing but return a simple associative array, with the value containing an argument, $name. The client provides this argument from a totally separate PHP script and SOAP provides the glue to make sure it is passed in when the function is called.

HTTP is stateless, and our PHP script will be executed from the top down whenever a request is made, so each SOAP call (or other script execution) will be a new request. To check if we have a SOAP call (and what the SOAP client wants us to do), we have to scan each request for data. SOAP clients send POST requests, with XML data in the message body of the request, so we can fetch this raw POST data and pass it to the service() method of the soap_server class. Raw POST data is available in $HTTP_RAW_POST_DATA, but PHP won't set this unless it has a value, so we use a small hack to ensure it exists before passing it on to the SOAP server.

$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$srv->service($HTTP_RAW_POST_DATA);

We quickly get together the raw POST data, pass it to the SOAP library, and away we go.

The Client

The client uses the NuSOAP library, but only because we choose to — the server could use the PHP SOAP extension or PEAR::SOAP, and could be hosted anywhere. With the power of SOAP, we're going to take the PHP function on the server and talk to it through SOAP; we're also going to receive the result just like any other variable within our script. Have a look at the code for the client:

<?php
include("lib/nusoap.php");
$soap = new soapclient("http://127.0.0.1/soap/hello_world_server.php");

$output = $soap->call("hello_world", array("name" => "Josh"));
print_r($output);

The client is very basic — we first load up the library, then establish a connection to the SOAP server at the URL we've provided and call the "hello_world" service. For testing, we'll print_r the output. The second argument to the $soap->call() method is an array of parameters to be passed to the service. Notice we specify 'name' as the array key, the same as the $name argument on the server's function — this is not necessary as we aren't working with complex pre-defined services, however, it does hold importance when consuming slightly more elaborate SOAP services.

The service call returns a value which we then put into $output. If we check that print_r output earlier, it showed we had a perfectly good PHP associative array — [data] => Hello World, Josh! — just as our server's hello_world() function should have returned. In just a few lines of code, we've linked together two independent PHP scripts. Now your Web apps are really talking.

Behind the scenes: debugging SOAP

While you make high-level calls to the SOAP libraries, the NuSOAP library is actually busy generating and parsing XML request messages and passing them back and forth between server and client. You can easily examine the message body of your request and the server's response on the client side, using the request and response properties of the SOAP client class. These are invaluable in debugging, and will help you get a better understanding of SOAP internals, although you may never need it...

<?php
include("lib/nusoap.php");
$soap = new soapclient("http://127.0.0.1/soap/hello_world_server.php");

$output = $soap->call("hello_world", array("name" => "Josh"));
print_r($output);
echo '<pre>'.htmlspecialchars($soap->request).'</pre>';
echo '<pre>'.htmlspecialchars($soap->response).'</pre>';

This request will output something like the following:

POST /soap/hello_world_server.php HTTP/1.0
Host: 127.0.0.1
User-Agent: NuSOAP/0.7.2 (1.94)
Content-Type: text/xml; charset=ISO-8859-1
SOAPAction: ""
Content-Length: 511

<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope ...

Notice we're making a direct POST request and passing all the XML through. In a HTML form request, that XML would be replaced with key=value&key=value pairs, which are then translated into elements of $_POST — this is why we have to request the raw POST data to check for a SOAP request. The actual XML schema for SOAP messages isn't important, as the libraries take care of it for us, but read up on the SOAP specifications if you want to take a closer look.

Further SOAP

Now that you've built your first SOAP client, experiment with more complex APIs, or try consuming one of the many SOAP-based APIs available. If your applications already receive data from other sources, check if they offer SOAP — its use is very prevalent in enterprise situations, especially where SOA is encouraged. Finally, if you want to learn more about NuSOAP, one of the authors provides some handy resources.

Do you need help with PHP? Gain advice from Builder AU forums

Comments

1

Insane - 03/05/08

Excellent, nice post.

» Report offensive content

2

Pritam - 08/05/08

Hi.

Your post on web services using NuSOAP Utility is very nice one.

I tried out @my end but giving the problem as:


Warning: SoapClient::SoapClient(http://127.0.0.1:81/soap/hello_world_server.php) [function.SoapClient-SoapClient]: failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error in C:\wamp\www\soap\hello_world.php on line 3

Warning: SoapClient::SoapClient() [function.SoapClient-SoapClient]: I/O warning : failed to load external entity "http://127.0.0.1:81/soap/hello_world_server.php" in C:\wamp\www\soap\hello_world.php on line 3

Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from 'http://127.0.0.1:81/soap/hello_world_server.php' in C:\wamp\www\soap\hello_world.php:3 Stack trace: #0 C:\wamp\www\soap\hello_world.php(3): SoapClient->SoapClient('http://127.0.0....') #1 {main} thrown in C:\wamp\www\soap\hello_world.php on line 3

Could you please tell me why this is happening?

I am using WAMP server. Also my host port is 81(localhost:81) b'se I am using IIS on port 80. I have done all changes which are required as per your post. But still I am facing the problem.

Regards,
Pritam

» Report offensive content

3

Bakhtiyor - 20/05/08

Excellent explanation of the subject. Well done. Thnx a lot.

» Report offensive content

4

Umesh Kumar Sharma - 22/05/08

Hi pritam,
i was also stuck with this kind of problem.
Please replace SoapClient with Soap_Client it will help you sure.
do like this-

$client = new soap_client("any file path");

» Report offensive content

5

Brendan - 05/06/08

Thanks for this.
It helped me a lot.

An FYI for anyone using IIS and SSL, you need cURL enables in your php.ini. I ran into this problem.

» Report offensive content

6

T.Aravindhan - 28/06/08

To Powerfull PHP Editor

» Report offensive content

7

cornice london - 26/08/08

vwery interestuing site ! really good article

» Report offensive content

8

mike - 07/10/08

Hi, i test and run to my local server and it returns nothing...anyone can help me?? anyways, nice post.

» Report offensive content

9

Nadeera - 03/11/08

i found the issue use the following code

$soap = new soapclientNusoap("XXXXXX") insted of
$soap = new soapclient("XXXXXXX")

» Report offensive content

10

asdasda - 18/11/08

11

asdf - 18/11/08

12

Nichi - 04/02/09

I figured out why I was getting the "[function.SoapClient-SoapClient]: failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error" message.

I'm using XAMPP on Windows and I needed to disable "extension=php_soap.dll" in the php.ini file for nusoap to work. I'd be curious to know as to why that would fix it though.

» Report offensive content

13

Mayuresh - 17/04/09

It is ok to disable "extension=php_soap.dll" if i a am working with local server, but what if i am working with sharing host? how can i disable this exttension using .htaccess or using php code(ini_set)?

» Report offensive content

14

markus - 11/05/09

it's a name conflict with the soap extension, just rename the class soapclient to something else

» Report offensive content

Leave a comment

You must read and type the 6 chars within 0..9 and A..F

* indicates mandatory fields.

14

markus - 05/11/09

it's a name conflict with the soap extension, just rename the class soapclient to something else ... more

13

Mayuresh - 17/04/09

It is ok to disable "extension=php_soap.dll" if i a am working with local server, but what if i am working with ... more

12

Nichi - 02/04/09

I figured out why I was getting the "[function.SoapClient-SoapClient]: failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error" ... more

Log in


Sign up | Forgot your password?

  • Staff Aussies to pay more for Win 7

    If you are looking to make some money in these troubled times, perhaps importing copies of Windows 7 could be for you. Read more »

    -- posted by Staff

  • Staff Firefox: Greens want it, 3.5rc2 not up to par

    This week's roundup looks at the situation surrounding a campaign to change Outlook HTML renderer, a Greens MP wants to install Firefox but is restricted and all the photos from the iPhone 3GS launch. Read more »

    -- posted by Staff

  • Chris Duckett Microsoft misses the Outlook point

    Ask designers which mail program is the bane of their existence, and you'll find that Outlook tops the list. The reason why the most popular email reader is also the most painful is simple: it uses Word to render HTML emails. Read more »

    -- posted by Chris Duckett

What's on?