From 9fb0a7a7a32d9f7e8b8a591ca9053168068da16d Mon Sep 17 00:00:00 2001 From: marcus Date: Mon, 16 Jun 2008 12:40:48 +0000 Subject: CLOSED - #14: XML-RPC handler http://trac.elgg.org/elgg/ticket/14 git-svn-id: https://code.elgg.org/elgg/trunk@930 36083f99-b078-4883-b0ff-0f9b5a30f544 --- engine/lib/xml-rpc.php | 510 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 engine/lib/xml-rpc.php (limited to 'engine/lib') diff --git a/engine/lib/xml-rpc.php b/engine/lib/xml-rpc.php new file mode 100644 index 000000000..d6a391fce --- /dev/null +++ b/engine/lib/xml-rpc.php @@ -0,0 +1,510 @@ +parse($xml); + } + + /** + * Return the method name associated with the call. + * + * @return string + */ + public function getMethodName() { return $this->methodname; } + + /** + * Return the parameters. + * Returns a nested array of XmlElement. + * + * @see XmlElement + * @return array + */ + public function getParameters() { return $this->params; } + + /** + * Parse the xml into its components according to spec. + * This first version is a little primitive. + * + * @param string $xml + */ + private function parse($xml) + { + $xml = xml_2_object($xml); + + // sanity check + if ((isset($xml->name)) && (strcasecmp($xml->name, "methodCall")!=0)) + throw new CallException(elgg_echo('CallException:NotRPCCall')); + + // method name + $this->methodname = $xml->children[0]->content; + + // parameters + $this->params = $xml->children[1]->children; + + print_r($this); + } + } + + // Response classes /////////////////////////////////////////////////////////////////////// + + /** + * @class XMLRPCParameter Superclass for all RPC parameters. + * @author Marcus Povey + */ + abstract class XMLRPCParameter + { + protected $value; + + function __construct() { } + + } + + /** + * @class XMLRPCIntParameter An Integer. + * @author Marcus Povey + */ + class XMLRPCIntParameter extends XMLRPCParameter + { + function __construct($value) + { + parent::__construct(); + + $this->value = (int)$value; + } + + function __toString() + { + return "{$this->value}\n"; + } + } + + /** + * @class XMLRPCBoolParameter A boolean. + * @author Marcus Povey + */ + class XMLRPCBoolParameter extends XMLRPCParameter + { + function __construct($value) + { + parent::__construct(); + + $this->value = (bool)$value; + } + + function __toString() + { + $code = ($this->value) ? "1" : "0"; + return "{$code}\n"; + } + } + + /** + * @class XMLRPCStringParameter A string. + * @author Marcus Povey + */ + class XMLRPCStringParameter extends XMLRPCParameter + { + function __construct($value) + { + parent::__construct(); + + $this->value = $value; + } + + function __toString() + { + $value = htmlentities($this->value); + return "{$value}\n"; + } + } + + /** + * @class XMLRPCDoubleParameter A double precision signed floating point number. + * @author Marcus Povey + */ + class XMLRPCDoubleParameter extends XMLRPCParameter + { + function __construct($value) + { + parent::__construct(); + + $this->value = (float)$value; + } + + function __toString() + { + return "{$this->value}\n"; + } + } + + /** + * @class XMLRPCDateParameter An ISO8601 data and time. + * @author Marcus Povey + */ + class XMLRPCDateParameter extends XMLRPCParameter + { + /** + * Construct a date + * + * @param int $timestamp The unix timestamp, or blank for "now". + */ + function __construct($timestamp = 0) + { + parent::__construct(); + + $this->value = $timestamp; + if (!$timestamp) + $this->value = time(); + } + + function __toString() + { + $value = date('c', $this->value); + return "{$value}\n"; + } + } + + /** + * @class XMLRPCBase64Parameter A base 64 encoded blob of binary. + * @author Marcus Povey + */ + class XMLRPCBase64Parameter extends XMLRPCParameter + { + /** + * Construct a base64 encoded block + * + * @param string $blob Unencoded binary blob + */ + function __construct($blob) + { + parent::__construct(); + + $this->value = base64_encode($blob); + } + + function __toString() + { + return "{$value}\n"; + } + } + + /** + * @class XMLRPCStructParameter A structure containing other XMLRPCParameter objects. + * @author Marcus Povey + */ + class XMLRPCStructParameter extends XMLRPCParameter + { + /** + * Construct a struct. + * + * @param array $parameters Optional associated array of parameters, if not provided then addField must be used. + */ + function __construct($parameters = NULL) + { + parent::__construct(); + + if (is_array($parameters)) + { + foreach ($parameters as $k => $v) + $this->addField($k, $v); + } + } + + /** + * Add a field to the container. + * + * @param string $name The name of the field. + * @param XMLRPCParameter $value The value. + */ + public function addField($name, XMLRPCParameter $value) + { + if (!is_array($this->value)) + $this->value = array(); + + $this->value[$name] = $value; + } + + function __toString() + { + $params = ""; + foreach ($this->value as $k => $v) + { + $params .= "$k$v"; + } + + return <<< END + + $params + +END; + } + } + + /** + * @class XMLRPCArrayParameter An array containing other XMLRPCParameter objects. + * @author Marcus Povey + */ + class XMLRPCArrayParameter extends XMLRPCParameter + { + /** + * Construct an array. + * + * @param array $parameters Optional array of parameters, if not provided then addField must be used. + */ + function __construct($parameters = NULL) + { + parent::__construct(); + + if (is_array($parameters)) + { + foreach ($parameters as $v) + $this->addField($v); + } + } + + /** + * Add a field to the container. + * + * @param XMLRPCParameter $value The value. + */ + public function addField(XMLRPCParameter $value) + { + if (!is_array($this->value)) + $this->value = array(); + + $this->value[] = $value; + } + + function __toString() + { + $params = ""; + foreach ($this->value as $value) + { + $params .= "$value"; + } + + return <<< END + + + $params + + +END; + } + } + + /** + * @class XMLRPCResponse XML-RPC Response. + * @author Marcus Povey + */ + abstract class XMLRPCResponse + { + /** An array of parameters */ + protected $parameters = array(); + + /** + * Add a parameter here. + * + * @param XMLRPCParameter $param The parameter. + */ + public function addParameter(XMLRPCParameter $param) + { + if (!is_array($this->parameters)) + $this->parameters = array(); + + $this->parameters[] = $param; + } + + public function addInt($value) { $this->addParameter(new XMLRPCIntParameter($value)); } + public function addString($value) { $this->addParameter(new XMLRPCStringParameter($value)); } + public function addDouble($value) { $this->addParameter(new XMLRPCDoubleParameter($value)); } + public function addBoolean($value) { $this->addParameter(new XMLRPCBoolParameter($value)); } + } + + /** + * @class XMLRPCSuccessResponse + * @author Marcus Povey + */ + class XMLRPCSuccessResponse extends XMLRPCResponse + { + /** + * Output to XML. + */ + public function __toString() + { + $params = ""; + foreach ($this->parameters as $param) + $params .= "$param\n"; + + return <<< END + + + $params + + +END; + } + } + + /** + * @class XMLRPCErrorResponse + * @author Marcus Povey + */ + class XMLRPCErrorResponse extends XMLRPCResponse + { + /** + * Set the error response and error code. + * + * @param string $message The message + * @param int $code Error code (default = system error as defined by http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php) + */ + function __construct($message, $code = -32400) + { + $this->addParameter( + new XMLRPCStructParameter( + array ( + 'faultCode' => new XMLRPCIntParameter($code), + 'faultString' => new XMLRPCStringParameter($message) + ) + ) + ); + } + + /** + * Output to XML. + */ + public function __toString() + { + return <<< END + + + + {$this->parameters[0]} + + + +END; + } + } + + // Functions for adding handlers ////////////////////////////////////////////////////////// + + /** XML-RPC Handlers */ + $XML_RPC_HANDLERS = array(); + + /** + * Register a method handler for a given XML-RPC method. + * + * @param string $method Method parameter. + * @param string $handler The handler function. This function accepts once XMLRPCCall object and must return a XMLRPCResponse object. + * @return bool + */ + function register_xmlrpc_handler($method, $handler) + { + global $XML_RPC_HANDLERS; + + $XML_RPC_HANDLERS['$method'] = $handler; + } + + /** + * Trigger a method call and pass the relevant parameters to the funciton. + * + * @param XMLRPCCall $parameters The call and parameters. + * @return XMLRPCCall + */ + function trigger_xmlrpc_handler(XMLRPCCall $parameters) + { + global $XML_RPC_HANDLERS; + + // Go through and see if we have a handler + if (isset($XML_RPC_HANDLERS[$parameters->getMethodName()])) + { + $result = $handler($parameters); + + if (!($result instanceof XMLRPCResponse)) + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnexpectedReturnFormat')); + + // Result in right format, return it. + return $result; + } + + // if no handler then throw exception + throw new NotImplementedException(sprintf(elgg_echo('NotImplementedException:XMLRPCMethodNotImplemented'), $method)); + } + + // Error handler functions //////////////////////////////////////////////////////////////// + + /** + * PHP Error handler function. + * This function acts as a wrapper to catch and report PHP error messages. + * + * @see http://uk3.php.net/set-error-handler + * @param unknown_type $errno + * @param unknown_type $errmsg + * @param unknown_type $filename + * @param unknown_type $linenum + * @param unknown_type $vars + */ + function __php_xmlrpc_error_handler($errno, $errmsg, $filename, $linenum, $vars) + { + $error = date("Y-m-d H:i:s (T)") . ": \"" . $errmsg . "\" in file " . $filename . " (line " . $linenum . ")"; + + switch ($errno) { + case E_USER_ERROR: + error_log("ERROR: " . $error); + + // Since this is a fatal error, we want to stop any further execution but do so gracefully. + throw new Exception("ERROR: " . $error); + break; + + case E_WARNING : + case E_USER_WARNING : + error_log("WARNING: " . $error); + break; + + default: + error_log("DEBUG: " . $error); + } + } + + /** + * PHP Exception handler for XMLRPC. + * @param Exception $exception + */ + function __php_xmlrpc_exception_handler($exception) { + + error_log("*** FATAL EXCEPTION (API) *** : " . $exception); + + page_draw($exception->getMessage(), elgg_view("xml-rpc/output", array('result' => new XMLRPCErrorResponse($exception->getMessage(), $exception->getCode()==0 ? -32400 : $exception->getCode())))); + } +?> \ No newline at end of file -- cgit v1.2.3