diff --git a/thirdparty/xmlrpc/xmlrpc.php b/thirdparty/xmlrpc/xmlrpc.php index 21e29a0..b3658f0 100644 --- a/thirdparty/xmlrpc/xmlrpc.php +++ b/thirdparty/xmlrpc/xmlrpc.php @@ -45,29 +45,6 @@ } } - // 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. @@ -112,7 +89,8 @@ 'METHODNAME' => array('METHODCALL'), 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), 'FAULT' => array('METHODRESPONSE'), - 'NIL' => array('VALUE') // only used when extension activated + 'NIL' => array('VALUE'), // only used when extension activated + 'EX:NIL' => array('VALUE') // only used when extension activated ); // define extra types for supporting NULL (useful for json or ) @@ -231,7 +209,7 @@ $GLOBALS['xmlrpc_internalencoding']='ISO-8859-1'; $GLOBALS['xmlrpcName']='XML-RPC for PHP'; - $GLOBALS['xmlrpcVersion']='2.2.2'; + $GLOBALS['xmlrpcVersion']='3.0.0.beta'; // let user errors start at 800 $GLOBALS['xmlrpcerruser']=800; @@ -243,9 +221,12 @@ /// @deprecated $GLOBALS['xmlrpc_backslash']=chr(92).chr(92); - // set to TRUE to enable correct decoding of values + // set to TRUE to enable correct decoding of and values $GLOBALS['xmlrpc_null_extension']=false; + // set to TRUE to enable encoding of php NULL values to instead of + $GLOBALS['xmlrpc_null_apache_encoding']=false; + // used to store state during parsing // quick explanation of components: // ac - used to accumulate values @@ -426,6 +407,7 @@ else { $GLOBALS['_xh']['rt'] = strtolower($name); + $GLOBALS['_xh']['rt'] = strtolower($name); } } else @@ -518,6 +500,7 @@ $GLOBALS['_xh']['vt']=null; break; case 'NIL': + case 'EX:NIL': if ($GLOBALS['xmlrpc_null_extension']) { if ($GLOBALS['_xh']['vt']!='value') @@ -580,7 +563,7 @@ if ($rebuild_xmlrpcvals) { // build the xmlrpc val out of the data received, and substitute it - $temp =& new xmlrpcval($GLOBALS['_xh']['value'], $GLOBALS['_xh']['vt']); + $temp = new xmlrpcval($GLOBALS['_xh']['value'], $GLOBALS['_xh']['vt']); // in case we got info about underlying php class, save it // in the object we're rebuilding if (isset($GLOBALS['_xh']['php_class'])) @@ -743,6 +726,7 @@ $GLOBALS['_xh']['method']=preg_replace('/^[\n\r\t ]+/', '', $GLOBALS['_xh']['ac']); break; case 'NIL': + case 'EX:NIL': if ($GLOBALS['xmlrpc_null_extension']) { $GLOBALS['_xh']['vt']='null'; @@ -844,6 +828,8 @@ var $proxy_pass=''; var $proxy_authtype=1; var $cookies=array(); + var $extracurlopts=array(); + /** * List of http compression methods accepted by the client for responses. * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib @@ -875,6 +861,10 @@ * valid strings are 'xmlrpcvals', 'phpvals' or 'xml' */ var $return_type = 'xmlrpcvals'; + /** + * Sent to servers in http headers + */ + var $user_agent; /** * @param string $path either the complete server URL or the PATH part of the xmlrc server URL, e.g. /xmlrpc/server.php @@ -942,15 +932,14 @@ $this->accepted_compression = array('gzip', 'deflate'); } - // keepalives: enabled by default ONLY for PHP >= 4.3.8 - // (see http://curl.haxx.se/docs/faq.html#7.3) - if(version_compare(phpversion(), '4.3.8') >= 0) - { - $this->keepalive = true; - } + // keepalives: enabled by default + $this->keepalive = true; // by default the xml parser can support these 3 charset encodings $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII'); + + // initialize user_agent string + $this->user_agent = $GLOBALS['xmlrpcName'] . ' ' . $GLOBALS['xmlrpcVersion']; } /** @@ -1117,6 +1106,25 @@ } } + /** + * Directly set cURL options, for extra flexibility + * It allows eg. to bind client to a specific IP interface / address + * @param $options array + */ + function SetCurlOptions( $options ) + { + $this->extracurlopts = $options; + } + + /** + * Set user-agent string that will be used by this client instance + * in http headers sent to the server + */ + function SetUserAgent( $agentstring ) + { + $this->user_agent = $agentstring; + } + /** * Send an xmlrpc request * @param mixed $msg The message object, or an array of messages for using multicall, or the complete xml representation of a request @@ -1142,7 +1150,7 @@ } elseif(is_string($msg)) { - $n =& new xmlrpcmsg(''); + $n = new xmlrpcmsg(''); $n->payload = $msg; $msg = $n; } @@ -1271,7 +1279,7 @@ $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n"; if ($authtype != 1) { - error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported with HTTP 1.0'); + error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported with HTTP 1.0'); } } @@ -1295,7 +1303,7 @@ { if ($proxyauthtype != 1) { - error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported with HTTP 1.0'); + error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported with HTTP 1.0'); } $proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n"; } @@ -1335,7 +1343,7 @@ } $op= 'POST ' . $uri. " HTTP/1.0\r\n" . - 'User-Agent: ' . $GLOBALS['xmlrpcName'] . ' ' . $GLOBALS['xmlrpcVersion'] . "\r\n" . + 'User-Agent: ' . $this->user_agent . "\r\n" . 'Host: '. $server . ':' . $port . "\r\n" . $credentials . $proxy_credentials . @@ -1372,15 +1380,15 @@ else { $this->errstr='Connect error: '.$this->errstr; - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')'); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')'); return $r; } if(!fputs($fp, $op, strlen($op))) { - fclose($fp); + fclose($fp); $this->errstr='Write error'; - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr); return $r; } else @@ -1431,7 +1439,7 @@ if(!function_exists('curl_init')) { $this->errstr='CURL unavailable on this install'; - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_curl'], $GLOBALS['xmlrpcstr']['no_curl']); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_curl'], $GLOBALS['xmlrpcstr']['no_curl']); return $r; } if($method == 'https') @@ -1440,7 +1448,7 @@ ((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version'])))) { $this->errstr='SSL unavailable on this install'; - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_ssl'], $GLOBALS['xmlrpcstr']['no_ssl']); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_ssl'], $GLOBALS['xmlrpcstr']['no_ssl']); return $r; } } @@ -1518,7 +1526,7 @@ { curl_setopt($curl, CURLOPT_VERBOSE, 1); } - curl_setopt($curl, CURLOPT_USERAGENT, $GLOBALS['xmlrpcName'].' '.$GLOBALS['xmlrpcVersion']); + curl_setopt($curl, CURLOPT_USERAGENT, $this->user_agent); // required for XMLRPC: post the data curl_setopt($curl, CURLOPT_POST, 1); // the data @@ -1571,7 +1579,7 @@ } else if ($authtype != 1) { - error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported by the current PHP/curl install'); + error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported by the current PHP/curl install'); } } @@ -1630,7 +1638,7 @@ } else if ($proxyauthtype != 1) { - error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported by the current PHP/curl install'); + error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported by the current PHP/curl install'); } } } @@ -1648,6 +1656,11 @@ curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2)); } + foreach ($this->extracurlopts as $opt => $val) + { + curl_setopt($curl, $opt, $val); + } + $result = curl_exec($curl); if ($this->debug > 1) @@ -1661,7 +1674,7 @@ if(!$result) /// @todo we should use a better check here - what if we get back '' or '0'? { $this->errstr='no response'; - $resp=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl)); + $resp=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl)); curl_close($curl); if($keepalive) { @@ -1732,7 +1745,7 @@ } else { - $result =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']); + $result = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']); } } } @@ -1779,17 +1792,17 @@ $calls = array(); foreach($msgs as $msg) { - $call['methodName'] =& new xmlrpcval($msg->method(),'string'); + $call['methodName'] = new xmlrpcval($msg->method(),'string'); $numParams = $msg->getNumParams(); $params = array(); for($i = 0; $i < $numParams; $i++) { $params[$i] = $msg->getParam($i); } - $call['params'] =& new xmlrpcval($params, 'array'); - $calls[] =& new xmlrpcval($call, 'struct'); + $call['params'] = new xmlrpcval($params, 'array'); + $calls[] = new xmlrpcval($call, 'struct'); } - $multicall =& new xmlrpcmsg('system.multicall'); + $multicall = new xmlrpcmsg('system.multicall'); $multicall->addParam(new xmlrpcval($calls, 'array')); // Attempt RPC call @@ -1837,7 +1850,7 @@ return false; // Bad value } // Normal return value - $response[$i] =& new xmlrpcresp($val[0], 0, '', 'phpvals'); + $response[$i] = new xmlrpcresp($val[0], 0, '', 'phpvals'); break; case 2: /// @todo remove usage of @: it is apparently quite slow @@ -1851,7 +1864,7 @@ { return false; } - $response[$i] =& new xmlrpcresp(0, $code, $str); + $response[$i] = new xmlrpcresp(0, $code, $str); break; default: return false; @@ -1884,7 +1897,7 @@ return false; // Bad value } // Normal return value - $response[$i] =& new xmlrpcresp($val->arraymem(0)); + $response[$i] = new xmlrpcresp($val->arraymem(0)); break; case 'struct': $code = $val->structmem('faultCode'); @@ -1897,7 +1910,7 @@ { return false; } - $response[$i] =& new xmlrpcresp(0, $code->scalarval(), $str->scalarval()); + $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval()); break; default: return false; @@ -2208,7 +2221,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha * Given an open file handle, read all data available and parse it as axmlrpc response. * NB: the file handle is not closed by this function. * NNB: might have trouble in rare cases to work on network streams, as we - * check for a read of 0 bytes instead of feof($fp). + * check for a read of 0 bytes instead of feof($fp). * But since checking for feof(null) returns false, we would risk an * infinite loop in that case, because we cannot trust the caller * to give us a valid pointer to an open file... @@ -2265,8 +2278,8 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha } else { - error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTPS via proxy error, tunnel connection possibly failed'); - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)'); + error_log('XML-RPC: '.__METHOD__.': HTTPS via proxy error, tunnel connection possibly failed'); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)'); return $r; } } @@ -2286,8 +2299,8 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data)) { $errstr= substr($data, 0, strpos($data, "\n")-1); - error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTP error, got response: ' .$errstr); - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')'); + error_log('XML-RPC: '.__METHOD__.': HTTP error, got response: ' .$errstr); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')'); return $r; } @@ -2316,7 +2329,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha } } // be tolerant to line endings, and extra empty lines - $ar = split("\r?\n", trim(substr($data, 0, $pos))); + $ar = preg_split("/\r?\n/", trim(substr($data, 0, $pos))); while(list(,$line) = @each($ar)) { // take care of multi-line headers and cookies @@ -2411,8 +2424,8 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha { if(!$data = decode_chunked($data)) { - error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to rebuild the chunked data received from server'); - $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']); + error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to rebuild the chunked data received from server'); + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']); return $r; } } @@ -2441,22 +2454,22 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha } else { - error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to decode the deflated data received from server'); - $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']); + error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to decode the deflated data received from server'); + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']); return $r; } } else { - error_log('XML-RPC: xmlrpcmsg::parseResponse: the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); - $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']); + error_log('XML-RPC: '.__METHOD__.': the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']); return $r; } } } } // end of 'if needed, de-chunk, re-inflate response' - // real stupid hack to avoid PHP 4 complaining about returning NULL by ref + // real stupid hack to avoid PHP complaining about returning NULL by ref $r = null; $r =& $r; return $r; @@ -2480,8 +2493,8 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha if($data == '') { - error_log('XML-RPC: xmlrpcmsg::parseResponse: no response received from server.'); - $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']); + error_log('XML-RPC: '.__METHOD__.': no response received from server.'); + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']); return $r; } @@ -2525,23 +2538,16 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha // be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts) // idea from Luca Mariano originally in PEARified version of the lib - $bd = false; - // Poor man's version of strrpos for php 4... - $pos = strpos($data, ''); - while($pos || is_int($pos)) + $pos = strrpos($data, ''); + if($pos !== false) { - $bd = $pos+17; - $pos = strpos($data, '', $bd); - } - if($bd) - { - $data = substr($data, 0, $bd); + $data = substr($data, 0, $pos+17); } // if user wants back raw xml, give it to him if ($return_type == 'xml') { - $r =& new xmlrpcresp($data, 0, '', 'xml'); + $r = new xmlrpcresp($data, 0, '', 'xml'); $r->hdrs = $GLOBALS['_xh']['headers']; $r->_cookies = $GLOBALS['_xh']['cookies']; $r->raw_data = $raw_data; @@ -2566,7 +2572,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha // makes the lib about 200% slower... //if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) { - error_log('XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of received response: '.$resp_encoding); + error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received response: '.$resp_encoding); $resp_encoding = $GLOBALS['xmlrpc_defencoding']; } $parser = xml_parser_create($resp_encoding); @@ -2613,7 +2619,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha xml_get_current_line_number($parser), xml_get_current_column_number($parser)); } error_log($errstr); - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')'); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')'); xml_parser_free($parser); if($this->debug) { @@ -2633,7 +2639,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha /// @todo echo something for user? } - $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh']['isf_reason']); } // third error check: parsing of the response has somehow gone boink. @@ -2643,7 +2649,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha // something odd has happened // and it's time to generate a client side error // indicating something odd went on - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return']); } else @@ -2683,11 +2689,11 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha $errno = -1; } - $r =& new xmlrpcresp(0, $errno, $errstr); + $r = new xmlrpcresp(0, $errno, $errstr); } else { - $r=&new xmlrpcresp($v, 0, '', $return_type); + $r=new xmlrpcresp($v, 0, '', $return_type); } } @@ -2741,7 +2747,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha $this->me['struct']=$val; break; default: - error_log("XML-RPC: xmlrpcval::xmlrpcval: not a known type ($type)"); + error_log("XML-RPC: ".__METHOD__.": not a known type ($type)"); } /*if($type=='') { @@ -2773,13 +2779,13 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha $typeof=@$GLOBALS['xmlrpcTypes'][$type]; if($typeof!=1) { - error_log("XML-RPC: xmlrpcval::addScalar: not a scalar type ($type)"); + error_log("XML-RPC: ".__METHOD__.": not a scalar type ($type)"); return 0; } // coerce booleans into correct values - // NB: we should iether do it for datetimes, integers and doubles, too, - // or just plain remove this check, implemnted on booleans only... + // NB: we should either do it for datetimes, integers and doubles, too, + // or just plain remove this check, implemented on booleans only... if($type==$GLOBALS['xmlrpcBoolean']) { if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false'))) @@ -2795,18 +2801,18 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha switch($this->mytype) { case 1: - error_log('XML-RPC: xmlrpcval::addScalar: scalar xmlrpcval can have only one value'); + error_log('XML-RPC: '.__METHOD__.': scalar xmlrpcval can have only one value'); return 0; case 3: - error_log('XML-RPC: xmlrpcval::addScalar: cannot add anonymous scalar to struct xmlrpcval'); + error_log('XML-RPC: '.__METHOD__.': cannot add anonymous scalar to struct xmlrpcval'); return 0; case 2: // we're adding a scalar value to an array here //$ar=$this->me['array']; - //$ar[]=&new xmlrpcval($val, $type); + //$ar[]=new xmlrpcval($val, $type); //$this->me['array']=$ar; // Faster (?) avoid all the costly array-copy-by-val done here... - $this->me['array'][]=&new xmlrpcval($val, $type); + $this->me['array'][]=new xmlrpcval($val, $type); return 1; default: // a scalar, so set the value and remember we're scalar @@ -2840,7 +2846,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha } else { - error_log('XML-RPC: xmlrpcval::addArray: already initialized as a [' . $this->kindOf() . ']'); + error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']'); return 0; } } @@ -2869,7 +2875,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha } else { - error_log('XML-RPC: xmlrpcval::addStruct: already initialized as a [' . $this->kindOf() . ']'); + error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']'); return 0; } } @@ -2941,15 +2947,41 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha $rs.="<${typ}>".(int)$val.""; break; case $GLOBALS['xmlrpcDouble']: - // avoid using standard conversion of float to string because it is locale-dependent, - // and also because the xmlrpc spec forbids exponential notation - // sprintf('%F') would be most likely ok but it is only available since PHP 4.3.10 and PHP 5.0.3. - // The code below tries its best at keeping max precision while avoiding exp notation, - // but there is of course no limit in the number of decimal places to be used... - $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', '')).""; + // avoid using standard conversion of float to string because it is locale-dependent, + // and also because the xmlrpc spec forbids exponential notation. + // sprintf('%F') could be most likely ok but it fails eg. on 2e-14. + // The code below tries its best at keeping max precision while avoiding exp notation, + // but there is of course no limit in the number of decimal places to be used... + $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', '')).""; + break; + case $GLOBALS['xmlrpcDateTime']: + if (is_string($val)) + { + $rs.="<${typ}>${val}"; + } + else if(is_a($val, 'DateTime')) + { + $rs.="<${typ}>".$val->format('Ymd\TH:i:s').""; + } + else if(is_int($val)) + { + $rs.="<${typ}>".strftime("%Y%m%dT%H:%M:%S", $val).""; + } + else + { + // not really a good idea here: but what shall we output anyway? left for backward compat... + $rs.="<${typ}>${val}"; + } break; case $GLOBALS['xmlrpcNull']: - $rs.=""; + if ($GLOBALS['xmlrpc_null_apache_encoding']) + { + $rs.=""; + } + else + { + $rs.=""; + } break; default: // no standard type value should arrive here, but provide a possibility @@ -3249,7 +3281,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha * @author Dan Libby (dan@libby.com) * * @param xmlrpcval $xmlrpc_val - * @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects + * @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects; if 'dates_as_objects' is set xmlrpc datetimes are decoded as php DateTime objects (standard is * @return mixed */ function php_xmlrpc_decode($xmlrpc_val, $options=array()) @@ -3276,6 +3308,27 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha return $xmlrpc_val->scalarval(); } } + if (in_array('dates_as_objects', $options) && $xmlrpc_val->scalartyp() == 'dateTime.iso8601') + { + // we return a Datetime object instead of a string + // since now the constructor of xmlrpcval accepts safely strings, ints and datetimes, + // we cater to all 3 cases here + $out = $xmlrpc_val->scalarval(); + if (is_string($out)) + { + $out = strtotime($out); + } + if (is_int($out)) + { + $result = new Datetime(); + $result->setTimestamp($out); + return $result; + } + elseif (is_a($out, 'Datetime')) + { + return $out; + } + } return $xmlrpc_val->scalarval(); case 'array': $size = $xmlrpc_val->arraysize(); @@ -3350,27 +3403,27 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha * @param array $options can include 'encode_php_objs', 'auto_dates', 'null_extension' or 'extension_api' * @return xmlrpcval */ - function &php_xmlrpc_encode($php_val, $options=array()) + function php_xmlrpc_encode($php_val, $options=array()) { $type = gettype($php_val); switch($type) { case 'string': if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $php_val)) - $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']); + $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']); else - $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcString']); + $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcString']); break; case 'integer': - $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']); + $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']); break; case 'double': - $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']); + $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']); break; // // Add support for encoding/decoding of booleans, since they are supported in PHP case 'boolean': - $xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']); + $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']); break; // case 'array': @@ -3384,7 +3437,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha $ko = false; foreach($php_val as $key => $val) { - $arr[$key] =& php_xmlrpc_encode($val, $options); + $arr[$key] = php_xmlrpc_encode($val, $options); if(!$ko && $key !== $j) { $ko = true; @@ -3393,11 +3446,11 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha } if($ko) { - $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); + $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); } else { - $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcArray']); + $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcArray']); } break; case 'object': @@ -3405,14 +3458,19 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha { $xmlrpc_val = $php_val; } + else if(is_a($php_val, 'DateTime')) + { + $xmlrpc_val = new xmlrpcval($php_val->format('Ymd\TH:i:s'), $GLOBALS['xmlrpcStruct']); + } else { $arr = array(); + reset($php_val); while(list($k,$v) = each($php_val)) { $arr[$k] = php_xmlrpc_encode($v, $options); } - $xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); + $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']); if (in_array('encode_php_objs', $options)) { // let's save original class name into xmlrpcval: @@ -3424,32 +3482,32 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha case 'NULL': if (in_array('extension_api', $options)) { - $xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcString']); + $xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcString']); } - if (in_array('null_extension', $options)) + else if (in_array('null_extension', $options)) { - $xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcNull']); + $xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcNull']); } else { - $xmlrpc_val =& new xmlrpcval(); + $xmlrpc_val = new xmlrpcval(); } break; case 'resource': if (in_array('extension_api', $options)) { - $xmlrpc_val =& new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']); + $xmlrpc_val = new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']); } else { - $xmlrpc_val =& new xmlrpcval(); + $xmlrpc_val = new xmlrpcval(); } // catch "user function", "unknown type" default: // giancarlo pinerolo // it has to return // an empty object in case, not a boolean. - $xmlrpc_val =& new xmlrpcval(); + $xmlrpc_val = new xmlrpcval(); break; } return $xmlrpc_val; @@ -3513,15 +3571,15 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha { $vc = $v->structmem('faultCode'); $vs = $v->structmem('faultString'); - $r =& new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval()); + $r = new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval()); } else { - $r =& new xmlrpcresp($v); + $r = new xmlrpcresp($v); } return $r; case 'methodcall': - $m =& new xmlrpcmsg($GLOBALS['_xh']['method']); + $m = new xmlrpcmsg($GLOBALS['_xh']['method']); for($i=0; $i < count($GLOBALS['_xh']['params']); $i++) { $m->addParam($GLOBALS['_xh']['params'][$i]); @@ -3616,7 +3674,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha // Note: we do not check for invalid chars in VALUE: // this had better be done using pure ereg as below // Note 2: we might be removing whitespace/tabs that ought to be left in if - // the received charset is a quoted string. But nobody uses such charset names... + // the received charset is a quoted string. But nobody uses such charset names... /// @todo this test will pass if ANY header has charset specification, not only Content-Type. Fix it? $matches = array(); diff --git a/thirdparty/xmlrpc/xmlrpc_wrappers.php b/thirdparty/xmlrpc/xmlrpc_wrappers.php index cb0c6e8..1a663f0 100644 --- a/thirdparty/xmlrpc/xmlrpc_wrappers.php +++ b/thirdparty/xmlrpc/xmlrpc_wrappers.php @@ -5,7 +5,7 @@ * * @version $Id: xmlrpc_wrappers.inc,v 1.13 2008/09/20 01:23:47 ggiunta Exp $ * @author Gaetano Giunta - * @copyright (C) 2006-2008 G. Giunta + * @copyright (C) 2006-2009 G. Giunta * @license code licensed under the BSD License: http://phpxmlrpc.sourceforge.net/license.txt * * @todo separate introspection from code generation for func-2-method wrapping @@ -22,6 +22,7 @@ * accepted come from javadoc blocks), return corresponding phpxmlrpc type. * NB: for php 'resource' types returns empty string, since resources cannot be serialized; * for php class names returns 'struct', since php objects can be serialized as xmlrpc structs + * for php arrays always return array, even though arrays sometiles serialize as json structs * @param string $phptype * @return string */ @@ -157,6 +158,10 @@ } $exists = false; + if (is_string($funcname) && strpos($funcname, '::') !== false) + { + $funcname = explode('::', $funcname); + } if(is_array($funcname)) { if(count($funcname) < 2 || (!is_string($funcname[0]) && !is_object($funcname[0]))) @@ -173,6 +178,11 @@ $plainfuncname = get_class($funcname[0]) . '->' . $funcname[1]; } $exists = method_exists($funcname[0], $funcname[1]); + if (!$exists && version_compare(phpversion(), '5.1') < 0) + { + // workaround for php 5.0: static class methods are not seen by method_exists + $exists = is_callable( $funcname ); + } } else { @@ -214,7 +224,7 @@ // start to introspect PHP code if(is_array($funcname)) { - $func =& new ReflectionMethod($funcname[0], $funcname[1]); + $func = new ReflectionMethod($funcname[0], $funcname[1]); if($func->isPrivate()) { error_log('XML-RPC: method to be wrapped is private: '.$plainfuncname); @@ -230,7 +240,8 @@ error_log('XML-RPC: method to be wrapped is the constructor: '.$plainfuncname); return false; } - if($func->isDestructor()) + // php 503 always says isdestructor = true... + if( version_compare(phpversion(), '5.0.3') != 0 && $func->isDestructor()) { error_log('XML-RPC: method to be wrapped is the destructor: '.$plainfuncname); return false; @@ -244,7 +255,7 @@ } else { - $func =& new ReflectionFunction($funcname); + $func = new ReflectionFunction($funcname); } if($func->isInternal()) { @@ -504,7 +515,7 @@ if ($methodfilter == '' || preg_match($methodfilter, $mname)) { // echo $mlist."\n"; - $func =& new ReflectionMethod($classname, $mname); + $func = new ReflectionMethod($classname, $mname); if(!$func->isPrivate() && !$func->isProtected() && !$func->isConstructor() && !$func->isDestructor() && !$func->isAbstract()) { if(($func->isStatic && ($methodtype == 'all' || $methodtype == 'static' || ($methodtype == 'auto' && is_string($classname)))) || @@ -600,7 +611,7 @@ $valclass = $prefix.'val'; $decodefunc = 'php_'.$prefix.'_decode'; - $msg =& new $msgclass('system.methodSignature'); + $msg = new $msgclass('system.methodSignature'); $msg->addparam(new $valclass($methodname)); $client->setDebug($debug); $response =& $client->send($msg, $timeout, $protocol); @@ -646,7 +657,7 @@ // in online mode, favour speed of operation if(!$buildit) { - $msg =& new $msgclass('system.methodHelp'); + $msg = new $msgclass('system.methodHelp'); $msg->addparam(new $valclass($methodname)); $response =& $client->send($msg, $timeout, $protocol); if (!$response->faultCode()) @@ -715,7 +726,7 @@ //$valclass = $prefix.'val'; $decodefunc = 'php_'.$prefix.'_decode'; - $msg =& new $msgclass('system.listMethods'); + $msg = new $msgclass('system.listMethods'); $response =& $client->send($msg, $timeout, $protocol); if($response->faultCode()) { @@ -835,7 +846,7 @@ $innercode = ''; $this_ = 'this->'; } - $innercode .= "\$msg =& new {$prefix}msg('$methodname');\n"; + $innercode .= "\$msg = new {$prefix}msg('$methodname');\n"; if ($mdesc != '') { @@ -858,7 +869,7 @@ $ptype == 'string' || $ptype == 'dateTime.iso8601' || $ptype == 'base64' || $ptype == 'null') { // only build directly xmlrpcvals when type is known and scalar - $innercode .= "\$p$i =& new {$prefix}val(\$p$i, '$ptype');\n"; + $innercode .= "\$p$i = new {$prefix}val(\$p$i, '$ptype');\n"; } else { @@ -920,7 +931,7 @@ */ function build_client_wrapper_code($client, $verbatim_client_copy, $prefix='xmlrpc') { - $code = "\$client =& new {$prefix}_client('".str_replace("'", "\'", $client->path). + $code = "\$client = new {$prefix}_client('".str_replace("'", "\'", $client->path). "', '" . str_replace("'", "\'", $client->server) . "', $client->port);\n"; // copy all client fields to the client that will be generated runtime diff --git a/thirdparty/xmlrpc/xmlrpcs.php b/thirdparty/xmlrpc/xmlrpcs.php index a089ca5..441dc3d 100644 --- a/thirdparty/xmlrpc/xmlrpcs.php +++ b/thirdparty/xmlrpc/xmlrpcs.php @@ -85,13 +85,13 @@ $outAr=array(); foreach($server->dmap as $key => $val) { - $outAr[]=&new xmlrpcval($key, 'string'); + $outAr[]=new xmlrpcval($key, 'string'); } if($server->allow_system_funcs) { foreach($GLOBALS['_xmlrpcs_dmap'] as $key => $val) { - $outAr[]=&new xmlrpcval($key, 'string'); + $outAr[]=new xmlrpcval($key, 'string'); } } return new xmlrpcresp(new xmlrpcval($outAr, 'array')); @@ -130,22 +130,22 @@ $cursig=array(); foreach($inSig as $sig) { - $cursig[]=&new xmlrpcval($sig, 'string'); + $cursig[]=new xmlrpcval($sig, 'string'); } - $sigs[]=&new xmlrpcval($cursig, 'array'); + $sigs[]=new xmlrpcval($cursig, 'array'); } - $r=&new xmlrpcresp(new xmlrpcval($sigs, 'array')); + $r=new xmlrpcresp(new xmlrpcval($sigs, 'array')); } else { // NB: according to the official docs, we should be returning a // "none-array" here, which means not-an-array - $r=&new xmlrpcresp(new xmlrpcval('undef', 'string')); + $r=new xmlrpcresp(new xmlrpcval('undef', 'string')); } } else { - $r=&new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']); + $r=new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']); } return $r; } @@ -177,16 +177,16 @@ { if(isset($dmap[$methName]['docstring'])) { - $r=&new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string'); + $r=new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string'); } else { - $r=&new xmlrpcresp(new xmlrpcval('', 'string')); + $r=new xmlrpcresp(new xmlrpcval('', 'string')); } } else { - $r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']); + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']); } return $r; } @@ -207,8 +207,8 @@ $str = $err->faultString(); } $struct = array(); - $struct['faultCode'] =& new xmlrpcval($code, 'int'); - $struct['faultString'] =& new xmlrpcval($str, 'string'); + $struct['faultCode'] = new xmlrpcval($code, 'int'); + $struct['faultString'] = new xmlrpcval($str, 'string'); return new xmlrpcval($struct, 'struct'); } @@ -243,7 +243,7 @@ } $numParams = $params->arraysize(); - $msg =& new xmlrpcmsg($methName->scalarval()); + $msg = new xmlrpcmsg($methName->scalarval()); for($i = 0; $i < $numParams; $i++) { if(!$msg->addParam($params->arraymem($i))) @@ -365,6 +365,7 @@ $GLOBALS['_xmlrpcs_occurred_errors'] = ''; $GLOBALS['_xmlrpcs_prev_ehandler'] = ''; + /** * Error handler used to track errors that occur during server-side execution of PHP code. * This allows to report back to the client whether an internal error has occurred or not @@ -381,7 +382,7 @@ return; //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING) - if($errcode != 2048) // do not use E_STRICT by name, since on PHP 4 it will not be defined + if($errcode != E_STRICT) { $GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n"; } @@ -432,17 +433,34 @@ class xmlrpc_server { - /// array defining php functions exposed as xmlrpc methods by this server + /** + * Array defining php functions exposed as xmlrpc methods by this server + * @access private + */ var $dmap=array(); /** - * Defines how functions in dmap will be invokde: either using an xmlrpc msg object + * Defines how functions in dmap will be invoked: either using an xmlrpc msg object * or plain php values. * valid strings are 'xmlrpcvals', 'phpvals' or 'epivals' */ var $functions_parameters_type='xmlrpcvals'; + /** + * Option used for fine-tuning the encoding the php values returned from + * functions registered in the dispatch map when the functions_parameters_types + * member is set to 'phpvals' + * @see php_xmlrpc_encode for a list of values + */ + var $phpvals_encoding_options = array( 'auto_dates' ); /// 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; /** + * Controls behaviour of server when invoked user function throws an exception: + * 0 = catch it and return an 'internal error' xmlrpc response (default) + * 1 = catch it and return an xmlrpc response with the error corresponding to the exception + * 2 = allow the exception to float to the upper layers + */ + var $exception_handling = 0; + /** * 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. */ @@ -466,9 +484,14 @@ * NB: pretty dangerous if you accept every charset and do not have mbstring enabled) */ var $response_charset_encoding = ''; - /// storage for internal debug info + /** + * Storage for internal debug info + * @access private + */ var $debug_info = ''; - /// extra data passed at runtime to method handling functions. Used only by EPI layer + /** + * Extra data passed at runtime to method handling functions. Used only by EPI layer + */ var $user_data = null; /** @@ -659,7 +682,7 @@ } else { - error_log('XML-RPC: xmlrpc_server::service: http headers already sent before response is fully generated. Check for php warning or error messages'); + error_log('XML-RPC: '.__METHOD__.': http headers already sent before response is fully generated. Check for php warning or error messages'); } print $payload; @@ -689,7 +712,7 @@ } if ($sigdoc) { - $this->dmap[$methodname]['signature_docs'] = $sigdoc; + $this->dmap[$methodname]['signature_docs'] = $sigdoc; } } @@ -731,7 +754,7 @@ } else { - $pt= $in[$n] == 'i4' ? 'int' : $in[$n]; // dispatch maps never use i4... + $pt= $in[$n] == 'i4' ? 'int' : strtolower($in[$n]); // dispatch maps never use i4... } // param index is $n+1, as first member of sig is return type @@ -767,10 +790,11 @@ */ function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression) { - // Play nice to PHP 4.0.x: superglobals were not yet invented... - if(!isset($_SERVER)) + // check if $_SERVER is populated: it might have been disabled via ini file + // (this is true even when in CLI mode) + if (count($_SERVER) == 0) { - $_SERVER = $GLOBALS['HTTP_SERVER_VARS']; + error_log('XML-RPC: '.__METHOD__.': cannot parse request headers as $_SERVER is not populated'); } if($this->debug > 1) @@ -819,14 +843,14 @@ } else { - $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']); + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']); return $r; } } else { //error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.'); - $r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']); + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']); return $r; } } @@ -919,7 +943,7 @@ // makes the lib about 200% slower... //if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) { - error_log('XML-RPC: xmlrpc_server::parseRequest: invalid charset encoding of received request: '.$req_encoding); + error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received request: '.$req_encoding); $req_encoding = $GLOBALS['xmlrpc_defencoding']; } /// @BUG this will fail on PHP 5 if charset is not specified in the xml prologue, @@ -957,7 +981,7 @@ if(!xml_parse($parser, $data, 1)) { // return XML error as a faultCode - $r=&new xmlrpcresp(0, + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser), sprintf('XML error: %s at line %d, column %d', xml_error_string(xml_get_error_code($parser)), @@ -967,14 +991,18 @@ elseif ($GLOBALS['_xh']['isf']) { xml_parser_free($parser); - $r=&new xmlrpcresp(0, + $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_request'], $GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']); } else { xml_parser_free($parser); - if ($this->functions_parameters_type != 'xmlrpcvals') + // small layering violation in favor of speed and memory usage: + // we should allow the 'execute' method handle this, but in the + // most common scenario (xmlrpcvals type server with some methods + // registered as phpvals) that would mean a useless encode+decode pass + if ($this->functions_parameters_type != 'xmlrpcvals' || (isset($this->dmap[$GLOBALS['_xh']['method']]['parameters_type']) && ($this->dmap[$GLOBALS['_xh']['method']]['parameters_type'] == 'phpvals'))) { if($this->debug > 1) { @@ -985,7 +1013,7 @@ else { // build an xmlrpcmsg object with data parsed from xml - $m=&new xmlrpcmsg($GLOBALS['_xh']['method']); + $m=new xmlrpcmsg($GLOBALS['_xh']['method']); // now add parameters in for($i=0; $ifunctions_parameters_type == 'epivals') + if (!is_a($r, 'xmlrpcresp')) { - $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)) + error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler does not return an xmlrpcresp object"); + if (is_a($r, 'xmlrpcval')) { - $r =& new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']); + $r = new xmlrpcresp($r); } else { - // functions using EPI api should NOT return resp objects, - // so make sure we encode the return type correctly - $r =& new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api'))); + $r = new xmlrpcresp( + 0, + $GLOBALS['xmlrpcerr']['server_error'], + $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object" + ); } } + } + else + { + // call a 'plain php' function + if($sysCall) + { + array_unshift($params, $this); + $r = call_user_func_array($func, $params); + } else { - $r = call_user_func_array($func, $params); + // 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 xmlrpcresp(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 xmlrpcresp(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 (!is_a($r, 'xmlrpcresp')) + { + // what should we assume here about automatic encoding of datetimes + // and php classes instances??? + $r = new xmlrpcresp(php_xmlrpc_encode($r, $this->phpvals_encoding_options)); } } - // the return type can be either an xmlrpcresp object or a plain php value... - if (!is_a($r, 'xmlrpcresp')) + } + catch(Exception $e) + { + // (barring errors in the lib) an uncatched exception happened + // in the called function, we wrap it in a proper error-response + switch($this->exception_handling) { - // what should we assume here about automatic encoding of datetimes - // and php classes instances??? - $r =& new xmlrpcresp(php_xmlrpc_encode($r, array('auto_dates'))); + case 2: + throw $e; + break; + case 1: + $r = new xmlrpcresp(0, $e->getCode(), $e->getMessage()); + break; + default: + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_error'], $GLOBALS['xmlrpcstr']['server_error']); } } if($this->debug > 2) @@ -1191,7 +1239,7 @@ */ function echoInput() { - $r=&new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string')); + $r=new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string')); print $r->serialize(); } }