12.8.1 Problem
You want to create an XML-RPC server and respond to XML-RPC requests. This allows any XML-RPC-enabled
client to ask your server questions and you to reply with data.
12.8.2 Solution
Use PHP's XML-RPC extension. Here is a PHP version of the
Userland XML-RPC demonstration application that returns an ISO 8601 string with the current date and time:
// this is the function exposed as "get_time( )"
function return_time($method, $args) {
return date('Ymd\THis');
}
$server = xmlrpc_server_create( ) or die("Can't create server");
xmlrpc_server_register_method($server, 'return_time', 'get_time')
or die("Can't register method.");
$request = $GLOBALS['HTTP_RAW_POST_DATA'];
$options = array('output_type' => 'xml', 'version' => 'xmlrpc');
print xmlrpc_server_call_method($server, $request, NULL, $options)
or die("Can't call method");
xmlrpc_server_destroy($server);
12.8.3 Discussion
Since the bundled XML-RPC extension, xmlrpc-epi, is written in
C, it processes XML-RPC requests in a speedy and efficient fashion. Add
--with-xmlrpc to your configure string to enable this extension during
compile time. For more on XML-RPC, see Section 12.7.
The Solution begins with a definition
of the PHP function to associate with the XML-RPC method. The name of the
function is return_time( ). This is later
linked with the get_time( ) XML-RPC method:
function return_time($method, $args) {
return date('Ymd\THis');
}
The function returns an ISO 8601-formatted string with the
current date and time. We escape the T inside the call to date(
) because the specification requires a literal T to divide the
date part and the time part. For August 21, 2002 at 3:03:51 P.M., the return
value is 20020821T150351.
The function is automatically called with two parameters: the
name of the XML-RPC method the server is responding to and an array of method
arguments passed by the XML-RPC client to the server. In this example, the
server ignores both variables.
$server = xmlrpc_server_create( ) or die("Can't create server");
xmlrpc_server_register_method($server, 'return_time', 'get_time');
We create a new server and assign it to $server, then
call xmlrpc_server_register_method( ) with
three parameters. The first is the newly created server, the second is the name
of the method to register, and the third is the name of the PHP function to
handle the request.
Now that everything is configured, tell the XML-RPC server to
dispatch the method for processing and print the results to the client:
$request = $GLOBALS['HTTP_RAW_POST_DATA'];
$options = array('output_type' => 'xml', 'version' => 'xmlrpc');
print xmlrpc_server_call_method($server, $request, NULL, $options);
The client
request comes in as POST data. PHP converts HTTP POST data to variables, but
this is XML-RPC data, so the server needs to access the unparsed data, which is
stored in $GLOBALS['HTTP_RAW_POST_DATA']. In this example, the request
XML looks like this:
<?xml version="1.0" encoding="iso-8859-1"?> <methodCall> <methodName>get_time</methodName> <params/></methodCall>
Thus, the server is responding to the get_time( )
method, and it expects no parameters.
We also configure the response options to output the results in
XML and interpret the request as XML-RPC. These two variables are then passed to
xmlrpc_server_call_method( ) along with the XML-RPC server,
$server. The third parameter to this function is for any user data you
wish to provide; in this case, there is none, so we pass NULL.
The xmlrpc_server_call_method( ) function decodes the
variables, calls the correct function to handle the method, and encodes the
response into XML-RPC. To reply to the client, all you need to do is print out
what xmlrpc_server_call_method( ) returns.
Finally, clean up with a call to xmlrpc_server_destroy(
):
xmlrpc_server_destroy($server);
Using the XML-RPC client code from Section 12.7, you can make a request and find the time, as follows:
require 'utils.php';
$output = array('output_type' => 'xml', 'version' => 'xmlrpc');
$result = xu_rpc_http_concise(array(
'method' => 'get_time',
'host' => 'clock.example.com',
'port' => 80,
'uri' => '/time-xmlrpc.php',
'output' => $output));
print "The local time is $result.\n";
The local time is 20020821T162615.
It is legal to
associate multiple methods with a single XML-RPC server. You can also associate
multiple methods with the same PHP function. For example, we can create a server
that replies to two methods: get_gmtime( ) and get_time( ). The first method, get_gmtime(
), is similar to get_time( ), but it replies with the current time
in GMT. To handle this, you can extend get_time( ) to take an optional
parameter, which is the name of a time zone to use when computing the current
time.
function return_time($method, $args) {
if ('get_gmtime' == $method) {
$tz = 'GMT';
} elseif (!empty($args[0])) {
$tz = $args[0];
} else {
// use local time zone
$tz = '';
}
if ($tz) { putenv("TZ=$tz"); }
$date = date('Ymd\THis');
if ($tz) { putenv('TZ=EST5EDT'); } // change EST5EDT to your server's zone
return $date;
}
This function uses both the $method and $args
parameters. At the top of the function, we check if the request is for
get_gmtime. If so, the time zone is set to GMT. If it isn't, see if an
alternate time zone is specified as an argument by checking $args[0].
If neither check is true, we keep the current time zone.
To configure the server to handle the new method, add only one
new line:
xmlrpc_server_register_method($server, 'return_time', 'get_gmtime');
This maps get_gmtime( ) to return_time( ).
Here's an
example of a client in action. The first request is for get_time( )
with no parameters; the second calls get_time( ) with a time zone of
PST8PDT, which is three hours behind the server; the last request is
for the new get_gmtime( ) method, which is four hours ahead of the
server's time zone.
require 'utils.php';
$output = array('output_type' => 'xml', 'version' => 'xmlrpc');
// get_time( )
$result = xu_rpc_http_concise(array(
'method' => 'get_time',
'host' => 'clock.example.com',
'port' => 80,
'uri' => '/time.php',
'output' => $output));
print "The local time is $result.\n";
// get_time('PST8PDT')
$result = xu_rpc_http_concise(array(
'method' => 'get_time',
'args' => array('PST8PDT'),
'host' => 'clock.example.com',
'port' => 80,
'uri' => '/time.php',
'output' => $output));
print "The time in PST8PDT is $result.\n";
// get_gmtime( )
$result = xu_rpc_http_concise(array(
'method' => 'get_gmtime',
'host' => 'clock.example.com',
'port' => 80,
'uri' => '/time.php',
'output' => $output));
print "The time in GMT is $result.\n";
The local time is 20020821T162615.
The time in PST8PDT is 20020821T132615.
The time in GMT is 20020821T202615.