<<

. 88
( 132 .)



>>


Next comes the meat of the SOAP message ” a call to a function, in this case.
The name of the function you™re calling is the name of the element that calls it. A
namespace identifier ” traditionally ns1 ” precedes the function name, like this:

<ns1:getInseam
xmlns:ns1=”urn:referenceToWebService”
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
522 Part IV: Not So Simple Applications

What™s all that other stuff? Well, the namespace definition states where the func-
tion getInseam() can be found on the network. The SOAP-ENV:encodingStyle
value further standardizes the way in which simple and complex data types are pre-
sented on each side of the SOAP transaction.
Next comes the question of whose inseam measurement you want to retrieve.
This specifier should be presented to the function as an argument, which is to say
that in a traditional (intra-program) call to the function the syntax looks something
like this:

GetInseam(“Joe Bloggs”)

In SOAP you™re obliged to do things a little differently. Remember that you are
already inside a getInseam element, which means you have already made clear
that getInseam is the function you™re calling. You need to specify the argument
now. Logically enough, you do that with an element whose name matches the argu-
ment name, as specified in the remote class:

<person xsi:type=”xsd:string”>Joe Bloggs</zipcode>

With that done, you close out the getInseam element and the Body element, as
well:

</ns1:getInseam>
</SOAP-ENV:Body>

How does all this look in practice? The next section takes a look at a request/
response pair in which a call to getInseam() is made and replied to.

A typical request/response pair
A SOAP transaction consists of a request and a response, similar in lots of ways to
the request and response that are made when you order up a Web page with your
browser. Remember, SOAP transmissions are nothing more than passages of text,
marked up with XML in such a way that they serve special SOAP purposes.

THE REQUEST
Here™s a complete request:

<?xml version=™1.0™ encoding=™UTF-8™?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>
<SOAP-ENV:Body>
<ns1:getInseam
Chapter 16: SOAP 523

xmlns:ns1=”urn:referenceToWebService”
SOAP-
ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
<person xsi:type=”xsd:string”>Joe Bloggs</person>
</ns1:getInseam>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

A request, at its simplest, is just a Body element inside an Envelope element. You
can make things more complicated if you want ” the specification allows for, among
other things, a supplementary Header element that describes the relationship
among several SOAP messages or that describes how the message should be routed.

THE RESPONSE
Responses, in terms of format, bear a close resemblance to requests. They have
exactly the same envelope formats, and the body is different only in terms of the
name given to the element being sent. Usually, that™s the same as the element name
specified in the request, with Response appended.
Here™s a complete response to match your earlier request:

<?xml version=™1.0™ encoding=™UTF-8™?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>
<SOAP-ENV:Body>
<ns1:getInseamResponse
xmlns:ns1=”urn:referenceToWebService”
SOAP-
ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
<return xsi:type=”xsd:float”>34.0</return>
</ns1:getInseamResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Not too complicated, right? Joe Bloggs has an inseam measurement of 34. That™s
probably 34 inches. However, could Joe be a child with a 34-centimeter inseam?
This response gives us no way to tell.
To encode complex data structures into SOAP messages (both requests and
responses), you have to dig a bit deeper into the specification. The next section
takes a look at how to encode an array into a SOAP message.

COMPLEX DATA TYPES
Complex data types are multipart data types. An array is an example of a complex
data type in which the members are accessed by number. A struct, as those of you
524 Part IV: Not So Simple Applications

who code in C know, is an “associative array,” in which the array elements are
accessed by name rather than by number.
In the case of the inseam-returning Web service, it would be handy to know
what unit applies to the floating-point number that comes back in response to a
request. You can modify the contents of the Body element to hold this information
in a struct.
The struct defined here contains two elements: the value (the floating-point
value) and the unit (the string inches, centimeters, or whatever).

<return xmlns:ns1=”urn:referenceToWebService”
xsi:type=”ns1:inseamInfo”>
<unit xsi:type=”xsd:string”>inch</unit>
<value xsi:type=”xsd:double”>34.0</value>
</return>

In this mode of using SOAP, the Web service referred to defines a struct called
inseamInfo, which is comprised of a string called unit and a float called value.
By stating in the opening return tag that the return value is of type inseamInfo,
you make it legal to refer to these sub-elements.
There™s a lot more to do with the SOAP specification, and not all of it obscure.
Some of the more interesting and useful bits have to do with how errors and other
exceptional conditions are noted via SOAP, while others have to do with how to
describe other compound data types in SOAP messages. Such aspects of the specifi-
cation are beyond the scope of this chapter, but are certainly worth studying.


There™s lots of information on SOAP at the World Wide Web Consortium
site, including an overview (http://www.w3schools.com/soap/
soap_intro.asp) and a tutorial (http://www.w3schools.com/soap/
default.asp).




Code Overview
Key to any successful career in software design is the ability to freely make use of
the work of other people. The open-source movement is all about this practice, and,
thankfully, a considerable amount of software is available for the taking. NuSphere
Corporation ” makers of PHPEd, a PHP development environment ” have developed
a set of classes called SOAPx4, which has since been modified and renamed
NuSOAP. It™s a remarkably capable SOAP suite, doing pretty much all the heavy lift-
ing for you. If you™re using a PHP development environment (such as NuSphere™s
PHPEd version 3 or later) you™ll probably find it even easier to work with NuSOAP.
You can add your own modules ” such as new releases of PHP ” to your environ-
ment after you set it up initially.
Chapter 16: SOAP 525


