Programming PHPProgramming PHPSearch this book

11.5. Web Services

Historically, every time there's been a need for two systems to communicate, a new protocol has been created (for example, SMTP for sending mail, POP3 for receiving mail, and the numerous protocols that database clients and servers use). The idea of web services is to remove the need to create new protocols by providing a standardized mechanism for remote procedure calls, based on XML and HTTP.

Web services make it easy to integrate heterogeneous systems. Say you're writing a web interface to a library system that already exists. It has a complex system of database tables, and lots of business logic embedded in the program code that manipulates those tables. And it's written in C++. You could reimplement the business logic in PHP, writing a lot of code to manipulate tables in the correct way, or you could write a little code in C++ to expose the library operations (e.g., check out a book to this user, see when this book is due back, see what the overdue fines are for this user) as a web service. Now your PHP code simply has to handle the web frontend; it can use the library service to do all the heavy lifting.

XML-RPC and SOAP are two of the standard protocols used to create web services. XML-RPC is the older (and simpler) of the two, while SOAP is newer and more complex. Microsoft's .NET initiative is based around SOAP, while many of the popular web journal packages, such as Frontier and blogger, offer XML-RPC interfaces.

PHP provides access to both SOAP and XML-RPC through the xmlrpc extension, which is based on the xmlrpc-epi project (see http://xmlrpc-epi.sourceforge.net for more information). The xmlrpc extension is not compiled in by default, so you'll need to add --with-xmlrpc to your configure line.

The PEAR project (http://pear.php.net) is working on an object-oriented XML-RPC extension, but it was not ready for release at the time of this writing.

11.5.1. Servers

Example 11-15 shows a very basic XML-RPC server that exposes only one function (which XML-RPC calls a "method"). That function, multiply( ), multiplies two numbers and returns the result. It's not a very exciting example, but it shows the basic structure of an XML-RPC server.

Example 11-15. Basic XML-RPC server

<?php
 // this is the function exposed as "multiply( )"
 function times ($method, $args) {
   return $args[0] * $args[1];
 }
  
 $request = $HTTP_RAW_POST_DATA;
 if (!$request) $request_xml = $HTTP_POST_VARS['xml'];
  
 $server = xmlrpc_server_create( );
 if (!$server) die("Couldn't create server");
  
 xmlrpc_server_register_method($server, 'multiply', 'times');
  
 $options = array('output_type' => 'xml', 'version' => 'auto');
 echo xmlrpc_server_call_method($server, $request, null, $options);
  
 xmlrpc_server_destroy($server);
?>

The xmlrpc extension handles the dispatch for you. That is, it works out which method the client was trying to call, decodes the arguments and calls the corresponding PHP function, and returns an XML response that encodes any values returned by the function that can be decoded by an XML-RPC client.

Create a server with xmlrpc_server_create( ):

$server = xmlrpc_server_create( );

Expose functions through the XML-RPC dispatch mechanism using xmlrpc_server_register_method( ):

xmlrpc_server_register_method(server, method, function);

The method parameter is the name the XML-RPC client knows. The function parameter is the PHP function implementing that XML-RPC method. In the case of Example 11-15, the multiply( ) method is implemented by the times( ) function. Often a server will call xmlrpc_server_register_method( ) many times, to expose many functions.

When you've registered all your methods, call xmlrpc_server_call_method( ) to do the dispatching:

$response = xmlrpc_server_call_method(server, request, user_data [, options]);

The request is the XML-RPC request, which is typically sent as HTTP POST data. We fetch that through the $HTTP_RAW_POST_DATA variable. It contains the name of the method to be called, and parameters to that method. The parameters are decoded into PHP data types, and the function (times( ), in this case) is called.

A function exposed as an XML-RPC method takes two or three parameters:

$retval = exposed_function(method, args [, user_data]);

The method parameter contains the name of the XML-RPC method (so you can have one PHP function exposed under many names). The arguments to the method are passed in the array args, and the optional user_data parameter is whatever the xmlrpc_server_call_method( )'s user_data parameter was.

The options parameter to xmlrpc_server_call_method( ) is an array mapping option names to their values. The options are:

output_type
Controls the data encoding used. Permissible values are: "php" or "xml" (default).

verbosity
Controls how much whitespace is added to the output XML to make it readable to humans. Permissible values are: "no_white_space", "newlines_only", and "pretty" (default).

escaping
Controls which characters are escaped, and how. Multiple values may be given as a subarray. Permissible values are: "cdata", "non-ascii" (default), "non-print" (default), and "markup" (default).

versioning
Controls which web service system to use. Permissible values are: "simple", "soap 1.1", "xmlrpc" (default for clients), and "auto" (default for servers, meaning "whatever format the request came in").

encoding
Controls the character encoding of the data. Permissible values include any valid encoding identifiers, but you'll rarely want to change it from "iso-8859-1" (the default).

11.5.2. Clients

An XML-RPC client issues an HTTP request and parses the response. The xmlrpc extension that ships with PHP can work with the XML that encodes an XML-RPC request, but it doesn't know how to issue HTTP requests. For that functionality, you must download the xmlrpc-epi distribution from http://xmlrpc-epi.sourceforge.net and install the sample/utils/utils.php file. This file contains a function to perform the HTTP request.

Example 11-16 shows a client for the multiply XML-RPC service.

Example 11-16. Basic XML-RPC client

<?php
 require_once('utils.php');
  
 $options = array('output_type' => 'xml', 'version' => 'xmlrpc');
 $result = xu_rpc_http_concise(
    array(method  => 'multiply',
          args    => array(5, 6),
          host    => '192.168.0.1',
          uri     => '/~gnat/test/ch11/xmlrpc-server.php',
          options => $options));
  
 echo "5 * 6 is $result";
?>

We begin by loading the XML-RPC convenience utilities library. This gives us the xu_rpc_http_concise( ) function, which constructs a POST request for us:

$response = xu_rpc_http_concise(hash);

The hash array contains the various attributes of the XML-RPC call as an associative array:

method
Name of the method to call

args
Array of arguments to the method

host
Hostname of the web service offering the method

uri
URL path to the web service

options
Associative array of options, as for the server

debug
If nonzero, prints debugging information (default is 0)

The value returned by xu_rpc_http_concise( ) is the decoded return value from the called method.

There are several features of XML-RPC we haven't covered. For example, XML-RPC's data types do not always map precisely onto PHP's, and there are ways to encode values as a particular data type rather than as the xmlrpc extension's best guess. Also, there are features of the xmlrpc extension we haven't covered, such as SOAP faults. See the xmlrpc extension's documentation at http://www.php.net for the full details.

For more information on XML-RPC, see Programming Web Services in XML-RPC, by Simon St. Laurent, et al. (O'Reilly). See Programming Web Services with SOAP, by James Snell, et al. (O'Reilly), for more information on SOAP.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.