XML-RPC client class in PHP
I currently have a project that requires communicating with a 3rd party application server via XML-RPC. Having never worked with XML-RPC before I went looking for a PHP wrapper class that could help. Unfortunately I couldn’t find one so I had to write one from scratch. I have decided to publish it here for anyone else that needs to use XML-RPC in PHP and wants a tidy wrapper class to make life easier.
This class makes use of a fantastically powerful and dangerous ‘magic’ method named __call. What __call does is allows any inaccessible method to be overloaded. This means that when you instantiate the class, ANY method that is not accessible in the class will run through the __call method. Therefore it is possible to use this class to execute methods on the remote application server.
Enjoy
class xmlrpc_client {
private $url;
private $proto = 'http';
private $host;
private $fhost;
private $uri = '/';
private $port = 80;
private $method_pfx = '';
private $debug = false;
function __construct($url, $method_pfx = '', $debug = false){
$this->method_pfx = $method_pfx;
$this->debug = $debug;
if(preg_match('/(\w*):\/\/(.*?)(\/.*)/', $url, $matches)){
list($this->url, $this->proto, $this->host, $this->uri) = $matches;
switch($this->proto){
case 'http':
$this->port = 80;
$this->fhost = $this->host;
break;
case 'https':
$this->port = 443;
$this->fhost = 'ssl://' . $this->host;
break;
default:
$this->dbg("Unknown protocol '$this->proto'. Defaulting to port $this->port.");
return;
break;
}
$this->dbg("Correctly parse URL '$this->url'");
}else{
$this->dbg("Invalid URL supplied");
return;
}
}
private function dbg($string, $op_xml = null, $force = false){
if(!$force && !$this->debug) return;
echo "
$string
";
if($op_xml) echo "$op_xml";
}
private function notice($string, $op_xml = false){
return $this->dbg($string, $op_xml, true);
}
public function __call($name, $args){
if(!$this->fhost && !$this->port && !$this->uri){
$this->dbg('No host, port or URI has been specified');
return;
}
$method = ($this->method_pfx?$this->method_pfx . '.':'') . $name;
$response = '';
$this->dbg("Generating request for method '$method'");
$output = array('version' => 'xmlrpc');
$request = xmlrpc_encode_request($method, $args, $output);
$this->dbg("opening socket to host: $this->fhost, port: $this->port, uri: $this->uri");
$sck_fd = fsockopen($this->fhost, $this->port, $errno, $errstr, 3);
if($sck_fd){
$content_len = strlen($request);
$http_request =
"POST $this->url HTTP/1.0\r\n" .
"User-Agent: xmlrpc-epi-php/0.2 (PHP)\r\n" .
"Host: $this->host\r\n" .
"Content-Type: text/xml\r\n" .
"Content-Length: $content_len\r\n" .
"\r\n" . $request;
$this->dbg("Sending HTTP request:", $http_request);
fputs($sck_fd, $http_request, strlen($http_request));
$this->dbg('Receiving response');
$header_parsed = false;
$line = fgets($sck_fd, 4096);
while ($line) {
if(!$header_parsed){
if($line === "\r\n" || $line === "\n"){
$this->dbg('Got header:', $header);
$header_parsed = 1;
}else{
$header .= $line;
}
}else{
$response_buf .= $line;
}
$line = fgets($sck_fd, 4096);
}
fclose($sck_fd);
$this->dbg('Reponse:', $response_buf);
$response = xmlrpc_decode($response_buf);
if((is_array($response)?xmlrpc_is_fault($response):false)){
$this->notice("Error #$response[faultCode] - $response[faultString]");
$response = null;
}
}else{
$this->dbg("Unable to open socket. ERR: $errno# - $errstr");
}
return $response;
}
}
Please provide a brief tutorial on how to use your class to complete the post.
Sure. Here ya go.
$x = new xmlrpc_client("http://xml.canihaveaclueplease.com");
$x->spoonFeedMeBecauseImStupid();
Easy, isn’t it. Almost like you didn’t really need to ask….