
Advanced PHP Programming
.pdf
408Chapter 16 RPC: Interacting with Remote Services
deserialized into native PHP types, using deserializeBody().When you executing it, you get this:
> php delayed-stockquote.php
Current price of IBM is 90.25
Rewriting system.load as a SOAP Service
A quick test of your new SOAP skills is to reimplement the XML-RPC system.load service as a SOAP service.
To begin, you define the SOAP service as a specialization of SOAP_Service. At a minimum, you are required to implement four functions:
n public static function getSOAPServiceNamespace(){}—Must return the
namespace of the service you are defining.
n public static function getSOAPServiceName() {}—Must return the name
of the service you are defining.
n public static function getSOAPServiceDescription()—Must return a string description of the service you are defining.
n public static function getWSDLURI() {}—Must return a URL that points to the WSDL file where the service is described.
In addition, you should define any methods that you will be calling.
Here is the class definition for the new SOAP SystemLoad implementation: require_once ‘SOAP/Server.php’;
class ServerHandler_SystemLoad implements SOAP_Service { public static function getSOAPServiceNamespace()
{return ‘http://example.org/SystemLoad/’; } public static function getSOAPServiceName()
{return ‘SystemLoadService’; }
public static function getSOAPServiceDescription()
{return ‘Return the one-minute load avergae.’; } public static function getWSDLURI()
{return ‘http://localhost/soap/tests/SystemLoad.wsdl’; }
public function SystemLoad()
{
$uptime = `uptime`;
if(preg_match(“/load averages?: ([\d.]+)/”, $uptime, $matches)) { return array( ‘Load’ => $matches[1]);
}
}
}

SOAP 409
Unlike in XML-RPC, your SOAP_Service methods receive their arguments as regular PHP variables.When a method returns, it only needs to return an array of the response message parameters.The namespaces you choose are arbitrary, but they are validated against the specified WSDL file, so they have to be internally consistent.
After the service is defined, you need to register it as you would with XML-RPC. In the following example, you create a new SOAP_Server, add the new service, and instruct the server instance to handle incoming requests:
$server = new SOAP_Server;
$service = new ServerHandler_System_Load;
$server->addService($service); $server->service(‘php://input’);
At this point you have a fully functional server, but you still lack the WSDL to allow clients to know how to address the server.Writing WSDL is not hard—just time-con- suming.The following WSDL file describes the new SOAP service:
<?xml version=’1.0’ encoding=’UTF-8’?> <definitions name=’SystemLoad’
targetNamespace=’http://example.org/SystemLoad/’ xmlns:tns=’http://example.org/SystemLoad/’ xmlns:soap=’http://schemas.xmlsoap.org/wsdl/soap/’ xmlns:xsd=’http://www.w3.org/2001/XMLSchema’ xmlns:soapenc=’http://schemas.xmlsoap.org/soap/encoding/’ xmlns:wsdl=’http://schemas.xmlsoap.org/wsdl/’ xmlns=’http://schemas.xmlsoap.org/wsdl/’>
<message name=’SystemLoadResponse’> <part name=’Load’ type=’xsd:float’/>
</message>
<message name=’SystemLoadRequest’/> <portType name=’SystemLoadPortType’>
<operation name=’SystemLoad’>
<input message=’tns:SystemLoadRequest’/> <output message=’tns:SystemLoadResponse’/>
</operation>
</portType>
<binding name=’SystemLoadBinding’ type=’tns:SystemLoadPortType’>
<soap:binding style=’rpc’ transport=’http://schemas.xmlsoap.org/soap/http’/> <operation name=’SystemLoad’>
<soap:operation soapAction=’http://example.org/SystemLoad/’/> <input>
<soap:body use=’encoded’ namespace=’http://example.org/SystemLoad/’ encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’/>
</input>
<output>

410 Chapter 16 RPC: Interacting with Remote Services
<soap:body use=’encoded’ namespace=’http://example.org/SystemLoad/’ encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’/>
</output>
</operation>
</binding>
<service name=’SystemLoadService’>
<documentation>System Load web service</documentation> <port name=’SystemLoadPort’
binding=’tns:SystemLoadBinding’>
<soap:address location=’http://localhost/soap/tests/SystemLoad.php’/>
</port>
</service>
</definitions>
Very little is new here. Notice that all the namespaces concur with what ServerHandler_SystemLoad says they are and that SystemLoad is prototyped to return a floating-point number named Load.
The client for this service is similar to the stock quote client:
include(“SOAP/Client.php”);
$url = “http://localhost/soap/tests/SystemLoad.wsdl”; $soapclient = new SOAP_Client($url, true);
$load = $soapclient->SystemLoad()->deserializeBody(); print “One minute system load is $load\n”;
Amazon Web Services and Complex Types
One of the major advantages of SOAP over XML-RPC is its support for user-defined types, described and validated via Schema.The PEAR SOAP implementation provides auto-translation of these user-defined types into PHP classes.
To illustrate, let’s look at performing an author search via Amazon.com’s Web services API. Amazon has made a concerted effort to make Web services work, and it allows full access to its search facilities via SOAP.To use the Amazon API, you need to register with the site as a developer.You can do this at www.amazon.com/gp/aws/landing.html.
Looking at the Amazon WSDL file http://soap.amazon.com/schemas2/AmazonWebServices.wsdl, you can see that the author searching operation is defined by the following WSDL block:
<operation name=”AuthorSearchRequest”>
<input message=”typens:AuthorSearchRequest” /> <output message=”typens:AuthorSearchResponse” />
</operation>

SOAP 411
In this block, the input and output message types are specified as follows:
<message name=”AuthorSearchRequest”>
<part name=”AuthorSearchRequest” type=”typens:AuthorRequest” />
</message>
and as follows:
<message name=”AuthorSearchResponse”>
<part name=”return” type=”typens:ProductInfo” />
</message>
These are both custom types that are described in Schema. Here is the typed definition for AuthorRequest:
<xsd:complexType name=”AuthorRequest”> <xsd:all>
<xsd:element name=”author” type=”xsd:string” /> <xsd:element name=”page” type=”xsd:string” /> <xsd:element name=”mode” type=”xsd:string” /> <xsd:element name=”tag” type=”xsd:string” /> <xsd:element name=”type” type=”xsd:string” /> <xsd:element name=”devtag” type=”xsd:string” />
<xsd:element name=”sort” type=”xsd:string” minOccurs=”0” /> <xsd:element name=”variations” type=”xsd:string” minOccurs=”0” /> <xsd:element name=”locale” type=”xsd:string” minOccurs=”0” />
</xsd:all>
</xsd:complexType>
To represent this type in PHP, you need to define a class that represents it and implements the interface SchemaTypeInfo.This consists of defining two operations:
n public static function getTypeName() {}—Returns the name of the type.
n public static function getTypeNamespace() {}—Returns the type’s namespace.
In this case, the class simply needs to be a container for the attributes. Because they are all base Schema types, no further effort is required.
Here is a wrapper class for AuthorRequest:
class AuthorRequest implements SchemaTypeInfo { public $author;
public $page; public $mode; public $tag; public $type; public $devtag;

412 Chapter 16 RPC: Interacting with Remote Services
public $sort; public $variations; public $locale;
public static function getTypeName() { return ‘AuthorRequest’;}
public static function getTypeNamespace() { return ‘http://soap.amazon.com’;}
}
To perform an author search, you first create a SOAP_Client proxy object from the Amazon WSDL file:
require_once ‘SOAP/Client.php’;
$url = ‘http://soap.amazon.com/schemas2/AmazonWebServices.wsdl’;
$client = new SOAP_Client($url, true);
Next, you create an AuthorRequest object and initialize it with search parameters, as follows:
$authreq = new AuthorRequest; $authreq->author = ‘schlossnagle’; $authreq->mode = ‘books’; $authreq->type = ‘lite’; $authreq->devtag = ‘DEVTAG’;
Amazon requires developers to register to use its services.When you do this, you get a developer ID that goes where DEVTAG is in the preceding code.
Next, you invoke the method and get the results:
$result = $client->AuthorSearchRequest($authreq)->deserializeBody();
The results are of type ProductInfo, which, unfortunately, is too long to implement here.You can quickly see the book titles of what Schlossnagles have written, though, using code like this:
foreach ($result->Details as $detail) {
print “Title: $detail->ProductName, ASIN: $detail->Asin\n”;
}
When you run this, you get the following:
Title: Advanced PHP Programming, ASIN: 0672325616
Generating Proxy Code
You can quickly write the code to generate dynamic proxy objects from WSDL, but this generation incurs a good deal of parsing that should be avoided when calling Web services repeatedly.The SOAP WSDL manager can generate actual PHP code for you so that you can invoke the calls directly, without reparsing the WSDL file.

SOAP and XML-RPC Compared |
413 |
To generate proxy code, you load the URL with WSDLManager::get() and call
generateProxyCode(), as shown here for the SystemLoad WSDL file:
require_once ‘SOAP/WSDL.php’;
$url = “http://localhost/soap/tests/SystemLoad.wsdl”;
$result = WSDLManager::get($url);
print $result->generateProxyCode();
Running this yields the following code:
class WebService_SystemLoadService_SystemLoadPort extends SOAP_Client
{
public function _ _construct()
{
parent::_ _construct(“http://localhost/soap/tests/SystemLoad.php”, 0);
}
function SystemLoad() {
return $this->call(“SystemLoad”,
$v = array(), array(‘namespace’=>’http://example.org/SystemLoad/’,
‘soapaction’=>’http://example.org/SystemLoad/’,
‘style’=>’rpc’,
‘use’=>’encoded’ ));
}
}
Now, instead of parsing the WSDL dynamically, you can simply call this class directly:
$service = new WebService_SystemLoadService_SystemLoadPort;
print $service->SystemLoad()->deserializeBody();
SOAP and XML-RPC Compared
The choice of which RPC protocol to implement—SOAP or XML-RPC—is often dictated by circumstance. If you are implementing a service that needs to interact with existing clients or servers, your choice has already been made for you. For example, implementing a SOAP interface to your Web log might be interesting, but might not provide integration with existing tools. If you want to query the Amazon or Google search APIs, the decision is not up to you:You will need to use SOAP.
If you are deploying a new service and you are free to choose which protocol to use, you need to consider the following:
nFrom an implementation standpoint, XML-RPC requires much less initial work than SOAP.
nXML-RPC generates smaller documents and is less expensive to parse than SOAP.

414 Chapter 16 RPC: Interacting with Remote Services
nSOAP allows for user-defined types via Schema.This allows both for more robust data validation and auto-type conversion from XML to PHP and vice versa. In
XML-RPC, all nontrivial data serialization must be performed manually.
nWSDL is cool. SOAP’s auto-discovery and proxy-generation abilities outstrip those of XML-RPC.
nSOAP has extensive support from IBM, Microsoft, and a host of powerful dotcoms that are interested in seeing the protocol succeed.This means that there has been and continues to be considerable time and money poured into improving SOAP’s interoperability and SOAP-related tools.
nSOAP is a generalized, highly extensible tool, whereas XML-RPC is a specialist protocol that has a relatively rigid definition.
I find the simplicity of XML-RPC very attractive when I need to implement an RPC that I control both ends of. If I control both endpoints of the protocol, the lack of sound auto-discovery and proxy generation does not affect me. If I am deploying a service that will be accessed by other parties, I think the wide industry support and excellent supporting tools for SOAP make it the best choice.
Further Reading
Interacting with remote services is a broad topic, and there is much more to it than is covered in this chapter. SOAP especially is an evolving standard that is deserving of a book of its own. Here are some additional resources for topics covered in this chapter, broken down by topic.
SOAP
The SOAP specification can be found at http://www.w3.org/TR/SOAP.
An excellent introduction to SOAP can be found at http://www.soapware.org/bdg. All of Shane Caraveo’s Web services talks at http://talks.php.net provide insight into succeeding with SOAP in PHP. Shane is the principal author of the PHP 5 SOAP
implementation.
XML-RPC
The XML-RPC specification can be found at http://www.xmlrpc.com/spec.
Dave Winer, author of XML-RPC, has a nice introduction to it at http://davenet. scripting.com/1998/07/14/xmlRpcForNewbies.

Further Reading |
415 |
Web Logging
The Blogger API specification is available at http://www.blogger.com/developers/ api/1_docs.
The MetaWeblog API specification is available at http://www.xmlrpc.com/ metaWeblogApi.
MovableType offers extensions to both the MetaWeblog and Blogger APIs. Its specification is available at http://www.movabletype.org/docs/ mtmanual_programmatic.html.
RSS is an open-XML format for syndicating content.The specification is available at http://blogs.law.harvard.edu/tech/rss.
The Serendipity Web logging system featured in the XML-RPC examples is available
at http://www.s9y.org.
Publicly Available Web Services
http://xmethods.net is devoted to developing Web services (primarily SOAP and WSDL). It offers a directory of freely available Web services and encourages interoperability testing.
Amazon has a free SOAP interface. Details are available at http://www.amazon.com/ gp/aws/landing.html.
Google also has a free SOAP search interface. Details are available at http://www. google.com/apis.


IV
Performance
17Application Benchmarks:Testing an Entire Application
18Profiling
19Synthetic Benchmarks: Evaluating Code Blocks and Functions