diff options
author | Dries Buytaert <dries@buytaert.net> | 2005-07-13 18:46:15 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2005-07-13 18:46:15 +0000 |
commit | ed3bf725bb3b22f65efbe5c9c3d96c8e6f1a0fd2 (patch) | |
tree | f515f8883e24acc88c5388d61db1c3afd8dfc79b /includes/xmlrpcs.inc | |
parent | 73010a5215325763c301110ba108bb98b0a4cb98 (diff) | |
download | brdo-ed3bf725bb3b22f65efbe5c9c3d96c8e6f1a0fd2.tar.gz brdo-ed3bf725bb3b22f65efbe5c9c3d96c8e6f1a0fd2.tar.bz2 |
- Patch #26391 by chx: replaced the old XML-RPC library with a smaller/better/working one.
Diffstat (limited to 'includes/xmlrpcs.inc')
-rw-r--r-- | includes/xmlrpcs.inc | 512 |
1 files changed, 248 insertions, 264 deletions
diff --git a/includes/xmlrpcs.inc b/includes/xmlrpcs.inc index 6c1fe80aa..f50b3d788 100644 --- a/includes/xmlrpcs.inc +++ b/includes/xmlrpcs.inc @@ -1,301 +1,285 @@ <?php -// by Edd Dumbill (C) 1999-2001 -// <edd@usefulinc.com> -// $Id$ -// Copyright (c) 1999,2000,2001 Edd Dumbill. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// -// * Neither the name of the "XML-RPC for PHP" nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -// OF THE POSSIBILITY OF SUCH DAMAGE. - -// XML RPC Server class -// requires: xmlrpc.inc +function xmlrpc_server($callbacks) { + $xmlrpc_server = new stdClass(); + $defaults = array( + 'system.multicall' => 'xmlrpc_server_multicall', + array( + 'system.methodSignature', + 'xmlrpc_server_method_signature', + array('array', 'string'), + 'Returns an array describing the return type and required parameters of a method' + ), + array( + 'system.getCapabilities', + 'xmlrpc_server_get_capabilities', + array('struct'), + 'Returns a struct describing the XML-RPC specifications supported by this server' + ), + array( + 'system.listMethods', + 'xmlrpc_server_list_methods', + array('array'), + 'Returns an array of available methods on this server'), + array( + 'system.methodHelp', + 'xmlrpc_server_method_help', + array('string', 'string'), + 'Returns a documentation string for the specified method') + ); + // the order matters in the next line. which is the best? + foreach (array_merge($defaults, (array)$callbacks) as $key => $callback) { + // we could check for is_array($callback) + if (is_int($key)) { + $method = $callback[0]; + $xmlrpc_server->callbacks[$method] = $callback[1]; + $xmlrpc_server->signatures[$method] = $callback[2]; + $xmlrpc_server->help[$method] = $callback[3]; + } + else { + $xmlrpc_server->callbacks[$key] = $callback; + $xmlrpc_server->signatures[$key] = ''; + $xmlrpc_server->help[$key] = ''; + } + } -// listMethods: either a string, or nothing -$_xmlrpcs_listMethods_sig=array(array($xmlrpcArray, $xmlrpcString), - array($xmlrpcArray)); -$_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch'; -function _xmlrpcs_listMethods($server, $m) { - global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; - $v=new xmlrpcval(); - $dmap=$server->dmap; - $outAr=array(); - for(reset($dmap); list($key, $val)=each($dmap); ) { - $outAr[]=new xmlrpcval($key, "string"); + $data = file_get_contents('php://input'); + if (!data) { + die('XML-RPC server accepts POST requests only.'); } - $dmap=$_xmlrpcs_dmap; - for(reset($dmap); list($key, $val)=each($dmap); ) { - $outAr[]=new xmlrpcval($key, "string"); + $xmlrpc_server->message = xmlrpc_message($data); + if (!xmlrpc_message_parse($xmlrpc_server->message)) { + xmlrpc_server_error(-32700, t('parse error. not well formed')); } - $v->addArray($outAr); - return new xmlrpcresp($v); -} - -$_xmlrpcs_methodSignature_sig=array(array($xmlrpcArray, $xmlrpcString)); -$_xmlrpcs_methodSignature_doc='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)'; -function _xmlrpcs_methodSignature($server, $m) { - global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; - - $methName=$m->getParam(0); - $methName=$methName->scalarval(); - if (ereg("^system\.", $methName)) { - $dmap=$_xmlrpcs_dmap; $sysCall=1; - } else { - $dmap=$server->dmap; $sysCall=0; + if ($xmlrpc_server->message->messagetype != 'methodCall') { + xmlrpc_server_error(-32600, t('server error. invalid xml-rpc. not conforming to spec. Request must be a method_call')); } - // print "<!-- ${methName} -->\n"; - if (isset($dmap[$methName])) { - if ($dmap[$methName]["signature"]) { - $sigs=array(); - $thesigs=$dmap[$methName]["signature"]; - for($i=0; $i<sizeof($thesigs); $i++) { - $cursig=array(); - $inSig=$thesigs[$i]; - for($j=0; $j<sizeof($inSig); $j++) { - $cursig[]=new xmlrpcval($inSig[$j], "string"); - } - $sigs[]=new xmlrpcval($cursig, "array"); - } - $r=new xmlrpcresp(new xmlrpcval($sigs, "array")); - } else { - $r=new xmlrpcresp(new xmlrpcval("undef", "string")); - } - } else { - $r=new xmlrpcresp(0, - $xmlrpcerr["introspect_unknown"], - $xmlrpcstr["introspect_unknown"]); + $result = xmlrpc_server_call($xmlrpc_server, $xmlrpc_server->message->methodname, $xmlrpc_server->message->params); + // Is the result an error? + if ($result->is_error) { + xmlrpc_server_error($result); } - return $r; -} + // Encode the result + $r = xmlrpc_value($result); + // Create the XML + $xml = ' +<methodResponse> + <params> + <param> + <value>'. + xmlrpc_value_get_xml($r) + .'</value> + </param> + </params> +</methodResponse> -$_xmlrpcs_methodHelp_sig=array(array($xmlrpcString, $xmlrpcString)); -$_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string'; -function _xmlrpcs_methodHelp($server, $m) { - global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap; +'; + // Send it + xmlrpc_server_output($xml); +} - $methName=$m->getParam(0); - $methName=$methName->scalarval(); - if (ereg("^system\.", $methName)) { - $dmap=$_xmlrpcs_dmap; $sysCall=1; - } else { - $dmap=$server->dmap; $sysCall=0; - } - // print "<!-- ${methName} -->\n"; - if (isset($dmap[$methName])) { - if ($dmap[$methName]["docstring"]) { - $r=new xmlrpcresp(new xmlrpcval($dmap[$methName]["docstring"]), - "string"); - } else { - $r=new xmlrpcresp(new xmlrpcval("", "string")); - } - } else { - $r=new xmlrpcresp(0, - $xmlrpcerr["introspect_unknown"], - $xmlrpcstr["introspect_unknown"]); +function xmlrpc_server_error($error, $message = false) { + // Accepts either an error object or an error code and message + if ($message && !is_object($error)) { + $error = xmlrpc_error($error, $message); } - return $r; + xmlrpc_server_output(xmlrpc_error_get_xml($error)); } -$_xmlrpcs_dmap=array( - "system.listMethods" => - array("function" => "_xmlrpcs_listMethods", - "signature" => $_xmlrpcs_listMethods_sig, - "docstring" => $_xmlrpcs_listMethods_doc), - "system.methodHelp" => - array("function" => "_xmlrpcs_methodHelp", - "signature" => $_xmlrpcs_methodHelp_sig, - "docstring" => $_xmlrpcs_methodHelp_doc), - "system.methodSignature" => - array("function" => "_xmlrpcs_methodSignature", - "signature" => $_xmlrpcs_methodSignature_sig, - "docstring" => $_xmlrpcs_methodSignature_doc) - ); - -$_xmlrpc_debuginfo=""; -function xmlrpc_debugmsg($m) { - global $_xmlrpc_debuginfo; - $_xmlrpc_debuginfo=$_xmlrpc_debuginfo . $m . "\n"; +function xmlrpc_server_output($xml) { + $xml = '<?xml version="1.0"?>'."\n". $xml; + header('Connection: close'); + header('Content-Length: '. strlen($xml)); + header('Content-Type: text/xml'); + header('Date: '.date('r')); + echo $xml; + exit; } -class xmlrpc_server { - var $dmap=array(); - - function xmlrpc_server($dispMap, $serviceNow=1) { - // dispMap is a despatch array of methods - // mapped to function names and signatures - // if a method - // doesn't appear in the map then an unknown - // method error is generated - $this->dmap=$dispMap; - if ($serviceNow) { - $this->service(); - } - } +function xmlrpc_server_list_methods() { + $xmlrpc_server = xmlrpc_server_get(); + return array_keys($xmlrpc_server->callbacks); +} - function serializeDebug() { - global $_xmlrpc_debuginfo; - if ($_xmlrpc_debuginfo!="") - return "<!-- DEBUG INFO:\n\n" . - $_xmlrpc_debuginfo . "\n-->\n"; - else - return ""; +function xmlrpc_server_set($xmlrpc_server = NULL) { + static $server; + if (!isset($server)) { + $server = $xmlrpc_server; } + return $server; +} - function service() { - $r=$this->parseRequest(); - $payload="<?xml version=\"1.0\"?>\n" . - $this->serializeDebug() . - $r->serialize(); - Header("Content-Type: text/xml\r\nContent-Length: " . - strlen($payload)); - print $payload; - } +function xmlrpc_server_get() { + return xmlrpc_server_set(); +} - function verifySignature($in, $sig) { - for($i=0; $i<sizeof($sig); $i++) { - // check each possible signature in turn - $cursig=$sig[$i]; - if (sizeof($cursig)==$in->getNumParams()+1) { - $itsOK=1; - for($n=0; $n<$in->getNumParams(); $n++) { - $p=$in->getParam($n); - // print "<!-- $p -->\n"; - if ($p->kindOf() == "scalar") { - $pt=$p->scalartyp(); - } else { - $pt=$p->kindOf(); - } - // $n+1 as first type of sig is return type - if ($pt != $cursig[$n+1]) { - $itsOK=0; - $pno=$n+1; $wanted=$cursig[$n+1]; $got=$pt; - break; - } - } - if ($itsOK) - return array(1); - } +function xmlrpc_server_multicall($xmlrpc_server, $methodcalls) { + // See http://www.xmlrpc.com/discuss/msgReader$1208 + $return = array(); + foreach ($methodcalls as $call) { + $method = $call['methodName']; + $params = $call['params']; + if ($method == 'system.multicall') { + $result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden')); + } else { + $result = xmlrpc_server_call($xmlrpc_server, $method, $params); + } + if ($result->is_error) { + $return[] = array( + 'faultCode' => $result->code, + 'faultString' => $result->message + ); + } else { + $return[] = array($result); } - return array(0, "Wanted ${wanted}, got ${got} at param ${pno})"); } + return $return; +} - function parseRequest($data="") { - global $_xh; - global $xmlrpcerr, $xmlrpcstr, $xmlrpcerrxml, $_xmlrpcs_dmap; +function xmlrpc_server_get_capabilities() { + return array( + 'xmlrpc' => array( + 'specUrl' => 'http://www.xmlrpc.com/spec', + 'specVersion' => 1 + ), + 'faults_interop' => array( + 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php', + 'specVersion' => 20010516 + ), + 'system.multicall' => array( + 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208', + 'specVersion' => 1 + ), + 'introspection' => array( + 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html', + 'specVersion' => 1 + ) + ); +} - if ($data=="") { - $data=$GLOBALS["HTTP_RAW_POST_DATA"]; +function xmlrpc_server_call($xmlrpc_server, $methodname, $args) { + // Make sure it's in an array + if ($args && !is_array($args)) { + $args = array($args); } - $parser = drupal_xml_parser_create($data); - - $_xh[$parser]=array(); - $_xh[$parser]['st']=""; - $_xh[$parser]['cm']=0; - $_xh[$parser]['isf']=0; - $_xh[$parser]['params']=array(); - $_xh[$parser]['method']=""; - - // decompose incoming XML into request structure + // Over-rides default call method, adds signature check + if (!isset($xmlrpc_server->callbacks[$methodname])) { + return xmlrpc_error(-32601, t('server error. requested method %methodname not specified.',array("%methodname" => $xmlrpc_server->message->methodname))); + } + $method = $xmlrpc_server->callbacks[$methodname]; + $signature = $xmlrpc_server->signatures[$methodname]; - xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); - xml_set_element_handler($parser, "xmlrpc_se", "xmlrpc_ee"); - xml_set_character_data_handler($parser, "xmlrpc_cd"); - xml_set_default_handler($parser, "xmlrpc_dh"); - if (!xml_parse($parser, $data, 1)) { - // return XML error as a faultCode - $r=new xmlrpcresp(0, - $xmlrpcerrxml+xml_get_error_code($parser), - sprintf("XML error: %s at line %d", - xml_error_string(xml_get_error_code($parser)), - xml_get_current_line_number($parser))); - xml_parser_free($parser); - } else { - xml_parser_free($parser); - $m=new xmlrpcmsg($_xh[$parser]['method']); - // now add parameters in - $plist=""; - for($i=0; $i<sizeof($_xh[$parser]['params']); $i++) { - //print "<!-- " . $_xh[$parser]['params'][$i]. "-->\n"; - $plist.="$i - " . $_xh[$parser]['params'][$i]. " \n"; - $m->addParam(eval('return '. $_xh[$parser]['params'][$i] .';')); - } - // uncomment this to really see what the server's getting! - // xmlrpc_debugmsg($plist); - // now to deal with the method - $methName=$_xh[$parser]['method']; - if (ereg("^system\.", $methName)) { - $dmap=$_xmlrpcs_dmap; $sysCall=1; - } else { - $dmap=$this->dmap; $sysCall=0; + $ok = true; + if (is_array($signature)) { + $return_type = array_shift($signature); + // Check the number of arguments + if (count($args) != count($signature)) { + return xmlrpc_error(-32602, t('server error. wrong number of method parameters')); } - if (isset($dmap[$methName]['function'])) { - // dispatch if exists - if (isset($dmap[$methName]['signature'])) { - $sr=$this->verifySignature($m, - $dmap[$methName]['signature'] ); + // Check the argument types + foreach ($signature as $key => $type) { + $arg = $args[$key]; + switch ($type) { + case 'int': + case 'i4': + if (is_array($arg) || !is_int($arg)) { + $ok = false; + } + break; + case 'base64': + case 'string': + if (!is_string($arg)) { + $ok = false; + } + break; + case 'boolean': + if ($arg !== false && $arg !== true) { + $ok = false; + } + break; + case 'float': + case 'double': + if (!is_float($arg)) { + $ok = false; + } + break; + case 'date': + case 'dateTime.iso8601': + if (!$arg->is_date) { + $ok = false; + } + break; } - if ( (!isset($dmap[$methName]['signature'])) - || $sr[0]) { - $f = $dmap[$methName]['function']; - // if no signature or correct signature - if ($sysCall) { - $r = $f($this, $m); - } else { - $r = $f($m); - } - } else { - $r=new xmlrpcresp(0, - $xmlrpcerr["incorrect_params"], - $xmlrpcstr["incorrect_params"].": ". $sr[1]); + if (!$ok) { + return xmlrpc_error(-32602, t('server error. invalid method parameters')); } - } else { - // else prepare error response - $r=new xmlrpcresp(0, - $xmlrpcerr["unknown_method"], - $xmlrpcstr["unknown_method"]); } } - return $r; + // It passed the test - run the "real" method call + if (!isset($xmlrpc_server->callbacks[$methodname])) { + return xmlrpc_error(-32601, t('server error. requested method %methodname does not exist.',array("%methodname" => $methodname))); } - function echoInput() { - - // a debugging routine: just echos back the input - // packet as a string value + $method = $xmlrpc_server->callbacks[$methodname]; + // Perform the callback and send the response +/* + if (count($args) == 1) { + // If only one paramater just send that instead of the whole array + $args = $args[0]; + } +*/ + if (!function_exists($method)) { + return xmlrpc_error(-32601, t('server error. requested function %method does not exist.', array("%method" => $method))); + } + // Call the function + return call_user_func_array($method, $args); +} - $r=new xmlrpcresp; - $r->xv=new xmlrpcval( "'Aha said I: '" . $GLOBALS["HTTP_RAW_POST_DATA"], "string"); - print $r->serialize(); +function xmlrpc_server_method_signature($xmlrpc_server, $methodname) { + if (!isset($xmlrpc_server->callbacks[$methodname])) { + return xmlrpc_error(-32601, t('server error. requested method %methodname not specified.', array("%methodname" => $methodname))); + } + if (!is_array($xmlrpc_server->signature[$methodname])) { + return xmlrpc_error(-32601, t('server error. requested method %methodname signature not specified.', array("%methodname" => $methodname))); + } + // We should be returning an array of types + $return = array(); + foreach ($xmlrpc_server->signatures[$methodname] as $type) { + switch ($type) { + case 'string': + $return[] = 'string'; + break; + case 'int': + case 'i4': + $return[] = 42; + break; + case 'double': + $return[] = 3.1415; + break; + case 'dateTime.iso8601': + $return[] = xmlrpc_date(time()); + break; + case 'boolean': + $return[] = true; + break; + case 'base64': + $return[] =xmlrpc_base64('base64'); + break; + case 'array': + $return[] = array('array'); + break; + case 'struct': + $return[] = array('struct' => 'struct'); + break; + } } + return $return; +} + +function xmlrpc_server_method_help($xmlrpc_server, $method) { + return $xmlrpc_server->help[$method]; } -?> +?>
\ No newline at end of file |