Article
Build your own Web Service with PHP and XML-RPC
The Methods
Next, we define some PHP functions that correspond to XML-RPC methods, and store them in web_service_api.php:
<?php
/* web_service_api.php */
/* Define an array to name the xmlrpc methods and
their corresponding PHP functions */
$xmlrpc_methods = array();
$xmlrpc_methods['news.getNewsList'] = news_getNewsList;
$xmlrpc_methods['news.viewNewsItem'] = news_viewNewsItem;
$xmlrpc_methods['method_not_found'] = XMLRPC_method_not_found;
/* Now a useful function for converting MySQL datetime
to a UNIX timestamp which can then be used with
the XMLRPC_convert_timestamp_to_iso8601($timestamp) function.
This is not a method!
It comes from: http://www.zend.com/codex.php?id=176&single=1 */
function mysql_datetime_to_timestamp($dt) {
$yr=strval(substr($dt,0,4));
$mo=strval(substr($dt,5,2));
$da=strval(substr($dt,8,2));
$hr=strval(substr($dt,11,2));
$mi=strval(substr($dt,14,2));
$se=strval(substr($dt,17,2));
return mktime($hr,$mi,$se,$mo,$da,$yr);
}
/* Function for listing news items, corresponding
to the news.getNewsList method Allows ordering by
column name and a result limit of up to 20 rows */
function news_getNewsList ( $query_info=0 ) {
/* Define an array of column names we'll accept
to ORDER BY in our query */
$order_fields = array ( "author", "title" );
/* Now check to see if $query_info['order'] has
an acceptable value and assign the correct value
to the $order variable */
if ( ISSET ( $query_info['order'] ) &&
in_array ( $query_info['order'], $order_fields ) ) {
$order = "ORDER BY " . $query_info['order'] . ", date DESC ";
} else {
$order = "ORDER BY date DESC ";
}
/* Now check for $query_info['limit'] to specify
the number of news items we want returned,
and assign the correct value to $limit */
if ( ISSET ( $query_info['limit'] ) && $query_info['limit'] < 20 ) {
$limit = "LIMIT 0, " . $query_info['limit'] . " ";
} else {
$limit = "LIMIT 0, 5 ";
}
/* Now build the query */
$query = "SELECT * FROM kd_xmlrpc_news " . $order . $limit;
$sql = mysql_query ( $query );
if ( $sql ) {
$news_items = array();
while ( $result = mysql_fetch_array ( $sql ) ) {
/* Extract the variables we want from the row */
$news_item['news_id'] = $result['news_id'];
$news_item['date'] = XMLRPC_convert_timestamp_to_iso8601(
mysql_datetime_to_timestamp( $result['date'] )
);
$news_item['title'] = $result['title'];
$news_item['short_desc'] = $result['short_desc'];
$news_item['author'] = $result['author'];
/* Add to the $news_items array */
$news_items[] = $news_item;
}
/* Convert the $news_items array to a set
of XML-RPC parameters then respond with the XML. */
XMLRPC_response(XMLRPC_prepare($news_items),
KD_XMLRPC_USERAGENT);
} else {
/* If there was an error, respond with an
error message */
XMLRPC_error("1", "news_getNewsList() error: Unable
to read news:"
. mysql_error() . "\nQuery was: " . $query,
KD_XMLRPC_USERAGENT);
}
}
/* Function for viewing a full news item corresponding
to the news.viewNewsItem method */
function news_viewNewsItem ( $news_id ) {
/* Define the query to fetch the news item */
$query = "SELECT * FROM kd_xmlrpc_news WHERE news_id = '"
. $news_id . "'";
$sql = mysql_query ( $query );
if ( $result = mysql_fetch_array ( $sql ) ) {
/* Extract the variables for sending in
our server response */
$news_item['news_id'] = $result['news_id'];
$news_item['date'] = XMLRPC_convert_timestamp_to_iso8601(
mysql_datetime_to_timestamp( $result['date'] ) );
$news_item['title'] = $result['title'];
$news_item['full_desc'] = $result['full_desc'];
$news_item['author'] = $result['author'];
/* Respond to the client with the news item */
XMLRPC_response(XMLRPC_prepare($news_item),
KD_XMLRPC_USERAGENT);
} else {
/* If there was an error, respond with a
fault code instead */
XMLRPC_error("1", "news_viewNewsItem() error: Unable
to read news:"
. mysql_error(), KD_XMLRPC_USERAGENT);
}
}
/* Function for when the request method name
doesn't exist */
function XMLRPC_method_not_found($methodName){
XMLRPC_error("2", "The method you requested, " . $methodName
. ", was not found.", KD_XMLRPC_USERAGENT);
}
?>
What happened here?
- First we defined a PHP array
$xmlrpc_methods, which is a list of all the available XML-RPC methods and the PHP functions to run for that method. - The
mysql_datetime_to_timestamp()function is not an XML-RPC method itself, but rather a useful function to convert MySQL datetime fields to a format PHP can work with. - Then we define
news_getNewsList(), which we'll use to query the "kd_xmlrpc_news" table. This function is capable of accepting an array called$query_info, which will correspond to optional parameters that the XML-RPC client can send. As you can see, this alters the query we run against mysql, changing the "ORDER BY" and "LIMIT" options. - The function
news_viewNewsItem()is used to pull a single news item from the database, and accepts only one variable/parameter:$news_id,which corresponds to the row id of the article in the database. - The last function,
XMLRPC_method_not_found(), is our default function, which generates a response when the client request is for an XML-RPC method that didn't exist.
The special XML-RPC functions we used were:
XMLRPC_convert_timestamp_to_iso8601(): the XML-RPC has a specified format for sending dates and times. This function takes a PHP timestamp and converts it to the correct format for XML-RPC.XMLRPC_prepare(): this takes a set of PHP variables and turns it into XML-RPC parameters. It identifies the type of variable being used and creates the correct XML-RPC output from it. This is one of the things that make Keith Devens' code friendly to use -- the other implementations generally require that you use a separate function for arrays, integers, strings and so on, when building the XML-RPC request of response.XMLRPC_response(): is the function you use to provide the results to the client, on request. It takes two values -- the first being the XML-RPC data (built byXMLRPC_prepare()), and the second, an optional name for the server or a user agent e.g.KD_XMLRPC_USERAGENT-- this can be whatever you like.XMLRPC_error(): generates an XML-RPC response using the error reporting tags defined in the specification. Should you desire, you could build your own set of error codes for your server here, which can help a lot when it comes to debugging the server.
Phew! So now we've defined our PHP functions, and have an array to translate them to XML-RPC methods: our XML-RPC server is ready to go! Now, to finish off, let's put together a simple client to access our news.