My mail management system (currently codenamed NVMS) is in the backend managing userdb, and the web interface is currently written in PHP. XML-RPC seemed the sensible thing to use, as it is simple and portable, Python and Twisted has excellent and easy-to-use support, and I knew PHP could do it. (Well, not without getting sidetracked to determine which XML-RPC library to use for PHP.) I settled on PEAR's XML_RPC. It's nowhere near as braindeadly simple and nice as Python's xmlrpclib (and Twisted's XML-RPC server support), so here's something I used to make PEAR's XML_RPC slightly easier to work with, and an example of how it works on the other side with Twisted.

<?php

require_once('XML/RPC.php');

class NVMSXmlrpc {
    function sendMsg($method) {
        global $_VNMS_Xmlrpc_client;
        $args = array_slice(func_get_args(), 1);
        if (count($args) === 0) {
            $m = new XML_RPC_Message($method);
        } else {
            $de = array();
            foreach($args as $arg) {
                $de[] = XML_RPC_encode($arg);
            }
            //$de = array(XML_RPC_encode($args));
            // var_dump($de);
            $m = new XML_RPC_Message($method, $de);
        }
        $resp = $_VNMS_Xmlrpc_client->send($m);
        if ($resp->faultCode()) {
            return PEAR::raiseError('Fault ' . $resp->faultCode() . ': ' .  $resp->faultString());
        } else {
            return XML_RPC_decode($resp->value());
        }
    }
}

$_VNMS_Xmlrpc_client = new XML_RPC_Client('/', 'localhost', 9680);

?>

Here's a simple example:

<?php

require_once('nvms.xmlrpc.php');
var_dump(NVMSXmlrpc::sendMsg('test2', array('foo', 'bar'), 3));

?>

This example can talk to a simple Twisted XML-RPC server (way too easy...):

#!/usr/bin/env python

import sys

from twisted.web import server, xmlrpc
from twisted.application import internet
from twisted.internet import reactor

class Example(xmlrpc.XMLRPC):
    def xmlrpc_test2(self, arg1, arg2):
        return ['s', arg1, 's', arg2, 's']

def main(argv = sys.argv):
    w = server.Site(Example())
    internet.TCPServer(9680, w, interface='127.0.0.1')
    reactor.run()

if __name__ == '__main__':
    main()

The output of the PHP tester is:

array(5) {
  [0]=>
  string(1) "s"
  [1]=>
  array(2) {
    [1]=>
    string(3) "bar"
    [0]=>
    string(3) "foo"
  }
  [2]=>
  string(1) "s"
  [3]=>
  int(3)
  [4]=>
  string(1) "s"
}