XML-RPC

This is simply a copy of my old XML-RPC article (2005). I’ve done a bit of content editing when converting the article to this blog format, but still most of the content is unchanged.

1. Introduction

So you’ve decided to learn XML-RPC[1], or did the name just sound “freaky” and raised a little interest? If it did I suggest you read on, if you already know what XML-RPC is, then just skip the next intro part

1.1 What is XML-RPC

XML-RPC is a way to make web services, it packs the requests and responses in XML both the client and the server can understand.
For those who don’t know a web service is a function of some sort placed on the net (it could be a function to convert a string into all upper case letters, which we are going to make in the examples below). The smart thing is that, a web service can be programmed in any kind of language, and any other language can use it. Many big sites have a web service, for example Amazon has a web service that allows you to search books and information.
Another smart thing about XML-RPC (and to my knowledge all other web services), is that they can be run from a web server. Not only is this smart, because you don’t need to install some high-end server dedicated to the purpose. But you don’t have to worry about firewalls.

1.2 Installing XML-RPC

If you’ve installed an extension before, this should be no problem at all, just install the XML-RPC extension. But if this is your first time, the following links will help a bit:
Windows users: http://www.php.net/manual/en/install.windows.extensions.php
Unix users: http://www.php.net/manual/en/install.unix.php
OS X users: http://www.php.net/manual/en/install.macosx.php
For you guys(and gals) who compile PHP: –with-xmlrpc.

2. The Server

For obviusly reasons we start making the server, which contains the function our client will be calling later on.
I’ve decided to comment the code, this way I don’t have to explain it to you after you’ve read it. And you can by remember what it all does later on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?php
/*****
 * We start witht the functions we wan't to be web services.
 * Each of them must have 3 arguments:
 * 1st: This is the method name, which the client requests.
 * 2nd: This one is the arguments, which the client sends with the request.
 * 3rd: This data is specified by the server it self.
 *****/
function xmlEcho($method, $args, $appData)
{
    return 'Come again: '. $args[0];
}
 
// Just for the fun of it, let's make 2 function:
function xmlAllToUpper($method, $args, $appData)
{
    for ($i = 0; $i < count($args); $i++) {
        $args[$i] = strToUpper($args[$i]);
    }
 
    return $args;
}
 
 
/*****
 * Next up we'll assign the XML-RPC server handle to a variable.
 * I've chosen this "sneaky" name: $xmlServer * But you can think of this
 * as any other handle, for example, when you're working with a database, 
 * you have the connection handle, it's the same thing.
 *****/
$xmlServer = xmlrpc_server_create();
 
 
/*****
 * Now that's done it's time to tell the server which functions the
 * client can request. This is done with the xmlrpc_server_register_method
 * function (why can't they come up with some short names!). This function
 * requires 3 arguments:
 * 1st: The server handle, we just specified above.
 * 2nd: The function name, which the client calls.
 * 3rd: The function name, to run.
 *
 * This means that your function dosn't have to be named the same as the
 * function the client calls.
 *****/
xmlrpc_server_register_method($server, 'echo', 'xmlEcho');
xmlrpc_server_register_method($server, 'goLarge', 'xmlAllToUpper');
 
 
/*****
 * We need to get what ever request the client send us.
 * This is done with the $HTTP_RAW_POST_DATA variable. Nothing more
 * to say about that, so I'll just give you yet another dumb ass
 * comment ... That was it.
 *****/
$xmlRequest = $HTTP_RAW_POST_DATA;
 
 
/*****
 * We have all we need now, for the server to call the function, the
 * client requested.
 * To call this function, we use this (again rediculesly long) function:
 * xmlrpc_server_call_method, which as always take 3 arguments:
 * 1st: The server handle.
 * 2nd: The client request we just got above.
 * 3rd: What ever data you (as the server) want to send, this
 *      will be passed into the $appData variable.
 *****/
$xmlResponse = xmlrpc_server_call_method($xmlServer, $xmlRequest, NULL);
 
