XML- RPC Client

August 1, 2013

Tutorials

Intended Audience
Overview
Learning Objectives

Definitions
Background Information
Prerequisites
How the script works
Step 1: Creating the Client
Step 2: Constructing the Request

Step 3: Sending the request to the server
Step 4: Working with server’s response

Working with the xmlrpcval class
The Script

About the Author

Intended Audience

This tutorial is written for the PHP developer interested in implementing an
XML-RPC client in PHP.
Experience working with PHP classes and an understanding of the HTTP protocol
are assumed.

Overview

This tutorial teaches you, step-by-step, how to build an XML-RPC client in
PHP using the XML-RPC library written by Edd Dumbill. It covers each of the PHP
classes you will be using, and how they fit together to form the final client.

A primer is included to introduce the basics of the XML-RPC specification.
The primer provides enough information to work with the XML-RPC library. If you
want to learn more about the XML-RPC specification see

http://www.xmlrpc.com.

Learning Objectives

In this tutorial you will:

  • Learn the basics of XML-RPC and its underlying technologies and ideas.
  • Implement and learn how to build an XML-RPC client in PHP.
  • Learn some good practices for handling the data returned from an XML-RPC Server.

Definitions

  • XML-RPC Message — XML-RPC messages are the requests and responses sent between server and client. They are similar to regular HTTP calls except the payload is XML.
  • CURL — A library written by Daniel Stenberg that allows you to connect to many different types of servers using a variety of protocols. It needs to be compiled into your PHP if you want to use XML-RPC over HTTPS.
  • HTTPS — An extension to the HTTP protocol that supports encryption.

Background Information

This section provides a brief introduction to XML-RPC. You can skip this
section if you are ready to start building your client right away.

XML-RPC is not a new technology; rather it is a new way of using existing
technologies. It is simply XML over HTTP. Let’s quickly review each of XML-RPC’s
supporting technologies starting with the tried and true HTTP.

HTTP stands for the Hypertext Transfer Protocol and is protocol of the World
Wide Web. It is lightweight, easy to implement, and it can carry both plain text
and binary data. By using HTTP as the carrier protocol, XML-RPC can be easily
implemented in millions of existing Web servers.

XML stands for eXtensible Markup Language. XML is a language designed for
creating other mark up languages. By using XML to structure the data, XML-RPC
becomes completely platform independent. (Imagine your toaster using XML-RPC to
order more bread through your grocer’s Web site.)

RPC stands for Remote Procedure Call. Every operation in a computer is the
result of a procedure call. RPC takes this a step further by allowing computers
to make procedure calls on other — remote –computers. XML-RPC implements this
idea with XML and HTTP.

XML-RPC has eight data types. They are:

  • int
  • double
  • string
  • boolean
  • base64
  • dateTime.iso8601
  • array
  • struct

Most of those data types will already be familiar to you if you are an
experienced programmer. (See the XML-RPC specification for the exact definitions
and data ranges of each type.) For our present purposes, knowing the difference
between the two complex types array and struct is enough. The array type is like
an indexed array, whereas the struct type is like an associative array.

 // An XML-RPC array type is similar to:
$array = array (‘one’,‘two’,‘three’); 

// An XML-RPC struct type is similar to:
$struct = array (
   ’primary’=> ‘one’
   ’secondary’=> ‘two’,
   ’tertiary’=> ‘three’);

The XML-RPC library used for this tutorial was written by Edd Dumbill, who is
also a co-author of “Programming Web Services with XML-RPC”.

Prerequisites

You will need the XML-RPC library from
http://phpxmlrpc.sourceforge.net/
and PHP 4 compiled with XML support. If you plan to use HTTPS to send your
requests, you will need PHP compiled with CURL support.

How the script works

Thanks to the XML-RPC library, the task of creating an XML-RPC client has
been reduced to four main steps. They are:

  1. Creating a client object
  2. Constructing the request
  3. Sending the request to the server
  4. Working with the server’s response

Consider this example:

// 1: INITIALIZE THE CLIENT

$xmlrpc_client = new
xmlrpc_client(‘path/to/script’,‘myserver.com’,80);

// 2: CONSTRUCT THE REQUEST (AN XML-RPC MESSAGE)
$xmlrpc_msg = new xmlrpcmsg(‘nameOf.Method’,
array(new xmlrpcval(‘param1′,‘string’),new
xmlrpcval(2,‘int’)));

