📄 xmlrpc.php
字号:
<?php// by Edd Dumbill (C) 1999-2002// <edd@usefulinc.com>// $Id: xmlrpc.inc,v 1.158 2007/03/01 21:21:02 ggiunta Exp $// Copyright (c) 1999,2000,2002 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. if(!function_exists('xml_parser_create')) { // For PHP 4 onward, XML functionality is always compiled-in on windows: // no more need to dl-open it. It might have been compiled out on *nix... if(strtoupper(substr(PHP_OS, 0, 3) != 'WIN')) { dl('xml.so'); } } // Try to be backward compat with php < 4.2 (are we not being nice ?) $phpversion = phpversion(); if($phpversion[0] == '4' && $phpversion[2] < 2) { // give an opportunity to user to specify where to include other files from if(!defined('PHP_XMLRPC_COMPAT_DIR')) { define('PHP_XMLRPC_COMPAT_DIR',dirname(__FILE__).'/compat/'); } if($phpversion[2] == '0') { if($phpversion[4] < 6) { include(PHP_XMLRPC_COMPAT_DIR.'is_callable.php'); } include(PHP_XMLRPC_COMPAT_DIR.'is_scalar.php'); include(PHP_XMLRPC_COMPAT_DIR.'array_key_exists.php'); include(PHP_XMLRPC_COMPAT_DIR.'version_compare.php'); } include(PHP_XMLRPC_COMPAT_DIR.'var_export.php'); include(PHP_XMLRPC_COMPAT_DIR.'is_a.php'); } // G. Giunta 2005/01/29: declare global these variables, // so that xmlrpc.inc will work even if included from within a function // Milosch: 2005/08/07 - explicitly request these via $GLOBALS where used. $GLOBALS['xmlrpcI4']='i4'; $GLOBALS['xmlrpcInt']='int'; $GLOBALS['xmlrpcBoolean']='boolean'; $GLOBALS['xmlrpcDouble']='double'; $GLOBALS['xmlrpcString']='string'; $GLOBALS['xmlrpcDateTime']='dateTime.iso8601'; $GLOBALS['xmlrpcBase64']='base64'; $GLOBALS['xmlrpcArray']='array'; $GLOBALS['xmlrpcStruct']='struct'; $GLOBALS['xmlrpcValue']='undefined'; $GLOBALS['xmlrpcTypes']=array( $GLOBALS['xmlrpcI4'] => 1, $GLOBALS['xmlrpcInt'] => 1, $GLOBALS['xmlrpcBoolean'] => 1, $GLOBALS['xmlrpcString'] => 1, $GLOBALS['xmlrpcDouble'] => 1, $GLOBALS['xmlrpcDateTime'] => 1, $GLOBALS['xmlrpcBase64'] => 1, $GLOBALS['xmlrpcArray'] => 2, $GLOBALS['xmlrpcStruct'] => 3 ); $GLOBALS['xmlrpc_valid_parents'] = array( 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'), 'BOOLEAN' => array('VALUE'), 'I4' => array('VALUE'), 'INT' => array('VALUE'), 'STRING' => array('VALUE'), 'DOUBLE' => array('VALUE'), 'DATETIME.ISO8601' => array('VALUE'), 'BASE64' => array('VALUE'), 'MEMBER' => array('STRUCT'), 'NAME' => array('MEMBER'), 'DATA' => array('ARRAY'), 'ARRAY' => array('VALUE'), 'STRUCT' => array('VALUE'), 'PARAM' => array('PARAMS'), 'METHODNAME' => array('METHODCALL'), 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), 'FAULT' => array('METHODRESPONSE'), 'NIL' => array('VALUE') // only used when extension activated ); // define extra types for supporting NULL (useful for json or <NIL/>) $GLOBALS['xmlrpcNull']='null'; $GLOBALS['xmlrpcTypes']['null']=1; // Not in use anymore since 2.0. Shall we remove it? /// @deprecated $GLOBALS['xmlEntities']=array( 'amp' => '&', 'quot' => '"', 'lt' => '<', 'gt' => '>', 'apos' => "'" ); // tables used for transcoding different charsets into us-ascii xml $GLOBALS['xml_iso88591_Entities']=array(); $GLOBALS['xml_iso88591_Entities']['in'] = array(); $GLOBALS['xml_iso88591_Entities']['out'] = array(); for ($i = 0; $i < 32; $i++) { $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; } for ($i = 160; $i < 256; $i++) { $GLOBALS['xml_iso88591_Entities']['in'][] = chr($i); $GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';'; } /// @todo add to iso table the characters from cp_1252 range, i.e. 128 to 159. /// These will NOT be present in true ISO-8859-1, but will save the unwary /// windows user from sending junk./*$cp1252_to_xmlent = array( '\x80'=>'€', '\x81'=>'?', '\x82'=>'‚', '\x83'=>'ƒ', '\x84'=>'„', '\x85'=>'…', '\x86'=>'†', \x87'=>'‡', '\x88'=>'ˆ', '\x89'=>'‰', '\x8A'=>'Š', '\x8B'=>'‹', '\x8C'=>'Œ', '\x8D'=>'?', '\x8E'=>'Ž', '\x8F'=>'?', '\x90'=>'?', '\x91'=>'‘', '\x92'=>'’', '\x93'=>'“', '\x94'=>'”', '\x95'=>'•', '\x96'=>'–', '\x97'=>'—', '\x98'=>'˜', '\x99'=>'™', '\x9A'=>'š', '\x9B'=>'›', '\x9C'=>'œ', '\x9D'=>'?', '\x9E'=>'ž', '\x9F'=>'Ÿ' );*/ $GLOBALS['xmlrpcerr']['unknown_method']=1; $GLOBALS['xmlrpcstr']['unknown_method']='Unknown method'; $GLOBALS['xmlrpcerr']['invalid_return']=2; $GLOBALS['xmlrpcstr']['invalid_return']='Invalid return payload: enable debugging to examine incoming payload'; $GLOBALS['xmlrpcerr']['incorrect_params']=3; $GLOBALS['xmlrpcstr']['incorrect_params']='Incorrect parameters passed to method'; $GLOBALS['xmlrpcerr']['introspect_unknown']=4; $GLOBALS['xmlrpcstr']['introspect_unknown']="Can't introspect: method unknown"; $GLOBALS['xmlrpcerr']['http_error']=5; $GLOBALS['xmlrpcstr']['http_error']="Didn't receive 200 OK from remote server."; $GLOBALS['xmlrpcerr']['no_data']=6; $GLOBALS['xmlrpcstr']['no_data']='No data received from server.'; $GLOBALS['xmlrpcerr']['no_ssl']=7; $GLOBALS['xmlrpcstr']['no_ssl']='No SSL support compiled in.'; $GLOBALS['xmlrpcerr']['curl_fail']=8; $GLOBALS['xmlrpcstr']['curl_fail']='CURL error'; $GLOBALS['xmlrpcerr']['invalid_request']=15; $GLOBALS['xmlrpcstr']['invalid_request']='Invalid request payload'; $GLOBALS['xmlrpcerr']['no_curl']=16; $GLOBALS['xmlrpcstr']['no_curl']='No CURL support compiled in.'; $GLOBALS['xmlrpcerr']['server_error']=17; $GLOBALS['xmlrpcstr']['server_error']='Internal server error'; $GLOBALS['xmlrpcerr']['multicall_error']=18; $GLOBALS['xmlrpcstr']['multicall_error']='Received from server invalid multicall response'; $GLOBALS['xmlrpcerr']['multicall_notstruct'] = 9; $GLOBALS['xmlrpcstr']['multicall_notstruct'] = 'system.multicall expected struct'; $GLOBALS['xmlrpcerr']['multicall_nomethod'] = 10; $GLOBALS['xmlrpcstr']['multicall_nomethod'] = 'missing methodName'; $GLOBALS['xmlrpcerr']['multicall_notstring'] = 11; $GLOBALS['xmlrpcstr']['multicall_notstring'] = 'methodName is not a string'; $GLOBALS['xmlrpcerr']['multicall_recursion'] = 12; $GLOBALS['xmlrpcstr']['multicall_recursion'] = 'recursive system.multicall forbidden'; $GLOBALS['xmlrpcerr']['multicall_noparams'] = 13; $GLOBALS['xmlrpcstr']['multicall_noparams'] = 'missing params'; $GLOBALS['xmlrpcerr']['multicall_notarray'] = 14; $GLOBALS['xmlrpcstr']['multicall_notarray'] = 'params is not an array'; $GLOBALS['xmlrpcerr']['cannot_decompress']=103; $GLOBALS['xmlrpcstr']['cannot_decompress']='Received from server compressed HTTP and cannot decompress'; $GLOBALS['xmlrpcerr']['decompress_fail']=104; $GLOBALS['xmlrpcstr']['decompress_fail']='Received from server invalid compressed HTTP'; $GLOBALS['xmlrpcerr']['dechunk_fail']=105; $GLOBALS['xmlrpcstr']['dechunk_fail']='Received from server invalid chunked HTTP'; $GLOBALS['xmlrpcerr']['server_cannot_decompress']=106; $GLOBALS['xmlrpcstr']['server_cannot_decompress']='Received from client compressed HTTP request and cannot decompress'; $GLOBALS['xmlrpcerr']['server_decompress_fail']=107; $GLOBALS['xmlrpcstr']['server_decompress_fail']='Received from client invalid compressed HTTP request'; // The charset encoding used by the server for received messages and // by the client for received responses when received charset cannot be determined // or is not supported $GLOBALS['xmlrpc_defencoding']='UTF-8'; // The encoding used internally by PHP. // String values received as xml will be converted to this, and php strings will be converted to xml // as if having been coded with this $GLOBALS['xmlrpc_internalencoding']='ISO-8859-1'; $GLOBALS['xmlrpcName']='XML-RPC for PHP'; $GLOBALS['xmlrpcVersion']='2.2'; // let user errors start at 800 $GLOBALS['xmlrpcerruser']=800; // let XML parse errors start at 100 $GLOBALS['xmlrpcerrxml']=100; // formulate backslashes for escaping regexp // Not in use anymore since 2.0. Shall we remove it? /// @deprecated $GLOBALS['xmlrpc_backslash']=chr(92).chr(92); // set to TRUE to enable correct decoding of <NIL/> values $GLOBALS['xmlrpc_null_extension']=false; // used to store state during parsing // quick explanation of components: // ac - used to accumulate values // isf - used to indicate a parsing fault (2) or xmlrpcresp fault (1) // isf_reason - used for storing xmlrpcresp fault string // lv - used to indicate "looking for a value": implements // the logic to allow values with no types to be strings // params - used to store parameters in method calls // method - used to store method name // stack - array with genealogy of xml elements names: // used to validate nesting of xmlrpc elements $GLOBALS['_xh']=null; /** * Convert a string to the correct XML representation in a target charset * To help correct communication of non-ascii chars inside strings, regardless * of the charset used when sending requests, parsing them, sending responses * and parsing responses, an option is to convert all non-ascii chars present in the message * into their equivalent 'charset entity'. Charset entities enumerated this way * are independent of the charset encoding used to transmit them, and all XML * parsers are bound to understand them. * Note that in the std case we are not sending a charset encoding mime type * along with http headers, so we are bound by RFC 3023 to emit strict us-ascii. * * @todo do a bit of basic benchmarking (strtr vs. str_replace) * @todo make usage of iconv() or recode_string() or mb_string() where available */ function xmlrpc_encode_entitites($data, $src_encoding='', $dest_encoding='') { if ($src_encoding == '') { // lame, but we know no better... $src_encoding = $GLOBALS['xmlrpc_internalencoding']; } switch(strtoupper($src_encoding.'_'.$dest_encoding)) { case 'ISO-8859-1_': case 'ISO-8859-1_US-ASCII': $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); $escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data); break; case 'ISO-8859-1_UTF-8': $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); $escaped_data = utf8_encode($escaped_data); break; case 'ISO-8859-1_ISO-8859-1': case 'US-ASCII_US-ASCII': case 'US-ASCII_UTF-8': case 'US-ASCII_': case 'US-ASCII_ISO-8859-1': case 'UTF-8_UTF-8': $escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&', '"', ''', '<', '>'), $data); break; case 'UTF-8_': case 'UTF-8_US-ASCII': case 'UTF-8_ISO-8859-1': // NB: this will choke on invalid UTF-8, going most likely beyond EOF $escaped_data = ''; // be kind to users creating string xmlrpcvals out of different php types $data = (string) $data; $ns = strlen ($data); for ($nn = 0; $nn < $ns; $nn++) { $ch = $data[$nn]; $ii = ord($ch); //1 7 0bbbbbbb (127) if ($ii < 128) { /// @todo shall we replace this with a (supposedly) faster str_replace? switch($ii){ case 34: $escaped_data .= '"'; break; case 38: $escaped_data .= '&'; break; case 39: $escaped_data .= '''; break; case 60: $escaped_data .= '<'; break; case 62: $escaped_data .= '>'; break; default: $escaped_data .= $ch; } // switch } //2 11 110bbbbb 10bbbbbb (2047) else if ($ii>>5 == 6) { $b1 = ($ii & 31); $ii = ord($data[$nn+1]); $b2 = ($ii & 63); $ii = ($b1 * 64) + $b2; $ent = sprintf ('&#%d;', $ii); $escaped_data .= $ent; $nn += 1; } //3 16 1110bbbb 10bbbbbb 10bbbbbb else if ($ii>>4 == 14) { $b1 = ($ii & 31); $ii = ord($data[$nn+1]); $b2 = ($ii & 63); $ii = ord($data[$nn+2]); $b3 = ($ii & 63); $ii = ((($b1 * 64) + $b2) * 64) + $b3; $ent = sprintf ('&#%d;', $ii); $escaped_data .= $ent; $nn += 2; } //4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb else if ($ii>>3 == 30) { $b1 = ($ii & 31); $ii = ord($data[$nn+1]); $b2 = ($ii & 63); $ii = ord($data[$nn+2]); $b3 = ($ii & 63); $ii = ord($data[$nn+3]); $b4 = ($ii & 63); $ii = ((((($b1 * 64) + $b2) * 64) + $b3) * 64) + $b4; $ent = sprintf ('&#%d;', $ii); $escaped_data .= $ent; $nn += 3; } } break; default: $escaped_data = ''; error_log("Converting from $src_encoding to $dest_encoding: not supported..."); } return $escaped_data; } /// xml parser handler function for opening element tags function xmlrpc_se($parser, $name, $attrs, $accept_single_vals=false) { // if invalid xmlrpc already detected, skip all processing if ($GLOBALS['_xh']['isf'] < 2) { // check for correct element nesting // top level element can only be of 2 types /// @todo optimization creep: save this check into a bool variable, instead of using count() every time: /// there is only a single top level element in xml anyway if (count($GLOBALS['_xh']['stack']) == 0) { if ($name != 'METHODRESPONSE' && $name != 'METHODCALL' && ( $name != 'VALUE' && !$accept_single_vals)) { $GLOBALS['_xh']['isf'] = 2; $GLOBALS['_xh']['isf_reason'] = 'missing top level xmlrpc element'; return; } else { $GLOBALS['_xh']['rt'] = strtolower($name); } } else { // not top level element: see if parent is OK $parent = end($GLOBALS['_xh']['stack']); if (!array_key_exists($name, $GLOBALS['xmlrpc_valid_parents']) || !in_array($parent, $GLOBALS['xmlrpc_valid_parents'][$name])) { $GLOBALS['_xh']['isf'] = 2; $GLOBALS['_xh']['isf_reason'] = "xmlrpc element $name cannot be child of $parent"; return; } } switch($name) { // optimize for speed switch cases: most common cases first case 'VALUE': /// @todo we could check for 2 VALUE elements inside a MEMBER or PARAM element $GLOBALS['_xh']['vt']='value'; // indicator: no value found yet $GLOBALS['_xh']['ac']=''; $GLOBALS['_xh']['lv']=1; $GLOBALS['_xh']['php_class']=null; break; case 'I4': case 'INT': case 'STRING': case 'BOOLEAN': case 'DOUBLE':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -