an xml rpc endpoint

(geek content:) Integrating the Incutio xml rpc class into a phpLinkDirectory install opens a lot of possibilities for running remote control automated networks. For a basic example I took the submit routine of phpLD and the xml-rpc routine from wordpress, deleted all nonsense, and ended up with a simple xml-rpc endpoint for my link directory.

On the sender side, I make an xml file that holds the methodName (which is the function I want to execute remotely : phpld.SubmitLink), and the array values I want to pass to the function as parameters. I attach the xml-string as post to a curl call and fire it at the xmlrpc endpoint.

  1. function getmyxml() {
  2.  
  3. //make the $data array
  4. //normally phpLd makes it when someone submits a site
  5.  $data['LINK_TYPE']=1;
  6.  $data['DESCRIPTION']='DESCRIPTION';
  7.  $data['TITLE']='TITLE';
  8.  $data['OWNER_NAME']='OWNER_NAME';
  9.  $data['URL']='http://www.domain.com/xmlrpc.php';
  10.  $data['ID']='';
  11.  
  12. //put the data array in an xml string to post to the xmlrpc endpoint
  13.  
  14. //make the xml header
  15.  $myxml='< ?xml version="1.0" encoding="UTF-8"?>';
  16.  $myxml.='< methodCall>';
  17.  $myxml.= '< methodName>phpld.SubmitLink< /methodName>';
  18.  $myxml.='< params>';
  19.  
  20. //loop to add the $data elements as param-tags
  21.  foreach($data as $d) {
  22.   $myxml.='< param>';
  23.   $myxml.='< value>< string>'.trim($d).'< /string>< /value>';
  24.   $myxml.='< /param>';
  25.  }
  26.  
  27. //finish the xml file :
  28.  $myxml.='< /params>';
  29.  $myxml.='< /methodCall>';
  30.  
  31. //return it
  32.  return $myxml;
  33. }
  34.  
  35. //make the call to the endpoint
  36.     $ch = curl_init('http://www.domain.com/xmlrpc.php');
  37. //use content-type text/xml as extra header
  38.     curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
  39. //get the xml-string and use it as post var
  40.     curl_setopt($ch, CURLOPT_POSTFIELDS, getmyxml());
  41.     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  42.     curl_setopt($ch, CURLOPT_TIMEOUT, 1);
  43.     $return = curl_exec($ch);
  44.     unset($ch);
  45. }

So much for the sending end, now the receiving end : the xmlrpc.php endpoint file. I need the Incutio xml handler and the phpLinkdirectory database class, with the proper settings, and a function SubmitLink to add the data in the posted xml-file as a record to the database.

Some general settings :

  1. define('XMLRPC_REQUEST', true);
  2. $_COOKIE = array();
  3. if ( !isset( $HTTP_RAW_POST_DATA ) ) $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
  4. if ( isset($HTTP_RAW_POST_DATA) )  $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);

I include the Incutio class file, which is a general xml client/server class, and I include init.php from the phpLD script. In the init.php script the AdoDb database instance is declared, that handles the mysql connection, as well as the basic phpLd environment.

  1. include_once('include/class-IXR.php');
  2. include_once('init.php');
  3. $xmlrpc_logging = 0;

Let’s put them both to work for me : the IXR_Server has to know it has to run the SubmitLink function if that function is set as methodName in the xml file. In php you can add methods dynamically to a class, and in the function call($methodname, $args) the IXR_Server handles callbacks.

In my phpLD_xmlrpc_server class, which extends IXR_Server, I add a function SubmitLink that stuffs the data in the phpld database, and I make an array with xml.methodName=>class:function as key=>value pair and pass that to the IXR_Server, that’s enough.

  1. class phpLD_xmlrpc_server extends IXR_Server {
  2.  
  3.  var $methods=array();
  4.  
  5.  function phpLD_xmlrpc_server() {
  6.  
  7. //mapping the custom methods
  8.     $this->methods['phpld.SubmitLink'] = 'this:SubmitLink';
  9.  
  10. //handing the custom methods to the base class
  11.     $this->IXR_Server($this->methods);
  12.  }

When the IXR class parses the posted xml and finds the phpld.SubmitLink methodName, it executes the custom method ($this->)SubmitLink with the data posted in the xml param tags as input :

  1.  
  2. function SubmitLink($params) {
  3.  
  4. //use db and tables from include(init.php)
  5.  global $db;
  6.  global $tables;
  7.  
  8. //map the param-values passed to the $data array
  9.  $data['LINK_TYPE']=$params[0];
  10.  $data['DESCRIPTION']=$params[1];
  11.  $data['TITLE']=$params[2];
  12.  $data['OWNER_NAME']=$params[3];
  13.  $data['URL']=$params[4];
  14.  $data['ID']='';
  15.  
  16. //pass the data array to the adodb $db instance's Replace function :
  17.   if ($db->Replace($tables['link']['name'], $data, 'ID', true) > 0) {
  18.    return $data['DESCRIPTION']." entered";
  19.   } else {
  20.    return " refused";
  21.   }
  22.  }

The AdoDb function Replace maps key-value to tablefield-value, so I use the database field names as keys for the $data array, and assign the $param-values to them. I pass the $data array to the adoDb function and that takes care of the rest.

After adding the includes, settings, and classes,
all I have to do is add a final call at the end to start a new instance of the extended class to handle the posted xml-data :

  1. $phpLD_xmlrpc_server = new phpLD_xmlrpc_server();

…and I have an xml-rpc endpoint :

  1. define('XMLRPC_REQUEST', true);
  2. $_COOKIE = array();
  3. if ( !isset( $HTTP_RAW_POST_DATA ) ) $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
  4. if ( isset($HTTP_RAW_POST_DATA) ) $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
  5.  
  6. include_once('include/class-IXR.php');
  7. include_once('init.php');
  8.  
  9. $xmlrpc_logging = 0;
  10.  
  11. class phpLD_xmlrpc_server extends IXR_Server {
  12.  
  13.  var $methods=array();
  14.  
  15.  function phpLD_xmlrpc_server() {
  16.     $this->methods['phpld.SubmitLink'] = 'this:SubmitLink';
  17.   $this->IXR_Server($this->methods);
  18.  }
  19.  
  20.  function SubmitLink($args) {
  21.  
  22.  global $db;
  23.  global $tables;
  24.  
  25.  $data['STATUS']         = $args[0];
  26.  $data['IPADDRESS']      = $args[1];
  27.  $data['VALID']          = $args[2];
  28.  $data['LINK_TYPE']      = $args[3];
  29.  
  30.   if ($db->Replace($tables['link']['name'], $data, 'ID', true) > 0) {
  31.    return $data['DESCRIPTION']." entered";
  32.   } else {
  33.    return " refused";
  34.   }
  35.  }
  36. }
  37. $phpLD_xmlrpc_server = new phpLD_xmlrpc_server();

Short and sweet.

The actual strength of xml-rpc is in defining a set of standard methodNames and parameters passed with the methodCall (for instance for small website maintenance tasks and statistics reporting, an rpc.sms protocol as successor to Twitter, or standard socialgraph functions for ajax/javascript/widgets) for developing standard API’s.

Posted in linkdir, php, xml-rpc and tagged , .

Leave a Reply

Your email address will not be published. Required fields are marked *