Creating and Consuming Web Services With PHP
by Jean-Luc David
March 24, 2004
Web services are widely supported by all the major technology
vendors and organizations including IBM, Microsoft, Sun Microsystems
and the W3C. Millions of dollars have been invested in the development
of this technology. Web services allow you to share data across many
platforms and hardware configurations. For example, you can create a
Java web service and someone else can consume it using a .NET client
without having to learn one line of Java code.
There are many available scripting languages that support web
services. PHP is one such language, with a powerful arsenal of open
source functions and tools.
In this article, we will compare and contrast three methods of
consuming and producing web services: XML-RPC, SOAP and REST. This
article assumes that the reader has a basic knowledge of both web
service specifications and PHP. You must also have access to a
PHP-enabled web server to implement our code samples. If you require
more information, please refer to the resource section at the end of
the article.
XML-RPC
Remote Procedure Calls are used to establish and facilitate
transactions between two remote systems. Example of popular RPC
implementations include DCOM and CORBA. XML-RPC is an established
implementation of RPC that allows you to transport XML encoded data
between two servers using HTTP. In the following examples, we will use
an implementation of XML-RPC originally developed by Edd Dumbill (
http://xmlrpc.usefulinc.com/php.html).
To enable PHP XML-RPC functionality, you must download the XML-RPC
toolkit available at the following link: http://sourceforge.net/project/showfiles.php?group_id=34455
Creating an XML-RPC Web service
The main include files we will be using are xmlrpc.inc (the base class
library) and xmlrpcs.inc (the server class library). Here is how you
implement a simple XML-RPC server using PHP. First, we bring in both
the client and server libraries using include statements:
<?
include("xmlrpc.inc");
include("xmlrpcs.inc");
Then we define a new function called onttax. This function
will be the backbone of a web service that will calculate the 15%
Federal & Provincial sales tax for Ontario Canada based on a
dollar amount. A parameter, which corresponds to the dollar amount, is
passed into the function. The parameter is then converted to a scalar
variable. Once the calculation is completed, a response is created
(using the xmlrpcresp class) returning the value of the sales tax:
function onttax($par){
$amount=$par->getParam(0);
$amountval=$amount->scalarval();
$taxcalc=$amountval*.15;
return new xmlrpcresp(new xmlrpcval($taxcalc, "string"));
}
Then we can instantiate the server and serialize our onttax
function back to the caller.
$server=new xmlrpc_server(array("taxcalc.onttax"=>array("function"=>"onttax")));
?>
Consuming an XML-RPC Web service
Now that we have built a server, the next step is to develop a client
to call our web service. First, we need to bring in the base class
library and define a scalar variable called $amount and
assign it a value of $15.00:
<?
include("xmlrpc.inc");
$amount="15.00";
Then we instantiate our XML-RPC client which will connect to our new
server. The value of $amount is passed to the server
using the xmlrpcmsg object:
$format=new xmlrpcmsg('taxcalc.onttax',
array(new xmlrpcval($amount, "double")));
$client=new xmlrpc_client("/xmlrpc-server.php", "localhost", 80);
Once a connection is made, the request is sent to the server. The
response, which corresponds to the sales tax calculation, is then
passed along to $value. $value is then converted to a scalar variable
and returned to the user. Of course there is no need to stop there,
you can easily create a custom client which manipulates the data
returned from the server:
$request=$client->send($format);
$value=$request->value();
print $value->scalarval();
?>
XML-RPC is a simple, effective method of transmitting XML data. It has
been implemented in projects such as FreeNET, O'Reilly's Meerkat,
Syndic8, the Google API and numerous other applications. For more
information about XML-RPC, be sure to visit the official website at http://www.xmlrpc.com or read Programming Web
Services with XML-RPC.
NuSOAP and PHP
SOAP is designed as an XML wrapper for web services requests and
responses. SOAP's strength lies in its use of namespaces, XML Schema
datatypes, and its flexibility with regard to transports. The
disadvantage of SOAP is the fact that the specs and implementation is
more complex, especially when you compare it to the simple XML-RPC
approach. SOAP is the bread and butter of corporate web service
developers. It has been deeply integrated into Microsoft .NET and IBM
WebSphere. Based on its popularity, Google and Amazon.com have both
created SOAP-based Web services.
NuSOAP is a powerful API developed for the PHP platform. It allows you
to build both Web service clients and servers. One of the great
features of NuSOAP is the built-in WSDL support. Installing the API is
a snap: all you need is a PHP enabled server. The required libraries
are contained in a file called nusoap.php. You can download both the
toolkit and the documentation at this link: http://deitrich.ganx4.com/nusoap/.
Creating a NuSOAP Client using PHP
Creating a SOAP client with the library is very simple. To
illustrate how the SOAP client works, I've decided to call a web
service from XMethods.net (http://www.xmethods.net). This
website has a wide range of useful web services you can access
freely. In our particular example, we will be querying the currency
converter Web service to find out the exchange rate between Canadian
and American dollars.
Here is a breakdown of the PHP code needed to access the currency
converter. First, we need to bring in the library
file. The require_once command will make sure the
functions are only added once into our script.
<?
require_once('nusoap.php');
Next step we will define where the WSDL is located and create an
instance of the soapclient class to access the web
service. WSDL stands for Web Services Description Language, an XML
file which describes the interface of a web service:
$wsdl="http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl";
$client=new soapclient($wsdl, 'wsdl');
We then send in two parameters through the SOAP client, the two
countries that we want to compare to get the currency exchange
rate. We then call the getRate function and pass our
parameters to get a response from the remote server. The result is
then displayed to the user:
$param=array(
'country1'=>'usa',
'country2'=>'canada'
);
echo $client->call('getRate', $param);
?>
To help better explain the process happening during SOAP
communication, here is a sample of packet data transmitted from client
to server and vice versa. First, our web client requests the WSDL file
from the XMethods server:
GET /sd/2001/CurrencyExchangeService.wsdl HTTP/1.0
Host: www.xmethods.net
The WSDL file is then passed into our SOAP client. It contains
definitions for all the methods available from the
CurrencyExchangeService Web service:
HTTP/1.1 200 OK
Date: Tue, 10 Feb 2004 11:45:24 GMT
Server: Apache/1.3.26 (Unix) Enhydra-Director/3 PHP/4.0.6 DAV/1.0.3 AuthNuSphere/1.0.0
Last-Modified: Tue, 23 Oct 2001 18:10:37 GMT
ETag: "1981a8-654-3bd5b29d"
Accept-Ranges: bytes
Content-Length: 1620
Connection: close
Content-Type: text/xml
<?xml version="1.0"?>
<definitions name="CurrencyExchangeService"
targetNamespace="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl"
xmlns:tns="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="getRateRequest">
<part name="country1" type="xsd:string"/>
<part name="country2" type="xsd:string"/>
</message>
<message name="getRateResponse">
<part name="Result" type="xsd:float"/>
</message>
<portType name="CurrencyExchangePortType">
<operation name="getRate">
<input message="tns:getRateRequest" />
<output message="tns:getRateResponse" />
</operation>
</portType>
<binding name="CurrencyExchangeBinding" type="tns:CurrencyExchangePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getRate">
<soap:operation soapAction=""/>
<input >
<soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="CurrencyExchangeService">
<documentation>Returns the exchange rate between the two currencies</documentation>
<port name="CurrencyExchangePort" binding="tns:CurrencyExchangeBinding">
<soap:address location="http://services.xmethods.net:80/soap"/>
</port>
</service>
</definitions>
Next step, our client contacts the server requesting the conversion
rate using the getRate method. The parameters are sent according to
the Web service specifications:
POST /soap HTTP/1.0
User-Agent: NuSOAP v0.6
Host: services.xmethods.net
Content-Type: text/xml
Content-Length: 622
SOAPAction: ""
<?xml version="1.0"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:si="http://soapinterop.org/xsd"
xmlns:galactivism="urn:xmethods-CurrencyExchange">
<SOAP-ENV:Body>
<galactivism:getRate>
<country1 xsi:type="xsd:string">usa</country1>
<country2 xsi:type="xsd:string">canada</country2>
</galactivism:getRate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
[1] [2] Next