| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- <?php
- /**
- * @package modx
- * @subpackage jsonrpc
- */
- /**
- * JSON extension to the PHP-XMLRPC lib: server components
- *
- * For more info see:
- * http://www.json.org/
- * http://json-rpc.org/
- *
- * @author Gaetano Giunta
- * @version $Id: jsonrpcs.inc,v 1.10 2007/02/15 21:48:38 ggiunta Exp $
- * @copyright (c) 2005 G. Giunta
- *
- * @todo implement dispatching of multicall requests, json way
- * @todo test system.XXX methods, with special care to multicall
- * @todo support for 'ping' calls, i.e. if id is null, echo back nothing
- **/
- // JSON RPC Server class
- // requires: jsonrpc.inc, xmlrpcs.inc, xmlrpc.inc
- // add to list of supported capaibilities the jsonrpc spec
- $GLOBALS['xmlrpcs_capabilities']['json-rpc'] = new xmlrpcval(array(
- 'specUrl' => new xmlrpcval('http://json-rpc.org/wiki/specification', 'string'),
- 'specVersion' => new xmlrpcval(1, 'int')
- ), 'struct');
- // NB: if building jsonrpc-only webservers, you should at least undeclare the xmlrpc capability:
- // unset($GLOBALS['xmlrpcs_capabilities']['xmlrpc']);
- class jsonrpc_server extends xmlrpc_server
- {
- //var $allow_system_funcs = false;
- var $functions_parameters_type='jsonrpcvals';
- function serializeDebug($charset_encoding='')
- {
- $out = '';
- if ($this->debug_info != '')
- {
- $out .= "/* SERVER DEBUG INFO (BASE64 ENCODED):\n".base64_encode($this->debug_info)."\n*/\n";
- }
- if ($GLOBALS['_xmlrpc_debuginfo'] != '')
- {
- $out .= "/* DEBUG INFO:\n\n" . json_encode_entitites($GLOBALS['_xmlrpc_debuginfo'], null, $charset_encoding) . "\n*/\n";
- }
- return $out;
- }
- /**
- * Note: syntax differs from overridden method, by adding an ID param
- * @access private
- */
- function execute($m, $params=null, $paramtypes=null, $msgID=null)
- {
- if (is_object($m))
- {
- // watch out: if $m is an xmlrpcmsg obj, this will raise a warning: no id memeber...
- $methName = $m->method();
- $msgID = $m->id;
- }
- else
- {
- $methName = $m;
- }
- $sysCall = $this->allow_system_funcs && @ereg("^system\.", $methName);
- $dmap = $sysCall ? $GLOBALS['_xmlrpcs_dmap'] : $this->dmap;
- if(!isset($dmap[$methName]['function']))
- {
- // No such method
- return new jsonrpcresp(0,
- $GLOBALS['xmlrpcerr']['unknown_method'],
- $GLOBALS['xmlrpcstr']['unknown_method']);
- }
- // Check signature
- if(isset($dmap[$methName]['signature']))
- {
- $sig = $dmap[$methName]['signature'];
- if (is_object($m))
- {
- list($ok, $errstr) = $this->verifySignature($m, $sig);
- }
- else
- {
- list($ok, $errstr) = $this->verifySignature($paramtypes, $sig);
- }
- if(!$ok)
- {
- // Didn't match.
- return new jsonrpcresp(
- 0,
- $GLOBALS['xmlrpcerr']['incorrect_params'],
- $GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
- );
- }
- }
- $func = $dmap[$methName]['function'];
- // let the 'class::function' syntax be accepted in dispatch maps
- if(is_string($func) && strpos($func, '::'))
- {
- $func = explode('::', $func);
- }
- // verify that function to be invoked is in fact callable
- if(!is_callable($func))
- {
- error_log("XML-RPC: jsonrpc_server::execute: function $func registered as method handler is not callable");
- return new jsonrpcresp(
- 0,
- $GLOBALS['xmlrpcerr']['server_error'],
- $GLOBALS['xmlrpcstr']['server_error'] . ": no function matches method"
- );
- }
- // If debug level is 3, we should catch all errors generated during
- // processing of user function, and log them as part of response
- if($this->debug > 2)
- {
- $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler');
- }
- if (is_object($m))
- {
- if($sysCall)
- {
- $r = call_user_func($func, $this, $m);
- }
- else
- {
- $r = call_user_func($func, $m);
- }
- if (!($r instanceof xmlrpcresp))
- {
- error_log("XML-RPC: jsonrpc_server::execute: function $func registered as method handler does not return an xmlrpcresp object");
- if ($r instanceof xmlrpcval) {
- $r = new jsonrpcresp($r);
- }
- else
- {
- $r = new jsonrpcresp(
- 0,
- $GLOBALS['xmlrpcerr']['server_error'],
- $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return jsonrpcresp or xmlrpcresp object"
- );
- }
- }
- }
- else
- {
- // call a 'plain php' function
- if($sysCall)
- {
- array_unshift($params, $this);
- $r = call_user_func_array($func,$params);
- }
- else
- {
- // 3rd API convention for method-handling functions: EPI-style
- if ($this->functions_parameters_type == 'epivals')
- {
- $r = call_user_func_array($func, array($methName, $params, $this->user_data));
- // mimic EPI behaviour: if we get an array that looks like an error, make it
- // an eror response
- if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r))
- {
- $r = new jsonrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']);
- }
- else
- {
- // functions using EPI api should NOT return resp objects,
- // so make sure we encode the return type correctly
- $r = new jsonrpcresp(php_xmlrpc_encode($r, array('extension_api')));
- }
- }
- else
- {
- $r = call_user_func_array($func, $params);
- }
- }
- // the return type can be either an xmlrpcresp object or a plain php value...
- if (!($r instanceof xmlrpcresp))
- {
- // what should we assume here about automatic encoding of datetimes
- // and php classes instances???
- $r = new jsonrpcresp(php_jsonrpc_encode($r));
- }
- }
- // here $r is either an xmlrpcresp or jsonrpcresp
- if (!($r instanceof jsonrpcresp))
- {
- // dirty trick: user has given us back an xmlrpc response,
- // since he had an existing xmlrpc server with boatloads of code.
- // Be nice to him, and serialize the xmlrpc stuff into JSON.
- // We also override the content_type of the xmlrpc response,
- // but lack knoweledge of intented response charset...
- $r->content_type = 'application/json';
- $r->payload = serialize_jsonrpcresp($r, $msgID);
- }
- else
- {
- $r->id = $msgID;
- }
- if($this->debug > 2)
- {
- // note: restore the error handler we found before calling the
- // user func, even if it has been changed inside the func itself
- if($GLOBALS['_xmlrpcs_prev_ehandler'])
- {
- set_error_handler($GLOBALS['_xmlrpcs_prev_ehandler']);
- }
- else
- {
- restore_error_handler();
- }
- }
- return $r;
- }
- /**
- * @access private
- */
- function parseRequest($data, $content_encoding='')
- {
- $GLOBALS['_xh']=array();
- if (!jsonrpc_parse_req($data, $this->functions_parameters_type == 'phpvals' || $this->functions_parameters_type == 'epivals', false, $content_encoding))
- {
- $r = new jsonrpcresp(0,
- $GLOBALS['xmlrpcerr']['invalid_request'],
- $GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']);
- }
- else
- {
- if ($this->functions_parameters_type == 'phpvals' || $this->functions_parameters_type == 'epivals')
- {
- if($this->debug > 1)
- {
- $this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++");
- }
- $r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt'], $GLOBALS['_xh']['id']);
- }
- else
- {
- // build an xmlrpcmsg object with data parsed from xml
- $m = new jsonrpcmsg($GLOBALS['_xh']['method'], 0, $GLOBALS['_xh']['id']);
- // now add parameters in
- /// @todo for more speeed, we could just substitute the array...
- for($i = 0; $i < sizeof($GLOBALS['_xh']['params']); $i++)
- {
- $m->addParam($GLOBALS['_xh']['params'][$i]);
- }
- if($this->debug > 1)
- {
- $this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++");
- }
- $r = $this->execute($m);
- }
- }
- return $r;
- }
- /**
- * No xml header generated by the server, since we are sending json
- * @access private
- */
- function xml_header($charset_encoding='')
- {
- return '';
- }
- }
- ?>
|