// 3: SEND THE REQUEST
$xmlrpc_resp $xmlrpc_client->send($xmlrpc_msg);
// 4: WORKING WITH THE SERVER’S RESPONSE
if ($xmlrpc_resp == False// check for successful transaction

die(‘error message’);

if (!$xmlrpc_resp->faultCode()) {
    // …
    }
 
Now let’s take a closer look at each step.

Step 1: Creating the Client

The client object is responsible for the sending and receiving of data from the XML-RPC server. A client object is created from the xmlrpc_client class and requires three pieces of
information:

  • The path to the script handling the XML-RPC requests
  • The hostname or IP address of the server
  • The port to make the connection on.

Beyond simply establishing connections and sending the XML-RPC data, the client object provides debugging and security support.

The debugging mode can be toggled on and off with the setDebug()method.

$xmlrpc_client->setDebug(1); // turn on debugging

When debugging mode is on, the client object will print out the HTTP response received from the server. This is useful for locating any low level I/O errors that may have occurred during a transaction between the client and the server.

Since XML-RPC uses HTTP as its transmission protocol, it also inherits the protocol’s security features. Basic HTTP user name and password authentication and HTTPS is supported. The setCredentials() method allows you to define a user name and password to be sent along with the XML data. The setCertificate() method allows you define a certificate to use to when establishing a connection over HTTPS.

Note: In order to use HTTPS your PHP must be compiled with CURL.

Step 2: Constructing the Request

The data going to, and coming from, an XML-RPC server are known as an XML-RPC message. To create an XML-RPC request message you need to create an instance of the xmlrpcmsg class.

To create an xmlrpcmsg object, you have to provide the name of the remote procedure you wish your run, and optionally a set of parameters for it to use.

Consider the following examples. The first example demonstrates a request message that calls a remote procedure without any parameters. The second example demonstrates how to include parameter data in the request message. When providing parameters during object initialization remember to provide them within an array, even if you only have one.

// create a message without any parameters

$msg_listCookies  = new xmlrpcmsg(‘cookie.List’);

// create a message with a parameter
$msg_cookieRating = new xmlrpcmsg(‘cookie.Rating’,
array(new xmlrpcval($cookieID,‘int’))); 

Parameters for the remote procedure do not have to be supplied during the initialization of the xmlrpcmsg object. You can use the addParam() method to add parameters after the object has been created.

All parameters added to the request object whether through the constructor or the addParam() method have to be encapsulated within an xmlrpcval object. (See the Working with xmlrpcval class section of this tutorial for information about working with that class.)

Step 3: Sending the request to the server

Once you have your client and message configured, you’re ready to send it off to the server. To send your request to the remote server, provide the send() method of your client object with your request message object.

For example:

$xmlrpc_resp =$xmlrpc_client->send($xmlrpc_msg);

The send() method will return one of two things, 0 (zero) if a low level I/O fault occurred, or an instance of the xmlrpcresp class if it was successful in communicating with the XML-RPC server.

Low level I/O faults usually occur when the client object could not connect to the XML-RPC server, could not send the request, or if the server returned a non XML-RPC related response. If a low level I/O fault occurs, turn on the client objects debugging mode to determine the exact cause of the problem.

Step 4: Working with server’s response

If the client object was able to complete a successful transaction with the
XML-RPC server it will return the server’s response encapsulated in an
xmlrpcresp object. If it was unable to complete a successful
transaction it will return a 0.

The xmlrpcresp instance will either be a normal response or a
fault report. Fault reports usually happen if the server was unable to
understand your request or there were server side problems. Thus it is important
to remember to check that the xmlrpcresp object returned by the

send() method is not a fault report.

The xmlrpcresp class provides two methods for checking if the
response is a fault report. The faultCode() method returns
the ID number assigned by the server for the fault returned or it will return 0
(zero) if no faults have occurred. The faultString() method will
return the description provided by the server on the fault that occurred.

Normal instances of xmlrpcresp will contain the data returned
from the remote procedure. You can access this data using the
value() method. The value() method returns the
server’s data encapsulated within an xmlprcval.

Working with the xmlrpcval class

The xmlrpcval class is the most used class in XML-RPC library and it is also the most complicated. The xmlrpcval class is used to encapsulate data into a form that the other classes in the library can easily work with.

Encapsulate scalar types in an xmlrpcval object isvery easy because it only requires a single value and type definition.

Consider the following examples:

// examples of scalar type xmlrpcval objects
$scalar_int = new xmlrpcval(1,'int');
$scalar_string = new xmlrpcval('1','string'); 
$scalar_dateTime = new
xmlrpcval('19791120T00:00:01','dateTime.iso8601');
$scalar_boolean = new xmlrpcval(1,'boolean');
$scalar_base64 = new
xmlrpcval($binaryData,'base64');
$type_swapping_1 = new xmlrpcval('123','int');  // this is fine
$type_swapping_2 = new xmlrpcval(123,'string'); // this is fine too

Since it is so easy to encapsulate scalar values, you should always do them manually. It is possible to create them using the library’s helper functions, but this is not recommended because you lose all the ability to define the type, and gain very little .

Using the above technique to encapsulate an array or struct is much more difficult, because you have to encapsulate each element within the complex type. For multi-dimensional arrays this usually results in a confusing mess of code.

Consider this example:

$multi_dimensional = new xmlrpcval(
array (
'first_name' => new
xmlrpcval('Benson','string'),
'last_name'  => new
xmlrpcval('Wong','string'),
    'age'        => new xmlrpcval(21,'int'),
    'hobbies'    => new xmlrpcval(
      array (
        new xmlrpcval('Programming','string'),
        new xmlrpcval('Martial Arts','string'),
        new xmlrpcval('Writing','string')
      ),'array')),'struct'); // Yikes!

Luckily, there are two helper functions that simplify the process of converting PHP variables to and from xlmrpcval encapsulated ones. They are xmlrpc_encode() and xmlrpc_decode(). Although these two functions work with any PHP variable, they are most useful when constructing the XML-RPC array and struct types.

Consider this example:

$multi_dimensional = array (
  'first_name' => 'Benson',
  'last_name'  => 'Wong',
  'age'        => 21,
  'hobbies'    => array ('Programming','Martial Arts','Writing')
 ); 
 $multi_dimensional_xmlrpc xmlrpc_encode($multi_dimensional);

The advantage of using xmlrpc_encode() over the manual process above is quite obvious. Now here is the catch: using xmlrpc_encode() does not create exactly the same object as the manual process above. What it creates is equivalent to:

$multi_dimensional = new xmlrpcval(
   array (
    'first_name' => new xmlrpcval('Benson','string'),
    'last_name'  => new xmlrpcval('Wong','string'),
    'age'        => new xmlrpcval(21,'int'),
    'hobbies'    => new xmlrpcval(
      array (
        => new xmlrpcval('Programming','string'),
        => new xmlrpcval('Martial Arts','string'),
        => new xmlrpcval('Writing','string')
      ),'struct')),'struct'); // see the difference ?

Notice that the simple indexed array ‘hobbies’ has been converted into a struct type instead of an array type. The xmlrpc_encode() function always converts all PHP arrays into struct types. This is a slight difference, but it could cause problems if an array type is expected. The other catch is that xmlrpc_encode() does not support the XML-RPC base64 and dateTime.iso8601 types.

The second helper function xmlrpc_decode() works the opposite of xmlrpc_encode. It takes an xmlrpcval object and coverts it into a native PHP variable. It doesn’t have the same limitations as xmlrpc_encode() since it is converting strongly typed data into a loosely typed PHP variable.

The Script

An XML-RPC server has been set up for you to experiment with. It is the same as that used in the example script below.

<?php

//  Name: XML-RPC Tutorial Script. 
//  Author: Benson Wong <benwong@tummytech.com>
//  Description: 
//  
//   This script is a demo of how to build an XML-RPC client in PHP.
//   It uses the XML-RPC library by Edd Dumbill and is available at:
//      http://phpxmlrpc.sourceforge.net/
//   
//   This script will connect to the Cookie Database server,
//   query it for data and construct the final HTML output.
//   
//   The Cookie Database server will be presented in the 
//   XML-RPC server tutorial.

require_once('xmlrpc.inc');

//  Initialize $Cookies as an empty Array. 
//  $Cookies will hold all the information available for each cookie. 
//     (CookieID, Name, Rating, Comments)
//  
//  It will be used later to create the HTML output.

$Cookies = Array(); 
 
//  GET A LIST OF THE AVAILABLE COOKIES ON THE XML-RPC SERVER
 
$cookieClient = new xmlrpc_client('/RPC/','www.tummytech.com',80);
$msg_listCookies  = new xmlrpcmsg('cookie.List');
$response $cookieClient->send($msg_listCookies);
if ($response == False)
     die('Unable to contact XML-RPC Server'); 
if (!$response->faultCode()) { // faults occured?
   // convert to a more usable PHP array
   $cookieList = xmlrpc_decode($response->value());
   foreach ($cookieList as $cookieID => $cookieName)
   {
   //  for each available cookie listed by the server grab it's
   //    a) Rating
   //    b) Comments
   //  
   //  and put the data into the $Cookies array. This is incredibly
   //  inefficient since it performs a lot of HTTP calls to grab each
   //  piece of data. Not recommended for use beyond this example.

     $Cookies[$cookieID]['name'] = $cookieName;

   // GET THE RATING FOR THE CURRENT COOKIE
   // Build XML-RPC Request for the Cookie's Rating

   $msg_cookieRating = new xmlrpcmsg('cookie.Rating',
   array(new xmlrpcval($cookieID,'int')));
          
   // Send the Message to the server
   $response = $cookieClient->send($msg_cookieRating);
   
  // Negative number If no rating found
  $Cookies[$cookieID]['rating'] = (!$response->faultCode()) ? 
            xmlrpc_decode($response->value()) : -1
   
 //  GET THE COMMENTS FOR THE CURRENT COOKIE

 // Build XML-RPC Request for the Cookie's Comments
 $msg_cookieComments = new xmlrpcmsg('cookie.Comments',
           array(new xmlrpcval($cookieID,'int')));

 // Send the Message to the server
 $response  = $cookieClient->send($msg_cookieComments);

 // Fill in the Comments for the Cookie
 $Cookies[$cookieID]['comments'] =
    (!$response->faultCode()) ? 
    xmlrpc_decode($response->value()) : 
     array(); // empty array for no Comments
 // END foreach ($cookieList as ...
 } else { // XML-RPC returned a fault...
 echo '<h1>An XML-RPC Fault Occured</h1>';
 printf('<b>Fault Code:</b>%s<br>',$response->faultCode());
 printf('<b>Fault Desc:</b>%s<br>',$response->faultString());
die();
}
//  GENERATE THE OUTPUT
?>

<html>
 <head>
   <title>The Delicious Cookie XML-RPC Example</title>
 </head>
 <body>
   <h1>Ben's Cookie Ratings XML-RPC Example</h1>
   <ol type="1">
   <?php 
   if (count($Cookies)) {
      foreach ($Cookies as $CookieData) 
      {
        printf('<font size="+2" color="#990000"><li> %s</font><br>',
               $CookieData['name']);
           
        // Output the cookie's rating if it exists
        if ($CookieData['rating'] != -1)
          printf('<b>Rating: %s/5.0</b><br>',$CookieData['rating']);
        
        // Output the cookie's comments if they exist
        if (count($CookieData['comments'])) {
           echo '<b>Comments:</b><ul>';
           foreach ($CookieData['comments'] as>$Comment)
                echo "<li> $Comment";
           echo '</ul>'; 
           }
      }
 } else {
   echo '<li> Darn No Cookies Found';
 }
?>
   </ol> 
 </body>
</html>

About the Author

Benson Wong is a programmer and a system administrator. As the head of Tummy
Tech’s technology development team, Benson is as comfortable deploying a
wireless WAN as he is building a database driven Web site. He can be reached at
benwong@tummytech.com.

,

2 Responses to “XML- RPC Client”

  1. maschek Says:

    use:
    php_xmlrpc_decode($xmlrpc_resp->value());

    to convert the response to php values

  2. _____anonymous_____ Says:

    hi
    tanx ,for your great article ,but i am a newbie to php ,would you plz explain a little about the method you call on the last script .
    for example what do you mean by this code:

    //start code
    $msg_listCookies = new xmlrpcmsg(‘cookie.List’);

    $response = $cookieClient->send($msg_listCookies);
    //end code

    does it mean i should have a page witch name is "cookie" and method witch name is "list"?