// Prepare the header contents so it sends XML
header('Content-Type: text/xml');
 
echo $xmlResponse;
 
xmlrpc_server_destroy($xmlServer);
?>

All done with the server part. If you haven’t figured out exactly how the server works yet, then let me give you a little insight. In short terms, it’s just a php file, that is called by the client, through a normal URL. It then processes the contents which the client send, and return a result.

3. The Client

Well you made it so far, so why not make the client to test your server as well. Even though we made the server first, I must admit you’ll probably be using the client part a “wee” bit more. Of course it’s fun to mess around with the server, but chances are you’ll be using other webservices most of the time?
Anyway, as you might notice, the client code contains a little socket[2] programming. If you’ve never worked with sockets before don’t think to much of it, it’s not that hard, and you’ll propably pick up the on the code anyway.
When I wrote this article I had no idea of the cURL library, which I would propably be using for an actual project instead of my own request function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
/*****
 * First off we'll be making a function, to send our request to the
 * server.
 * This is where the feared socket programming makes it appearence,
 * take a notice at the default value for port, some people have
 * (for reasons only god may know).
 *****/
function sendRequest($host, $url, $request, $port = 80)
{
    // First off we open a connection to the server.
    if ( !$sock = fsockopen($host, $port, $errNo, $errString) ) {
        echo 'Error: '. $errNo . ' - '. $errString;
        return FALSE;
    }
 
    /*****
     * We prepare the HTTP header, in our request.
     * Notice we set the Content-Type to text/xml (just notice...).
     *****/
    $httpQuery = "POST ". $url ." HTTP/1.0\n";
    $httpQuery .= "User-Agent: xmlrpc\n";
    $httpQuery .= "Host: ". $host ."\n";
    $httpQuery .= "Content-Type: text/xml\n";
    $httpQuery .= "Content-Length: ". strlen($request) ."\n\n";
    $httpQuery .= $request ."\n";
 
    // Here we send the request to the server
    if ( !fwrite($sock, $httpQuery, strlen($httpQuery)) ) {
        echo 'Error while trying to send request';
        return FALSE;
    }
 
    // We get the response from the server
    while ( !feof($sock) ) {
        $xmlResponse .= fgets($sock);
    }
 
    // Closing the connection
    fclose($sock);
 
    // We strip the response from it's HTTP header
    $xmlResponse = substr($xmlResponse, strpos($xmlResponse, "\r\n\r\n") +4);
 
    /*****
     * To decode the XML into PHP, we use the (finaly a short function)
     * xmlrpc_decode function. And that should've done the trick.
     * We now have what ever the server function made in our $xmlRespnse
     * variable.
     *****/
    $xmlResponse = xmlrpc_decode($xmlResponse);
 
    // Returns the result.
    return $response;
}
 
/*****
 * The first thing we do, is encoding our request into an XML-RPC
 * string. This is done with the xmlrpc_encode_request function, which 
 * accepts 2 arguments:
 * 1st: Name of the function we wish to call from the server.
 * 2nd: The argument we want to parse into this function. If we
 *      wish to parse more than 1 argument, we put them into an array.
 *****/
$xmlRequest = xmlrpc_encode_request('echo', 'All hail Philip the almighty... Obey!');
 
/*****
 * Now we call the sendRequest function, with our XML request. Remember
 * to change the host if you're not on a local computer or what ever you use.
 * And remember to change the path, if you've not saved the server directly in
 * the root (which I suspect you havent). If you hav it in the "articles/php"
 * subdirectory, you use "/articles/php/xml_server.php"
 *****/
$xmlResponse = sendRequest('127.0.0.1', '/xmlrpc_server.php', $xmlRequest);
 
// And at last, we print out the response!
var_dump($xmlResponse);
?>
The response from the serverstring(49) “Come again: All hail Philip the almighty… Obey!”

