Skip to content

Instantly share code, notes, and snippets.

@decodedmrq
Forked from hofmeister/xmlrpc.php
Created July 7, 2021 18:19
Show Gist options
  • Save decodedmrq/7f333f3ace1fc03d5cbfb64daf40106e to your computer and use it in GitHub Desktop.
Save decodedmrq/7f333f3ace1fc03d5cbfb64daf40106e to your computer and use it in GitHub Desktop.

Revisions

  1. @hofmeister hofmeister created this gist Feb 12, 2012.
    298 changes: 298 additions & 0 deletions xmlrpc.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,298 @@
    <?php
    /**
    * @author Henrik Hofmeister
    * @license MIT
    * @version 1.0
    *
    * XmlRPC using SimpleXML and CURL
    *
    * Usage:
    *
    * $xmlRpc = new XmlRPC('localhost','/service/xmlrpc');
    * $xmlRpc->setCredentials('username','password');
    * $xmlRpc->setDebug(true);
    * $output = $xmlRpc->complexCall(array(
    * (object)array('id'=>'someid','name'=>'some name'),
    * (object)array('id'=>'otherId','name'=>'other name','properties'=>(object)array('active'=>true,'visits'=>2343)),
    * ));
    *
    *
    */

    class XmlRPC {
    private $host;
    private $path;
    private $connection;
    private $debug = false;
    private $user;
    private $pass;

    public function __construct($host,$path) {
    $this->host = $host;
    $this->path = $path;
    }
    public function setHost($host) {
    $this->disconnect();
    $this->host = $host;
    }
    public function setCredentials($user,$pass) {
    $this->user = $user;
    $this->pass = $pass;
    }
    public function setDebug($debug) {
    $this->debug = $debug;
    }

    public function call($methodName) {
    $args = func_get_args();
    array_shift($args);
    $request = $this->encodeRequest($methodName,$args);
    if ($this->debug) {
    echo "REQUEST:\n$request\n\n";
    }
    $conn = $this->getConnection();
    curl_setopt($conn, CURLOPT_RETURNTRANSFER, 1);

    if($this->debug)
    {
    curl_setopt($conn, CURLOPT_VERBOSE, 1);
    }
    curl_setopt($conn, CURLOPT_USERAGENT,'PHP XML-RPC Client');
    curl_setopt($conn, CURLOPT_POST, 1);
    curl_setopt($conn, CURLOPT_POSTFIELDS, $request);
    //curl_setopt($conn, CURLOPT_HEADER, 1);
    if ($this->user)
    curl_setopt($conn, CURLOPT_USERPWD,$this->user.':'.$this->pass);

    $response = curl_exec($conn);

    if ($this->debug) {
    echo "CURL INFO:\n";
    foreach(curl_getinfo($conn) as $name => $val) {
    if (is_array($val))
    $val = implode(', ',$val);
    echo $name . ': ' . htmlentities($val). "\n";
    }
    echo "\n\nRESPONSE:\n$response";
    }
    $httpCode = curl_getinfo($conn,CURLINFO_HTTP_CODE);
    if ($httpCode != 200) {
    if ($httpCode == 401)
    throw new XmlRPC_Exception("Invalid user name or password - authentication failed",9999);
    else
    throw new XmlRPC_Exception("Server replied with an error code: $httpCode",9999);
    }
    if (empty($response)) {
    throw new XmlRPC_Exception('Empty response from server at: '.$this->getUrl(),9999);
    }

    $result = $this->parseResponse($response);
    return $result;
    }
    public function __call($name, $arguments) {
    array_unshift($arguments,$name);
    return call_user_method_array('call',$this,$arguments);
    }

    private function encodeRequest($methodName,$args) {
    $req = '<?xml version="1.0" encoding="UTF-8" ?>';
    $params = '';
    foreach($args as $arg) {
    $parm = XmlRPC_Parm::encode($arg);
    $params .= sprintf('<param><value>%s</value></param>',$parm);
    }
    $req .= "\n<methodCall><methodName>$methodName</methodName><params>$params</params></methodCall>";
    return $req;
    }
    private function parseResponse($xmlStr) {
    $xml = simplexml_load_string(trim($xmlStr));
    $response = array();

    if (count($xml->fault) > 0) {
    //An error was returned
    $fault = $this->parseValue($xml->fault->value);
    throw new XmlRPC_Exception($fault->faultString,$fault->faultCode);
    }

    if (count($xml->params->param) == 1)
    $scalar = true;

    foreach($xml->params->param as $param) {
    $valueStruct = $param->value;

    $value = $this->parseValue($valueStruct);
    if ($scalar)
    return $value;
    else
    $response[] = $value;
    }
    return $response;
    }
    private function parseValue($valueStruct) {
    switch(true) {
    case count($valueStruct->struct) > 0:
    $value = new stdClass();
    foreach($valueStruct->struct->member as $member) {
    $name = (string)$member->name;
    $memberValue = $this->parseValue($member->value);
    $value->$name = $memberValue;
    }
    return $value;
    break;
    case count($valueStruct->array) > 0:
    $value = array();
    foreach($valueStruct->array->data->value as $arrayValue) {
    $value[] = $this->parseValue($arrayValue);
    }
    return $value;
    break;
    case count($valueStruct->i4) > 0:
    return (int)$valueStruct->i4;
    case count($valueStruct->int) > 0:
    return (int)$valueStruct->int;
    case count($valueStruct->boolean) > 0:
    return (boolean) $valueStruct->boolean;
    case count($valueStruct->string) > 0:
    return (string)$valueStruct->string;
    case count($valueStruct->double) > 0:
    return (double)$valueStruct->double;
    case count($valueStruct->dateTime) > 0:
    return (string)$valueStruct->dateTime;
    case count($valueStruct->base64) > 0:
    return (string)$valueStruct->base64;
    }
    }
    private function disconnect() {
    if ($this->connection)
    @curl_close($this->connection);
    $this->connection = null;
    }
    protected function getUrl() {
    return sprintf('http://%s%s',$this->host,$this->path);
    }
    private function getConnection() {
    if (!$this->connection)
    $this->connection = curl_init($this->getUrl());
    return $this->connection;
    }
    public function __destruct() {
    $this->disconnect();
    }
    }
    class XmlRPC_Exception extends Exception {
    public function __construct($message, $code) {
    parent::__construct($message, $code);
    }
    }
    /* PARMS */
    class XmlRPC_Parm {
    private $value;

    public function __construct($value) {
    $this->value = $value;
    }
    public function getType() {
    switch(true) {
    case is_bool($arg):
    return 'boolean';
    case is_int($arg):
    return 'int';
    case is_float($arg):
    case is_double($arg):
    return 'double';
    break;
    case is_object($arg):
    return 'struct';
    case is_bool($arg):
    return 'boolean';
    case is_array($arg):
    return 'array';
    default:
    case is_string($arg):
    return 'string';
    break;
    }
    }
    public function getValue() {
    return $this->value;
    }
    protected function getFormattedValue() {
    return $this->value;
    }

    public function __toString() {
    return sprintf('<%1$s>%2$s</%1$s>',$this->getType(),$this->getFormattedValue());
    }
    /**
    *
    * @param mixed $arg
    * @return XmlRPC_Parm
    */
    public static function encode($arg) {
    switch(true) {
    case $arg instanceof XmlRPC_Parm:
    return $arg;
    case is_object($arg):
    return new XmlRPC_Struct($arg);
    case is_array($arg):
    return new XmlRPC_Array($arg);
    default:
    case is_bool($arg):
    case is_int($arg):
    case is_float($arg):
    case is_double($arg):
    case is_string($arg):
    return new XmlRPC_Parm($arg);
    }
    }
    public static function decode($param) {

    }
    }
    class XmlRPC_Struct extends XmlRPC_Parm{

    protected function getFormattedValue() {
    $result = '';
    foreach($this->getValue() as $name=>$value) {
    $parm = XmlRPC_Parm::encode($value);
    $result .= sprintf('<member><name>%s</name><value>%s</value></member>',$name,$parm);
    }
    return $result;
    }
    public function getType() {
    return 'struct';
    }
    }

    class XmlRPC_Array extends XmlRPC_Parm{

    protected function getFormattedValue() {
    $result = '<data>';
    foreach($this->getValue() as $value) {
    $parm = XmlRPC_Parm::encode($value);
    $result .= sprintf('<value>%s</value>',$parm);
    }
    return $result.'</data>';
    }
    public function getType() {
    return 'array';
    }
    }
    class XmlRPC_Date extends XmlRPC_Parm{

    protected function getFormattedValue() {
    return date('Ymd\TH:i:s',parent::getFormattedValue());
    }
    public function getType() {
    return 'dateTime.iso8601';
    }
    }
    class XmlRPC_Binary extends XmlRPC_Parm{

    protected function getFormattedValue() {
    return base64_encode(parent::getFormattedValue());
    }
    public function getType() {
    return 'base64';
    }
    }