Developing Web Services Using PHP
Developing Web Services Using PHP
A web service consists of a server to serve requests to the web service and a client to invoke
methods on the web service. The PHP class library provides the SOAP extension to develop
SOAP servers and clients and the XML-RPC extension to create XML-RPC servers and clients.
Before I delve further into developing web services with PHP, I shall briefly discuss web
services.
A web service is a software system designed for interoperable interaction over a network. A web
service is defined with a WSDL (Web Services Description Language) document, and other
systems interact with the web service using SOAP messages, transferred using HTTP with an
XML serialization. A web service is an abstract resource that provides a set of functions and is
implemented by an agent, which sends and receives messages. A provider entity provides the
functionality of a web service with a provider agent and a requester entity uses the web service
functionality with a requester agent. Web services implement various technologies, some of
which are XML, SOAP, and WSDL. XML is a standard format for data exchange. Web service
requests and responses are sent as XML messages. The elements and attributes that may be
specified in an XML document are specified in an XML Schema. SOAP provides a standard
framework for packaging and exchanging XML messages. WSDL is an XML document in the
http://schemas.xmlsoap.org/wsdl/ namespace for describing a web service as a set of endpoints
operating on messages. A WSDL document specifies the operations (methods) provided by a
web service and the format of the XML messages.
The SOAP and XML-RPC extensions are packaged with the PHP 5 installation. The SOAP
extension and the XML-RPC extension are not enabled by default in a PHP installation. To
enable the SOAP and XML-RPC extensions add the following extension directives in the
php.ini configuration file.
extension=php_xmlrpc.dll
extension=php_soap.dll
Restart the Apache 2 server to activate the SOAP and XML-RPC extensions. The SOAP
extension supports subsets of the SOAP 1.1, SOAP 1.2, and WSDL 1.1 specifications.
After activating the SOAP extension in the PHP configuration file, a SOAP server and a SOAP
client may be created using the SOAP PHP class library. A SOAP server serves web service
requests and a SOAP client invokes methods on the SOAP web service. The SOAP library
provides various functions for creating a SOAP server and a SOAP client. Some of the
commonly used SOAP functions are discussed in Table 1.
Table 1. SOAP functions
Method Description
SoapClient->__soapCall( string
function_name, array arguments [, array
Invokes a SOAP function.
options [, mixed input_headers [, array
&output_headers]]] )
Before we create a SOAP server we need to create a WSDL document defining the web service.
The WSDL document defines the operations that the web service provides. I will create an
example web service that provides an operation getCatalogEntry, which returns a catalog entry
for a catalog ID. A WSDL is an XML document in the http://schemas.xmlsoap.org/wsdl/
namespace. Some of the elements of a WSDL document are discussed in Table 2.
Element Description
Specifies data type definitions for the messages exchanged by the web service. XML
types
Schema is the recommended type system.
Defines the data being transmitted. A message consists of one or more parts. A part is
message
associated with a type.
portType Defines a set of operations and the input-output messages for each operation.
An action (method) supported by the service. Each operation consists of input and
operation
output messages.
Defines message format and protocol details for operations and messages for a
binding
particular portType.
Next, create a WSDL document for the example web service. The example WSDL document,
catalog.wsdl, defines message elements getCatalogRequest and getCatalogResponse for
the request and response messages. In the WSDL document define a portType,
CatalogPortType, for the getCatalogEntry operation that returns a catalog entry as a HTML
string for a string catalogId. Define a binding, CatalogBinding, for the getCatalogEntry
operation and the input output messages. The soap:binding element specifies that the binding is
bound to the SOAP protocol format. The soap:operation element specifies information for the
operation. The soap:body element specifies how the message parts appear inside the SOAP
Body element. Define a service CatalogService that consists of a port, CatalogPort, which is
associated with the CatalogBinding binding. The soap:address element specifies the URI of
an address. The catalog.wsdl WSDL document is listed below.
<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='Catalog'
targetNamespace='http://example.org/catalog'
xmlns:tns=' http://example.org/catalog '
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='getCatalogRequest'>
<part name='catalogId' type='xsd:string'/>
</message>
<message name='getCatalogResponse'>
<part name='Result' type='xsd:string'/>
</message>
<portType name='CatalogPortType'>
<operation name='getCatalogEntry'>
<input message='tns:getCatalogRequest'/>
<output message='tns:getCatalogResponse'/>
</operation>
</portType>
<service name='CatalogService'>
<port name='CatalogPort' binding=
'CatalogBinding'>
<soap:address location='http://localhost/
soap-server.php'/>
</port>
</service>
</definitions>
Copy the catalog.wsdl document to the C:\Apache2\htdocs directory, the directory in which PHP
scripts are run. Create a PHP script, soap-server.php, to define the operations provided by the
CatalogService web service. In the soap-server.php script define a function
getCatalogEntry() that takes a catalogId as an argument and returns a string consisting of an
HTML document. The HTML document string returned comprises of the catalog entry for the
specified catalogId.
function getCatalogEntry($catalogId) {
if($catalogId=='catalog1')
return "<HTML> … </HTML>";
elseif ($catalogId='catalog2')
return "<HTML>…</HTML>";
The WSDL cache is enabled by default. Disable the WSDL cache by setting the
soap.wsdl_cache_enabled configuration option to 0.
ini_set("soap.wsdl_cache_enabled", "0");
Add the getCatalogEntry function to the SoapServer object using the addFunction()
method. The SOAP web service provides the getCatalogEntry operation.
$server->addFunction("getCatalogEntry");
$server->handle();
<?php
function getCatalogEntry($catalogId) {
if($catalogId=='catalog1')
return "<HTML>
<HEAD>
<TITLE>Catalog</TITLE>
</HEAD
<BODY>
<p> </p>
<table border>
<tr><th>CatalogId</th>
<th>Journal</th><th>Section
</th><th>Edition</th><th>
Title</th><th>Author</th>
</tr><tr><td>catalog1</td>
<td>IBM developerWorks</td><td>
XML</td><td>October 2005</td>
<td>JAXP validation</td>
<td>Brett McLaughlin</td></tr>
</table>
</BODY>
</HTML>";
elseif ($catalogId='catalog2')
return "<HTML>
<HEAD>
<TITLE>Catalog</TITLE>
</HEAD
<BODY>
<p> </p>
<table border>
<tr><th>CatalogId</th><th>
Journal</th><th>Section</th>
<th>Edition</th><th>Title
</th><th>Author
</th></tr><tr><td>catalog1
</td><td>IBM developerWorks</td>
<td>XML</td><td>July 2006</td>
<td>The Java XPath API
</td><td>Elliotte Harold</td>
</tr>
</table>
</BODY>
</HTML>";
}
ini_set("soap.wsdl_cache_enabled", "0");
$server = new SoapServer("catalog.wsdl");
$server->addFunction("getCatalogEntry");
$server->handle();
?>
In the next section, I will create a SOAP client to send a request to the SOAP server.
Create a PHP script, soap-client.php, in the C:\Apache2\htdocs directory. In the PHP script,
create a SOAP client using the SoapClient class. The WSDL document, catalog.wsdl, is
specified as an argument to the SoapClient constructor. The WSDL document specifies the
operations that are available to the SOAP client.
Specify the catalogId for which a catalog entry is to be retrieved. Invoke the getCatalogEntry
method of the SOAP web service.
$catalogId='catalog1';
$response = $client->getCatalogEntry($catalogId);
echo $response;
<?php
$client = new SoapClient("catalog.wsdl");
$catalogId='catalog1';
$response = $client->getCatalogEntry($catalogId);
echo $response;
?>
Invoke the soap-client.php PHP script with the URL http://localhost/soap-client.php.The catalog
entry for the catalog1 catalogId gets output as shown in Figure 1.
Figure 1. Invoking the SOAP client
An XML-RPC message is an HTTP-POST request. The request body is in XML format. The
request is sent to an XML-RPC server, which runs some business logic and returns a response in
the form of XML. An example XML-RPC request is listed below.
<?xml version="1.0"?>
<methodCall>
<methodName>getCatalog</methodName>
<params>
<param>
<value><string>catalog1
</string></value>
</param>
</params>
</methodCall>
The URI in the header, /php/xmlrpc-server.php specifies the server URI to which the request is
sent. The HTTP version is also specified. The User-Agent and Host are required to be specified.
The Content-Type is text/xml and the Content-Length specifies the content length.
The request body is in XML with root element as methodCall. The methodCall element is
required to contain a sub-element methodName which specifies the name of the method to be
invoked as a string. If the XML-RPC request has parameters, the methodCall element contains
sub-element params. The params element contains one or more param elements. Each of the
param elements contains a value element. The param value may be specified as a string, a
Boolean, a four-byte signed integer, double-precision signed, floating point number, date/time, or
base-64 encoded binary. The sub-element of value in which a param value is specified is
different for different value types. If a type is not specified the default type is string. The sub-
elements for the value types are listed in Table 3.
Date/time <dateTime.iso8601>
A param value may also be of type <struct>. A <struct> element consists of <member>
elements. Each <member> element contains a <name> element and a <value> element. An
example of struct value is listed below.
<struct>
<member>
<name>catalogId</name>
<value><string>catalog1
</string></value>
</member>
<member>
<name>journal</name>
<value><string>IBM developerWorks
</string></value>
</member>
</struct>
A value element in a member element may be of any of the param data types including struct.
A param type may also be of type <array>. An <array> element consists of of a <data>
element, which consists of one or more <value> elements. An example of an <array> param
value is listed below.
<array>
<data>
<value><i4>1</i4></value>
<value><string>IBM developerWorks
</string></value>
<value>XML</value>
<value><string>Introduction to dom4j
</string></value>
<value><string>Deepak Vohra</string
></value>
</data>
</array>
A <value> element in a <data> element may consist of any of the data types including struct
and array. The server response to an XML-RPC request is in the format of XML. An example
response is listed below.
HTTP/1.1 200 OK
Connection: close
Content-Length: 190
Content-Type: text/xml
Date:
Server: Example Server
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>Introduction
to SQLXML</string></value>
</param>
</params>
</methodResponse>
If an error has not occurred, the server response returns "200 OK." The Connection header
specifies the state of the connection after the response is completed. For non-persistent
connection the Connection header value is "close." The Content-Type is text/xml. The
response body is in XML format with root element as methodResponse. The methodResponse
element consists of a single <params> element, which consists of a single <param> element. The
<param> element contains a single <value> element.
HTTP/1.1 200 OK
Connection: close
Content-Length: 190
Content-Type: text/xml
Date:
Server: Example Server
<?xml version="1.0"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>4</int
></value>
</member>
<member>
<name>faultString</name>
<value><string>No such Method.
</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
The PHP XML-RPC extension is a PHP implementation of the XML-RPC specification. The
XML-RPC PHP class library provides functions to create a XML-RPC server and invoke
methods on the server. Some of the commonly used XML-RPC functions are discussed in Table
4.
Function Description
xmlrpc_encode_request ( string
Generates XML for a method request or response.
method, mixed params [, array
output_options] ) Returns a string or FALSE on error.
xmlrpc_get_type ( mixed value ) Returns XML-RPC data types, for example "struct",
"int", "string", "base64" for a PHP value.
xmlrpc_set_type ( string &value, Sets xmlrpc type, base64, or datetime for a PHP string
string type ) value. Returns True or False on error.
xmlrpc_server_destroy ( resource
Destroys a server resource.
server )
{
$name = $params[0];
return "Hello $name.";
}
$xmlrpc_server=xmlrpc_server_create();
If a server does not get created the xmlrpc_server_create method returns FALSE. Register the
hello_func function with the server using the xmlrpc_server_register_method method. The
first argument to the xmlrpc_server_register_method method is the XML-RPC server
resource. The second argument is name of the method that is provided by the web service, which
is the <methodName> element value in a XML-RPC request. The third argument is the PHP
function to be registered with the server.
$registered=xmlrpc_server_register_method
($xmlrpc_server, "hello", "hello_func" );
Next, I shall create a XML-RPC client to send a request to the XML-RPC server. First, specify
the XML string to be sent in the request.
To escape XML in PHP, <<<END ….END; is used. An XML document demarker other END may
also be used. The methodCall element specifies the web service method that is to be invoked.
Invoke the web service method using the xmlrpc_server_call_method function. The first
argument to the xmlrpc_server_call_method function is the server resource. The second
argument is the string containing the XML-RPC request. The third argument is the application
data that is sent to the third parameter of the method handler function.
$response=xmlrpc_server_call_method( $xmlrpc_server,
$request_xml, '', array(output_type => "xml"));
print $response;
<?php
function hello_func($method_name, $params, $app_data)
{
$name = $params[0];
return "Hello $name.";
}
$xmlrpc_server=xmlrpc_server_create();
$registered=xmlrpc_server_register_method
($xmlrpc_server, "hello", "hello_func" );
Copy the xmlrpc-webservice.php script to the C:/Apache2/htdocs directory. Invoke the PHP
script with the URL http://localhost/xmlrpc-webservice.php. The response from the server gets
output to the browser as shown in Figure 2.
Figure 2. Response from XML-RPC web service
To demonstrate an error in the request, returned as a <fault> element in the response XML,
make the request XML not valid XML. For example replace </methodCall> with
<methodCall> in the $request_xml. Invoke the xmlrpc-webservice.php. The response from the
server is returned as a <fault> element that consists of a struct element value, which consists
of faultCode and faultString members, as shown in Figure 3.
Figure 3. Response as fault element