📄 xmlrpcs.inc.svn-base
字号:
// The previous error handler was the default: all we should do is log error // to the default error log (if level high enough) if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode)) { error_log($errstring); } } else { // Pass control on to previous error handler, trying to avoid loops... if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler') { // NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers if(is_array($GLOBALS['_xmlrpcs_prev_ehandler'])) { $GLOBALS['_xmlrpcs_prev_ehandler'][0]->$GLOBALS['_xmlrpcs_prev_ehandler'][1]($errcode, $errstring, $filename, $lineno, $context); } else { $GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context); } } } } $GLOBALS['_xmlrpc_debuginfo']=''; /** * Add a string to the debug info that can be later seralized by the server * as part of the response message. * Note that for best compatbility, the debug string should be encoded using * the $GLOBALS['xmlrpc_internalencoding'] character set. * @param string $m * @access public */ function xmlrpc_debugmsg($m) { $GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n"; } class xmlrpc_server { /// array defining php functions exposed as xmlrpc methods by this server var $dmap=array(); /** * Defines how functions in dmap will be invokde: either using an xmlrpc msg object * or plain php values. * valid strings are 'xmlrpcvals', 'phpvals' or 'epivals' */ var $functions_parameters_type='xmlrpcvals'; /// controls wether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3 var $debug = 1; /** * When set to true, it will enable HTTP compression of the response, in case * the client has declared its support for compression in the request. */ var $compress_response = false; /** * List of http compression methods accepted by the server for requests. * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib */ var $accepted_compression = array(); /// shall we serve calls to system.* methods? var $allow_system_funcs = true; /// list of charset encodings natively accepted for requests var $accepted_charset_encodings = array(); /** * charset encoding to be used for response. * NB: if we can, we will convert the generated response from internal_encoding to the intended one. * can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled), * null (leave unspecified in response, convert output stream to US_ASCII), * 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert output stream if needed), * or 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway). * NB: pretty dangerous if you accept every charset and do not have mbstring enabled) */ var $response_charset_encoding = ''; /// storage for internal debug info var $debug_info = ''; /// extra data passed at runtime to method handling functions. Used only by EPI layer var $user_data = null; /** * @param array $dispmap the dispatch map withd efinition of exposed services * @param boolean $servicenow set to false to prevent the server from runnung upon construction */ function xmlrpc_server($dispMap=null, $serviceNow=true) { // if ZLIB is enabled, let the server by default accept compressed requests, // and compress responses sent to clients that support them if(function_exists('gzinflate')) { $this->accepted_compression = array('gzip', 'deflate'); $this->compress_response = true; } // by default the xml parser can support these 3 charset encodings $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); // dispMap is a dispatch 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 /* milosch - changed to make passing dispMap optional. * instead, you can use the class add_to_map() function * to add functions manually (borrowed from SOAPX4) */ if($dispMap) { $this->dmap = $dispMap; if($serviceNow) { $this->service(); } } } /** * Set debug level of server. * @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments) * 0 = no debug info, * 1 = msgs set from user with debugmsg(), * 2 = add complete xmlrpc request (headers and body), * 3 = add also all processing warnings happened during method processing * (NB: this involves setting a custom error handler, and might interfere * with the standard processing of the php function exposed as method. In * particular, triggering an USER_ERROR level error will not halt script * execution anymore, but just end up logged in the xmlrpc response) * Note that info added at elevel 2 and 3 will be base64 encoded * @access public */ function setDebug($in) { $this->debug=$in; } /** * Return a string with the serialized representation of all debug info * @param string $charset_encoding the target charset encoding for the serialization * @return string an XML comment (or two) */ function serializeDebug($charset_encoding='') { // Tough encoding problem: which internal charset should we assume for debug info? // It might contain a copy of raw data received from client, ie with unknown encoding, // intermixed with php generated data and user generated data... // so we split it: system debug is base 64 encoded, // user debug info should be encoded by the end user using the INTERNAL_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" . xmlrpc_encode_entitites(str_replace('--', '_-', $GLOBALS['_xmlrpc_debuginfo']), $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n-->\n"; // NB: a better solution MIGHT be to use CDATA, but we need to insert it // into return payload AFTER the beginning tag //$out .= "<![CDATA[ DEBUG INFO:\n\n" . str_replace(']]>', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n"; } return $out; } /** * Execute the xmlrpc request, printing the response * @param string $data the request body. If null, the http POST request will be examined * @return xmlrpcresp the response object (usually not used by caller...) * @access public */ function service($data=null, $return_payload=false) { if ($data === null) { $data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : ''; } $raw_data = $data; // reset internal debug info $this->debug_info = ''; // Echo back what we received, before parsing it if($this->debug > 1) { $this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++"); } $r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding); if (!$r) { $r=$this->parseRequest($data, $req_charset); } // save full body of request into response, for more debugging usages $r->raw_data = $raw_data; if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors']) { $this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" . $GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++"); } $payload=$this->xml_header($resp_charset); if($this->debug > 0) { $payload = $payload . $this->serializeDebug($resp_charset); } // G. Giunta 2006-01-27: do not create response serialization if it has // already happened. Helps building json magic if (empty($r->payload)) { $r->serialize($resp_charset); } $payload = $payload . $r->payload; if ($return_payload) { return $payload; } // if we get a warning/error that has output some text before here, then we cannot // add a new header. We cannot say we are sending xml, either... if(!headers_sent()) { header('Content-Type: '.$r->content_type); // we do not know if client actually told us an accepted charset, but if he did // we have to tell him what we did header("Vary: Accept-Charset"); // http compression of output: only // if we can do it, and we want to do it, and client asked us to, // and php ini settings do not force it already $php_no_self_compress = ini_get('zlib.output_compression') == '' && (ini_get('output_handler') != 'ob_gzhandler'); if($this->compress_response && function_exists('gzencode') && $resp_encoding != '' && $php_no_self_compress) { if(strpos($resp_encoding, 'gzip') !== false) { $payload = gzencode($payload); header("Content-Encoding: gzip"); header("Vary: Accept-Encoding"); } elseif (strpos($resp_encoding, 'deflate') !== false) { $payload = gzcompress($payload); header("Content-Encoding: deflate"); header("Vary: Accept-Encoding"); } } // do not ouput content-length header if php is compressing output for us: // it will mess up measurements if($php_no_self_compress) { header('Content-Length: ' . (int)strlen($payload)); } } else { error_log('XML-RPC: xmlrpc_server::service: http headers already sent before response is fully generated. Check for php warning or error messages'); } print $payload; // return request, in case subclasses want it return $r; } /** * Add a method to the dispatch map * @param string $methodname the name with which the method will be made available * @param string $function the php function that will get invoked * @param array $sig the array of valid method signatures * @param string $doc method documentation * @access public */ function add_to_map($methodname,$function,$sig=null,$doc='') { $this->dmap[$methodname] = array( 'function' => $function, 'docstring' => $doc ); if ($sig) { $this->dmap[$methodname]['signature'] = $sig; } } /** * Verify type and number of parameters received against a list of known signatures * @param array $in array of either xmlrpcval objects or xmlrpc type definitions * @param array $sig array of known signatures to match against * @access private */ function verifySignature($in, $sig) { // check each possible signature in turn if (is_object($in)) { $numParams = $in->getNumParams(); } else { $numParams = count($in); } foreach($sig as $cursig) { if(count($cursig)==$numParams+1) { $itsOK=1; for($n=0; $n<$numParams; $n++) { if (is_object($in)) { $p=$in->getParam($n); if($p->kindOf() == 'scalar') { $pt=$p->scalartyp(); } else { $pt=$p->kindOf(); } } else { $pt= $in[$n] == 'i4' ? 'int' : $in[$n]; // dispatch maps never use i4... } // param index is $n+1, as first member of sig is return type if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue']) { $itsOK=0; $pno=$n+1; $wanted=$cursig[$n+1]; $got=$pt; break; } } if($itsOK) { return array(1,''); } } } if(isset($wanted)) { return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); } else { return array(0, "No method signature matches number of parameters"); } } /** * Parse http headers received along with xmlrpc request. If needed, inflate request * @return null on success or an xmlrpcresp * @access private */ function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression) { // Play nice to PHP 4.0.x: superglobals were not yet invented... if(!isset($_SERVER)) { $_SERVER = $GLOBALS['HTTP_SERVER_VARS']; } if($this->debug > 1) { if(function_exists('getallheaders')) { $this->debugmsg(''); // empty line foreach(getallheaders() as $name => $val) { $this->debugmsg("HEADER: $name: $val"); } } } if(isset($_SERVER['HTTP_CONTENT_ENCODING'])) { $content_encoding = str_replace('x-', '', $_SERVER['HTTP_CONTENT_ENCODING']); } else { $content_encoding = ''; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -