• Index
  •  » Articles
  •  » Create your own Web Service with PHP and XML-RPC

Create your own Web Service with PHP and XML-RPC

Create your own Web Service with PHP and XML-RPC

That article requires some knowledge of PHP, MySQL and XML.

We can suggest as follows:

The Basics of Web Services: To start with we'll be quickly reviewing the basic concepts behind Web Services.


Introducing XML-RPC: Next, we'll introduce you to an XML standard for the exchange of data between systems.


PHP XML-RPC Implementations: Then we'll review some of the Open Source implementations of XML-RPC in PHP: code you can use to quickly build your own Web Service, or access other Web Services from your site.


Your first Web Service: If you want to get straight down to business, this is the place to be. Here, we'll take one of the implementations described previously, and build a Web Service for it in PHP.


What you can do with XML-RPC: Wondering what to do next? We'll give you some ideas for what you could do with XML-RPC and Web Services.

The Basics of Web Services

First thing you have to understand is that web-services conception isn’t new. If you have ever used RSS Feed for getting news from other sites and placing them at your own site you have got an idea about Web Service working. Web Services are used for exchanging data between client and server; XML format is used for “package” queries and data so that both sides can understand each other. Client and server can be both Web Services and other electronic devices.

Data exchange happens via TPC port 80 using standard HTTP protocol POST method. Other words Web Service working is similar to browser working that sends HTML form and receives the Web page in response. The main difference is that Web Services use XML instead of HTML. The data exchange happens at the packaging level.

You can also need the information that describes the service interface (API). That information makes Web Service very useful to the rest of the Internet. It allows other developers to create applications for accessing your web service. It is called the description layer; the WSDL (Web Services Description Language) is currently under the development.

Above that, there's information that describes the nature of the service itself (not unlike the HTML-descriptive META tags), so that it can be categorised and found on sites that offer Web Service directories. This is the discovery layer, which is currently being addressed by the UDDI (Universal Description, Discovery and Integration) standard.

Description and discovery layers are simply XML governed by the special format for enabling the information about all the Web Services on the Internet.

Introduction to XML-RPC

XML-RPC has been created about 1998, and although it's not an official W3C standard, is already widely used, and has impressive support in the form of Open Source projects. XML-RPC has been developed by Useful Incorporation together with Microsoft and now it is considered as the forerunner to SOAP.

The main reason of XML-RPC’s popularity is its simplicity. XML-RPC is supported in PHP and many other languages. For a detailed comparison of XML-RPC and SOAP, read XML-RPC vs. SOAP. In brief, SOAP is intended to fill the gaps in XML-RPC, offering a truly enterprise-level mechanism for the exchange of data between systems. For example, it should be easier to deliver multi-dimensional arrays through SOAP than through XML-RPC. But there's nothing wrong with using XML-RPC, especially given that it's a stable standard, while SOAP may undergo further re-definition in the future.

You can wonder whether XML-RPC learning makes sense, because it can be superseded by another standard. Don’t worry. Using XSLT you can easily transform SOAP query to XML-PRC query.

So, how does it work? Reading that article you’ll understand that you don’t have to know a lot about XML-PRC for using it.

There are two components of the XML-PRC “messages” – methods and parameters. Methods correspond to functions defined in PHP; parameters correspond to the variables we pass to these functions. Parameters have different types such as strings, integers or arrays.

XML-RPC "conversation", between two systems begins with a request from the XML-RPC client, which the server answers with a response. Request has method’s name and required parameters. Response contains the parameter set which include the requested data. That process is similar to using functions defined in PHP: call the function and pass it some variables. As a result function responses returning several variables.

Here is an example of the typical XML-PRC server query:

POST /xmlrpcInterface HTTP/1.0
User-Agent: Sitepoint XML-RPC Client 1.0
Host: xmlrpc.sitepoint.com
Content-type: text/xml
Content-length: 195
<?xml version="1.0"?>
<methodCall> 
<methodName>forums.getNumTodaysThreads</methodName>
<params>
<param><value><string>PHP Development</string></value></param>
</params>
</methodCall>

And here's the response from the server, as seen by the XML-RPC client.

HTTP/1.1 200 OK
Connection: close
Content-Length: 148
content-Type: text/xml
Date: Wed, Jul 28 1999 15:59:04 GMT
Server: Sitepoint XML-RPC Server 1.0
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><int>42</int></value>
</param>
</params>
</methodResponse>

The example request can find out how many threads have been posted in the forum today. The response tells the client the interested number. This is just a simple example, sending one parameter to a method and getting one parameter back. XML-RPC provides much more, allowing you to pass the server more complicated sets of data (such as arrays), and receive in return a detailed response that contains all sorts of data.

In case you were wondering, the "RPC" in XML-RPC stands for Remote Procedure Call. The client system "calls" a "procedure" (or method) on a remote server. The concept of a Remote Procedure Call is general to software development, and one which you'll come across in many places. XML-RPC is an XML standard for data exchange to be used in a Remote Procedure Call.

PHP implementations XML-RPC

XMLRPC-EPI

XMLRPC-EPI was developed for internal use in the epinions and has become successful and now it provides PHP with the experimental XML-RPC functions. XMLRPC-EPI is a base class written in C++ (the rest are written in PHP). That’s why if you don’t have the root access you won’t be able to install it; you’ll have to recompile PHP.

That application just interprets the content of the XML-RPC requests and responses; it doesn’t send or receive them.

eZ xmlrpc

Developed by Bĺrd Farstad, this is the XML-RPC class used in ezPublish to receive requests from their desktop client. The design of the class is good, in that it's fairly intuitive to work with and is nicely introduced by this tutorial, plus it offers introspection.

phpRPC

Class has a great potential. Developers didn’t stop at the simple interpretation and request/response handling; they provided wider functionality such as connection to the “abstract” database.

phpxmlrpc

It was developed by Useful Incorporation. The application supports XML-RPC standard and provides the debug opportunity that can become the biggest problem while creating the Web Service

Keith Devens' XML-RPC Client/Server.

If you visit the homepage of that project you can understand that it is the best beginning. The code is not the full class; it is the set of the user-defined functions that should be included to the script.

In that system XML-RPC server and client doesn’t have to define the type of the received XML-RPC parameters. It means that XML-RPC client should check the received data more thoroughly. The documentation is good, that’s why our first Web Service will be built using that project.

Your first Web Service

So, let’s start. Let’s write the web-service for publishing news from your web site and lines of RSS feeds. But instead of providing a list of titles and links, our Web Service will make it look like the news lives on the site where the XML-RPC client is installed.

We'll define two XML-RPC methods: "news.getNewsList", which will provide a list of news items, and "news.viewNewsItem", which displayes a single news item in full. Also we will use default "method_not_found" method, in case of trouble. Each method corresponds to a function we'll define in PHP, such as a query which selects news from your database.

Preparations

  • Download the code of that article; it will help you to escape copying and pasting.
  • Download the source code from http://www.keithdevens.com/software/xmlrpc/source.php and save it as “kd_xmlrpc.php”.
  • Now create a directory on your Web server, call it kd_xmlrpc, below your Web root (where your "home page" is located), and place kd_xmlrpc.php there. We'll be putting all the other files we create below in the same directory.
  • In MySQL database create the table using the following query:
  • CREATE TABLE kd_xmlrpc_news (
    news_id mediumint(9) NOT NULL auto_increment,
    title varchar(255) default NULL,
    short_desc text,
    full_desc text,
    author varchar(100) default NULL,
    date datetime NOT NULL default "0000-00-00 00:00:00",
    PRIMARY KEY (news_id)
    ) TYPE=MyISAM COMMENT="XML RPC News";

  • And now INSERT some news, run the "kd_xmlrpc_news.sql" query you'll find in the code archive

XML-RPC-server

Database is ready. Now let’s write the server script called “server.php”

<?php 
/* server.php */ 

/* Variables for accessing MySQL */ 
$dbserver"localhost";     // Hostname of your MySQL server 
$db "database_name";      // Name of your MySQL database 
$dbuser "username";       // MySQL user with access to $db 
$dbpassword "password";   // Password for MySQL user 

/* Connect to the MySQL server */ 
$link = @mysql_connect ($dbserver$dbuser$dbpassword); 
if (! 
$link){ 
   echo ( 
"Unable to connect to db" ); 
exit(); 


/* Select the database */ 
if (!mysql_select_db ($db$link) ){ 
exit (); 


/* Include Keith"s xml-rpc library */ 
include("kd_xmlrpc.php"); 

/* Include a file that defines all the xml-rpc "methods" */ 
include("web_service_api.php"); 

/* Now use the XMLRPC_parse function to take POST  
  data from what xml-rpc client connects and turn  
  it into normal PHP variables */ 
$xmlrpc_request XMLRPC_parse($GLOBALS["HTTP_RAW_POST_DATA"]); 

/* From the PHP variables generated, let"s get the  
  method name ie. server asks "What would you like  
  me to do for you?" */ 
$methodName XMLRPC_getMethodName($xmlrpc_request); 

/* Get the parameters associated with that method  
  e.g "So you want to view a news item. Tell me  
  which one you want. What"s the id#?" */ 
$params XMLRPC_getParams($xmlrpc_request); 

/* Error check - if a method was used that doesn"t  
  exist, return the error response to the client */ 
if(!isset($xmlrpc_methods[$methodName])){ 
   
$xmlrpc_methods["method_not_found"]($methodName); 

/* Otherwise, let"s run the PHP function corresponding  
  to that method - note the functions themselves  
  return the correct formatted xml-rpc response  
  to the client */ 
}else{ 

   
/* Call the method - notice $params[0] not just $params as the 
   documentation states. */ 
   
$xmlrpc_methods[$methodName]($params[0]); 

?>

Here is a short description that illustrates what happens in “server.php”.

  • Connect to MySQL and give the script access to the database
  • Include kd_xmlrpc.php
  • Include web_service_api.phpthat defines the XML-RPC methods
  • We have to use XMLRPC_parse() function for taking the contents of the $GLOBALS['HTTP_RAW_POST_DATA'] which contains XML-RPC client query.
  • Now let’s define the method called by XMLRPC_getMethodName() function. We want our XML-RPC server to run more than one function or method and exactly here we’ll define the method that will process the current query (for example, "news.getNewsList" or "news.viewNewsItem").
  • Now check for any parameters sent in the client request, such as an "id" (identifying number) of a news item.
  • Finally we check that the method exists, as defined in web_service_api.php, and if everything looks good, we run the method (i.e. PHP function) required. If we can't find the method, we run the default "method_not_found" method.

Specific XML-RPC functions used in the script are as follows:


  • XMLRPC_parse(): that function receives XML data and transform them to the PHP variables At this point, this isn't specific to the XML-RPC standard - any XML that's sent will be converted to PHP variables.
  • XMLRPC_getMethodName() determines which method is being used so we can decide which PHP function to use.
  • XMLRPC_getParams() takes any XML-RPC parameters and converts them to PHP variables.

XML-RPC server is completed. Now all we need are those PHP functions to be used with the methods...

Methods

Now let’s write PHP functions that correspond to the XML-RPC methods and store them in the 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=) { 

   
/* 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); 

?>

So, what’s happens here

  • At first we’ve created $xmlrpc_methods PHP array where is stored a list of all available XML-RPC methods and correspondent PHP functions.
  • mysql_datetime_to_timestamp() function can’t be considered as a XML-RPC method. That function converts MySQL date-time fields to a format PHP can work with.
  • Then we define news_getNewsList() function for sending requests to the "kd_xmlrpc_news" table. The available argument of that function is $query_info array which has parameters that XML-RPC client can send.
  • 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.

Specific XML-RPC functions used in the script are as follows:


  • XMLRPC_convert_timestamp_to_iso8601() :XML-RPC uses special format for defining data and time. That function just takes timestamp in PHP and transforms to the correct format for XML-PRC.
  • XMLRPC_prepare(): that function takes the variables set and transforms to the XML-PRC parameters.
  • XMLRPC_response(): that function is used for sending the response to client. Function has two arguments XML-RPC data and 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.

XML-RPC client

We'll store the client script in the same place as the server, but if you have another Web server, you could place the script there, making sure it has access to "kd_xmlrpc.php", the functions library.

<?php 
/* Include the library */ 
include ( "kd_xmlrpc.php" ); 

/* Define variables to find the rpc server script */ 
$site "www.yourdomain.com"
$location "/kd_xmlrpc/server.php"

/* Function to give us back a nice date */ 
function convert_date $date ) { 
   
$date date "D M y H:i:s"
                 
XMLRPC_convert_iso8601_to_timestamp $date ) ); 
   return ( 
$date ); 

?> 
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<html> 
<head> 
<title> KD XML RPC News Client </title> 
<meta name="Generator" content="EditPlus"> 
<meta name="Author" content="HarryF"> 
<meta name="Keywords" content="XML RPC"> 
<meta name="Description" content="Gets news form server.php"> 
</head> 
<body> 
<?php  

/* client.php */ 
/* If user is viewing a single news item, do this */ 
if ( ISSET ( $_GET["news_id"] ) ) { 

   
/* $success is 0 (fail) / 1 ( succeeded ).  
      XMLPRC_request preforms the XML POST to  
      the server script, calling the method and  
      sending the correct parameters using  
      XMLRPC_prepare */ 
   
list($success$response) = XMLRPC_request
       
$site
       
$location
       
"news.viewNewsItem"
       array(
XMLRPC_prepare($_GET["news_id"]), 
       
"HarryFsXMLRPCClient"
   ); 

   
/* If all went well, show the article */ 
   
if ($success) { 
?> 
<table align="center" width="600"> 
<tr valign="top"> 
<th colspan="2"><b><?php echo ( $response["title"] );?></b></th> 
</tr> 
<tr valign="top"> 
<th><?php echo ( $response["author"] );?></th> 
<th><?php echo ( convert_date $response["date"] ) );?></th> 
</tr> 
<tr valign="top"> 
<td colspan="2"> 
<?php echo ( nl2br $response["full_desc"] ) );?> 
</th> 
</tr> 
</table> 
<?php 

   
/* Else display the error */ 
   
} else { 
       echo ( 
"<p>Error: " nl2br $response["faultString"] ) ); 
   } 
} else { 

   
/* Define the parameters to pass to the XML-RPC  
   method as a PHP array */ 
   
$query_info["limit"] = 10
   
$query_info["order"] = "author"

   
/* XMLRPC_prepare works on an array and  
   converts it to XML-RPC parameters */ 
   
list($success$response) = XMLRPC_request
       
$site
       
$location
       
"news.getNewsList"
       array(
XMLRPC_prepare($query_info), 
       
"HarryFsXMLRPCClient"
   ); 

   
/* On success, display the list as HTML table */ 
   
if ($success) { 
       echo ( 
"<table align=\"center\" width=\"600\">\n" ); 
       
$count 0
       while ( list ( 
$key$val ) = each $response ) ) { 
?> 
<tr valign="top"> 
<td colspan="2"> 
<a href="<?php echo ( $_SERVER["PHP_SELF"] );?>?news_id=<?php 
echo ( $response[$count]["news_id"] ); 
?>"> 
<?php echo ( $response[$count]["title"] ); ?> 
</a> 
</td> 
</tr> 
<tr valign="top"> 
<td colspan="2"> 
<?php echo ( $response[$count]["short_desc"] ); ?> 
</td> 
</tr> 
<tr valign="top"> 
<td> 
<?php echo ( $response[$count]["author"] ); ?> 
</td> 
<td> 
<?php echo ( convert_date $response[$count]["date"] ) ); ?> 
</td> 
</tr> 
<?php 
           $count
++; 
       } 
       echo ( 
"</table>\n" ); 

   
/* Or error */ 
   
} else { 
       echo ( 
"<p>Error: " nl2br $response["faultString"] ) ); 
   } 

;
?> 
</body> 
</html>

What happens here? PHP code is just a if/else structure, so if we want to look at the single news item and use $_GET['news_id'] variable script will show that news item. Otherwise there will be shown the whole list of the news.

For looking at the news list we use news.getNewsList method.

If we want to view only one news item we will transform $_GET['news_id'] to the parameter. According to that parameter server will “understand” which news item we want to view.


Specific XML-RPC functions used in the script are as follows:


  • XMLRPC_prepare(): we used it in the server; we will convert PHP variables to the XML-PRC parameters. Here we fix data that server will use for working with requested method.
  • XMLRPC_request(): that function gets five variables as arguments and returns an array:
    • $site – server domain name
    • $location path to the server script from the web-root.
    • $methodName –name of the requested XML-RPC method
    • $params – any required variables
    • $user_agent optional argument, here you can use whatever you want (for example HarryFsXMLRPCClient).

Returned array has two variables. First variable gets value 0 in the case of the negative response from the server, 1 in the case of positive response. Second variable is a multidimensional array that has data from the server response.

One tip: for writing XML-RPC clients, it can be helpful to think of the server in the same way that you'd think of a database -- it's just a source of data. In terms of your scripts, the code will be a similar structure to that which you'd use when querying MySQL.

So that's it! Point your browser at http://www.yourdomain.com/kd_xmlrpc/client.php, sit back and read the news.


 

  • Top