The best place to begin the process of getting NuSOAP is on the Web site
of Dietrich Ayala (http://dietrich.ganx4.com/nusoap/). His site
includes links to the latest version of NuSOAP, as well as links to documenta-
tion, mailing lists, and other resources for developers and architects.



The essence of NuSOAP
NuSOAP is a series of classes. You copy the downloaded files (most of them .php
files) to your include directory and then make reference to them in your own PHP
classes. The NuSOAP classes take care of such work as creating SOAP client and
server objects and managing the transmission of SOAP messages among those
objects. The NuSOAP classes even take care of something we discussed earlier in
this chapter: the encoding of values into properly structured XML.
For the most part, you can think of the NuSOAP classes as black boxes. You just
stick the PHP files in your include directory and then cease worrying about them.
All you have to do is be aware, as you™re writing PHP programs that you want to
act as Web-service providers or consumers, that you have some new classes avail-
able to you.
Suppose you want to build a server. In other words, you want to make a PHP
function available as a Web service. Once you™ve added the required include state-
ment (as follows) you have a four-step process ahead of you.

require_once(˜nusoap.php™);

1. Create a server object. All you need to do is set a variable equal to a
soap_server object (soap_server being one of the classes made avail-
able by your inclusion of NuSOAP). It™s easy:
$server = new soap_server;

2. Register one of your local functions with that new soap_server object.
Again, no problem. You simply invoke the register() function of the
soap_server object, specifying one of your local functions as the sole
argument. The complete syntax looks like this:
$server->register(˜getInseam™);

3. Define a function called getInseam(). This can contain whatever code
you want. Presumably, in this case, it accesses a database to retrieve a
named party™s inseam measurement and then returns a value and unit.
The skeleton of the function looks something like this:
function getInseam($name) {
// Function code...
}
526 Part IV: Not So Simple Applications

4. Tune the soap_server object in to the HTTP requests it™s meant to moni-
tor and enable it to respond to them. You do this with a standard piece of
code that rarely varies across NuSOAP applications:
$server->service($HTTP_RAW_POST_DATA);

Those are the key elements of a SOAP server as implemented under NuSOAP.
What, then, about the client that speaks to this service? It™s even simpler.
NuSOAP clients have to include the nusoap.php file as well. Once that™s done,
they need only to instantiate a soapclient object (the soapclient object, again,
being part of the NuSOAP collection) with the URL of the service to be called as an
argument. If you had a service called getInseam() on http://www.wiley.com
(there isn™t one, by the way), you could do this to create a SOAP client to call it:

$soapclient = new soapclient(˜http://www.wiley.com/getInseam.php™);

Then you could send a call to the server via that client, like this:

write( $soapclient->call(˜getInseam™,array(˜name™=>™Joe Bloggs™)));

Pretty cool, eh? The arguments are sent as an array that enables you to match
sent values to expected values as you like.

A simple NuSOAP service call
Now we take a quick look at a “Hello, user” program as written with the help of the
NuSOAP classes. Really you see two programs here: a client and a server. The server
exposes a simple routine that takes in a string (the user™s name) and returns a string
made up of the word Hello and the provided name followed by a period. In other
words, if you send the service Ralph as an argument, the service says, Hello,
Ralph.
First you need a server. The server has the same name as the service you want to
expose, so in this case name it hello.php. Its full contents are as follows:

require_once(˜nusoap.php™);

$server = new soap_server;

$server->register(˜hello™);

function hello ($name){
return “Hello $name.”;
}

$server->service($HTTP_RAW_POST_DATA);
Chapter 16: SOAP 527

Not complicated, really. It™s just a matter of registering an otherwise ordinary
function with a special server object and then setting that server to deal with HTTP
activity.
Every server needs a client. The client file, in this case, can be called anything
and can reside anywhere the server can be accessed via HTTP.

require_once(˜nusoap.php™);

$soapclient = new soapclient(˜http://yourdomain.com/hello.php™);

write($soapclient->call(˜hello™,array(˜name™=>™Ralph™)));

Pretty simple, really. You just bind your client to the service (this example
assumes you know exactly where it is and what it™s called) and call that client as
you need values from it.
The glory of NuSOAP is its simplicity. There™s more to it than we™ve just dis-
cussed ” you will see some more complexity as the chapter continues ” but there™s
no doubt that NuSOAP makes it unbelievably easy to incorporate SOAP client and
server capability into PHP programs. It can be said that, other than for educational
reasons, there™s never a reason to write your own SOAP client and server classes
anymore. You™d be reinventing an already highly refined wheel.



Determining the Goals
of the Application
It™s time to have a look at SOAP messaging under PHP, and at some of the ways you
can communicate with publicly accessible Web services via SOAP. The rest of this
chapter focuses on an application that requests information from different sources,

<<

. 88
( 132 .)



>>