Hey, now wasn’t that funny! Ya I bet it was … Anyway let’s take one last example just to try out all of our functions. This time we parse more than one argument with the request, just to get the whole picture:

1
2
3
4
5
6
7
<?php
$xmlRequest = xmlrpc_encode_request('goLarge', array(1234, 'little', '1 small step'));
 
$xmlResponse = sendRequest('127.0.0.1', '/xmlrpc_server.php', $xmlRequest);
 
var_dump($xmlResponse);
?>
goLarge outputarray(3) {
[0]=>
string(4) “1234″
[1]=>
string(6) “LITTLE”
[2]=>
string(12) “1 SMALL STEP”
}

Well I don’t realy know how to explain this any better, so I guess all the practical stuff ends here.

4. Theory

I’ve chosen to place this section at the end of the article, because it’s just a little extra on how XML-RPC works underneath. And let me just tell you, that I quickly go through this, if you want more detailed information try the XML-RPC Specification[3], which will go more in depth.

4.1 Request

I’ll start by pasting in our own request to the server (the echo request we made in the example above), leaving out the headers:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="iso-8859-1"?>
<methodCall>
  <methodName>echo</methodName>
  <params>
   <param>
    <value>
     <string>All hail Philip the almighty... Obey!</string>
    </value>
   </param>
  </params>
</methodCall>

It’s pretty straight forward, the first thing we do is state that we would like to call a function <methodCall>.
We then tell the server which function we’re calling <methodName>, this is followed by out list of parameters.
A <params> can have any number of <param>, which each holds a <value>. In our case this value is a string (<string>), but it can be any one of XML-RPCs 5 supported data types:

Tag Type Example
<i4> or <int> four-byte signed integer -12
<boolean> 0(false) or 1(true) 1
<string> string hello world
<double> double-precision signed floating point number -12.214
<dateTime.iso8601> date/time 19980717T14:08:55
<base64> base64-encoded binary eW91IGNhbid0IHJlYWQgdGhpcyE=

XML-RPC also supports arrays and structures, but you’ll have to read about them in the XML specs.

4.2 Response

Again I’ve stripped the HTML header from the server response:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="iso-8859-1"?>
<methodResponse>
  <params>
    <param>
      <value>
        <string>Come again: All hail Philip the almighty... Obey!</string>
      </value>
    </param>
  </params>
</methodResponse>

Like with the request, this is rather understandable, so I wont add anything to this.
Sometimes an error happens, you might have supplied to many arguments, or you might misspelled a function so the server can’t find it. When this happen the server will return a fault code. I’ve (besides stolen the idea of showing this fault code here from the XML-RPC Specs) chosen to give you an example on a fault code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="iso-8859-1"?>
<methodResponse>
  <fault>
    <value>
      <struct>
        <member>
          <name>faultString</name>
          <value>
            <string>server error. method not found.&#10;&#10;echos</string>
          </value>
        </member>
        <member>
          <name>faultCode</name>
          <value>
            <int>-32601</int>
          </value>
        </member>
      </struct>
    </value>
  </fault>
</methodResponse>

Again, it’s easy to understand, but this shows the <struct> and how it works.

Conclusion

To be honest I don’t really know what to make of all this, except that it works like a charm. If you compare the XML-RPC protocol to some of the other web service protocols you can find “out there”, you’ll find that the difference is small. Some are a little bit more advanced, some are more compact, others are exactly the same and some are useless.
Finding the right web service, is all about what you like to work with, my personal favorit is XML-RPC (hence this article). So my suggestion is try some of the other big web services, and find the one you’re most comfortable with, and then stick with it!
Honestly I haven’t used XML-RPC since I wrote this article. And if I should make a service available, I would first search through any new alternatives, and find a solution that would fit my problem.

a. sources

[1] http://www.xmlrpc.com
[2] http://dk.php.net/manual/en/function.fsockopen.php
[3] http://www.xmlrpc.com/spec

Leave a comment

0 Comments.

Leave a Reply

[ Ctrl + Enter ]