X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/11be8dc178e77d0b46189bbd8e33a216a9b90942..9e77185fafaf4e60e2b73821e0e4b9b1a11fb85f:/wp-includes/class-IXR.php?ds=sidebyside diff --git a/wp-includes/class-IXR.php b/wp-includes/class-IXR.php index 63fc53ec..b0a0f28d 100644 --- a/wp-includes/class-IXR.php +++ b/wp-includes/class-IXR.php @@ -1,36 +1,63 @@ data = $data; if (!$type) { $type = $this->calculateType(); } $this->type = $type; if ($type == 'struct') { - /* Turn all the values in the array in to new IXR_Value objects */ + // Turn all the values in the array in to new IXR_Value objects foreach ($this->data as $key => $value) { $this->data[$key] = new IXR_Value($value); } @@ -42,7 +69,8 @@ class IXR_Value { } } - function calculateType() { + function calculateType() + { if ($this->data === true || $this->data === false) { return 'boolean'; } @@ -52,6 +80,7 @@ class IXR_Value { if (is_double($this->data)) { return 'double'; } + // Deal with IXR object types base64 and date if (is_object($this->data) && is_a($this->data, 'IXR_Date')) { return 'date'; @@ -59,16 +88,17 @@ class IXR_Value { if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) { return 'base64'; } + // If it is a normal PHP object convert it in to a struct if (is_object($this->data)) { - $this->data = get_object_vars($this->data); return 'struct'; } if (!is_array($this->data)) { return 'string'; } - /* We have an array - is it an array or a struct ? */ + + // We have an array - is it an array or a struct? if ($this->isStruct($this->data)) { return 'struct'; } else { @@ -76,8 +106,9 @@ class IXR_Value { } } - function getXml() { - /* Return XML for this value */ + function getXml() + { + // Return XML for this value switch ($this->type) { case 'boolean': return ''.(($this->data) ? '1' : '0').''; @@ -117,8 +148,14 @@ class IXR_Value { return false; } - function isStruct($array) { - /* Nasty function to check if an array is a struct or not */ + /** + * Checks whether or not the supplied array is a struct or not + * + * @param unknown_type $array + * @return boolean + */ + function isStruct($array) + { $expected = 0; foreach ($array as $key => $value) { if ((string)$key != (string)$expected) { @@ -131,18 +168,21 @@ class IXR_Value { } /** - * IXR_Message + * IXR_MESSAGE * * @package IXR - * @since 1.5 + * @since 1.5.0 + * */ -class IXR_Message { +class IXR_Message +{ var $message; var $messageType; // methodCall / methodResponse / fault var $faultCode; var $faultString; var $methodName; var $params; + // Current variable stacks var $_arraystructs = array(); // The stack used to keep track of the current array/struct var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array @@ -153,15 +193,47 @@ class IXR_Message { var $_currentTagContents; // The XML parser var $_parser; - function IXR_Message ($message) { - $this->message = $message; + + function IXR_Message($message) + { + $this->message =& $message; } - function parse() { + + function parse() + { // first remove the XML declaration - $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message); - if (trim($this->message) == '') { + // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages + $header = preg_replace( '/<\?xml.*?\?'.'>/s', '', substr( $this->message, 0, 100 ), 1 ); + $this->message = trim( substr_replace( $this->message, $header, 0, 100 ) ); + if ( '' == $this->message ) { + return false; + } + + // Then remove the DOCTYPE + $header = preg_replace( '/^]*+>/i', '', substr( $this->message, 0, 200 ), 1 ); + $this->message = trim( substr_replace( $this->message, $header, 0, 200 ) ); + if ( '' == $this->message ) { + return false; + } + + // Check that the root tag is valid + $root_tag = substr( $this->message, 0, strcspn( substr( $this->message, 0, 20 ), "> \t\r\n" ) ); + if ( 'message, '<' ) ) { + return false; + } + $this->_parser = xml_parser_create(); // Set XML parser to take the case of tags in to account xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false); @@ -169,13 +241,23 @@ class IXR_Message { xml_set_object($this->_parser, $this); xml_set_element_handler($this->_parser, 'tag_open', 'tag_close'); xml_set_character_data_handler($this->_parser, 'cdata'); - if (!xml_parse($this->_parser, $this->message)) { - /* die(sprintf('XML error: %s at line %d', - xml_error_string(xml_get_error_code($this->_parser)), - xml_get_current_line_number($this->_parser))); */ - return false; - } + $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages + $final = false; + do { + if (strlen($this->message) <= $chunk_size) { + $final = true; + } + $part = substr($this->message, 0, $chunk_size); + $this->message = substr($this->message, $chunk_size); + if (!xml_parse($this->_parser, $part, $final)) { + return false; + } + if ($final) { + break; + } + } while (true); xml_parser_free($this->_parser); + // Grab the error messages, if any if ($this->messageType == 'fault') { $this->faultCode = $this->params[0]['faultCode']; @@ -183,7 +265,9 @@ class IXR_Message { } return true; } - function tag_open($parser, $tag, $attr) { + + function tag_open($parser, $tag, $attr) + { $this->_currentTagContents = ''; $this->currentTag = $tag; switch($tag) { @@ -192,7 +276,7 @@ class IXR_Message { case 'fault': $this->messageType = $tag; break; - /* Deal with stacks of arrays and structs */ + /* Deal with stacks of arrays and structs */ case 'data': // data is to all intents and puposes more interesting than array $this->_arraystructstypes[] = 'array'; $this->_arraystructs[] = array(); @@ -203,28 +287,31 @@ class IXR_Message { break; } } - function cdata($parser, $cdata) { + + function cdata($parser, $cdata) + { $this->_currentTagContents .= $cdata; } - function tag_close($parser, $tag) { + + function tag_close($parser, $tag) + { $valueFlag = false; switch($tag) { case 'int': case 'i4': - $value = (int) trim($this->_currentTagContents); + $value = (int)trim($this->_currentTagContents); $valueFlag = true; break; case 'double': - $value = (double) trim($this->_currentTagContents); + $value = (double)trim($this->_currentTagContents); $valueFlag = true; break; case 'string': - $value = $this->_currentTagContents; + $value = (string)trim($this->_currentTagContents); $valueFlag = true; break; case 'dateTime.iso8601': $value = new IXR_Date(trim($this->_currentTagContents)); - // $value = $iso->getTimestamp(); $valueFlag = true; break; case 'value': @@ -235,14 +322,14 @@ class IXR_Message { } break; case 'boolean': - $value = (boolean) trim($this->_currentTagContents); + $value = (boolean)trim($this->_currentTagContents); $valueFlag = true; break; case 'base64': - $value = base64_decode( trim( $this->_currentTagContents ) ); + $value = base64_decode($this->_currentTagContents); $valueFlag = true; break; - /* Deal with stacks of arrays and structs */ + /* Deal with stacks of arrays and structs */ case 'data': case 'struct': $value = array_pop($this->_arraystructs); @@ -259,6 +346,7 @@ class IXR_Message { $this->methodName = trim($this->_currentTagContents); break; } + if ($valueFlag) { if (count($this->_arraystructs) > 0) { // Add value to struct or array @@ -270,7 +358,7 @@ class IXR_Message { $this->_arraystructs[count($this->_arraystructs)-1][] = $value; } } else { - // Just add as a paramater + // Just add as a parameter $this->params[] = $value; } } @@ -282,28 +370,42 @@ class IXR_Message { * IXR_Server * * @package IXR - * @since 1.5 + * @since 1.5.0 */ -class IXR_Server { +class IXR_Server +{ var $data; var $callbacks = array(); var $message; var $capabilities; - function IXR_Server($callbacks = false, $data = false) { + + function IXR_Server($callbacks = false, $data = false, $wait = false) + { $this->setCapabilities(); if ($callbacks) { $this->callbacks = $callbacks; } $this->setCallbacks(); - $this->serve($data); + if (!$wait) { + $this->serve($data); + } } - function serve($data = false) { + + function serve($data = false) + { if (!$data) { + if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Content-Type: text/plain'); // merged from WP #9093 + die('XML-RPC server accepts POST requests only.'); + } + global $HTTP_RAW_POST_DATA; - if (!$HTTP_RAW_POST_DATA) { - die('XML-RPC server accepts POST requests only.'); + if (empty($HTTP_RAW_POST_DATA)) { + // workaround for a bug in PHP 5.2.2 - http://bugs.php.net/bug.php?id=41293 + $data = file_get_contents('php://input'); + } else { + $data =& $HTTP_RAW_POST_DATA; } - $data = $HTTP_RAW_POST_DATA; } $this->message = new IXR_Message($data); if (!$this->message->parse()) { @@ -313,118 +415,145 @@ class IXR_Server { $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall'); } $result = $this->call($this->message->methodName, $this->message->params); + // Is the result an error? if (is_a($result, 'IXR_Error')) { $this->error($result); } + // Encode the result $r = new IXR_Value($result); $resultxml = $r->getXml(); + // Create the XML $xml = << - $resultxml + $resultxml EOD; - // Send it - $this->output($xml); + // Send it + $this->output($xml); } - function call($methodname, $args) { + + function call($methodname, $args) + { if (!$this->hasMethod($methodname)) { - return new IXR_Error(-32601, 'server error. requested method '. - $methodname.' does not exist.'); + return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.'); } $method = $this->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 + // If only one parameter just send that instead of the whole array $args = $args[0]; } + // Are we dealing with a function or a method? - if (substr($method, 0, 5) == 'this:') { + if (is_string($method) && substr($method, 0, 5) == 'this:') { // It's a class method - check it exists $method = substr($method, 5); if (!method_exists($this, $method)) { - return new IXR_Error(-32601, 'server error. requested class method "'. - $method.'" does not exist.'); + return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.'); } - // Call the method + + //Call the method $result = $this->$method($args); } else { // It's a function - does it exist? if (is_array($method)) { - if (!method_exists($method[0], $method[1])) { - return new IXR_Error(-32601, 'server error. requested object method "'. - $method[1].'" does not exist.'); + if (!is_callable(array($method[0], $method[1]))) { + return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.'); } } else if (!function_exists($method)) { - return new IXR_Error(-32601, 'server error. requested function "'. - $method.'" does not exist.'); + return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.'); } + // Call the function $result = call_user_func($method, $args); } return $result; } - function error($error, $message = false) { + function error($error, $message = false) + { // Accepts either an error object or an error code and message if ($message && !is_object($error)) { $error = new IXR_Error($error, $message); } $this->output($error->getXml()); } - function output($xml) { - $xml = ''."\n".$xml; + + function output($xml) + { + $charset = function_exists('get_option') ? get_option('blog_charset') : ''; + if ($charset) + $xml = ''."\n".$xml; + else + $xml = ''."\n".$xml; $length = strlen($xml); header('Connection: close'); header('Content-Length: '.$length); - header('Content-Type: text/xml'); + if ($charset) + header('Content-Type: text/xml; charset='.$charset); + else + header('Content-Type: text/xml'); header('Date: '.date('r')); echo $xml; exit; } - function hasMethod($method) { + + function hasMethod($method) + { return in_array($method, array_keys($this->callbacks)); } - function setCapabilities() { + + function setCapabilities() + { // Initialises capabilities array $this->capabilities = 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 - ), + ), ); } - function getCapabilities($args) { + + function getCapabilities($args) + { return $this->capabilities; } - function setCallbacks() { + + function setCallbacks() + { $this->callbacks['system.getCapabilities'] = 'this:getCapabilities'; $this->callbacks['system.listMethods'] = 'this:listMethods'; $this->callbacks['system.multicall'] = 'this:multiCall'; } - function listMethods($args) { + + function listMethods($args) + { // Returns a list of methods - uses array_reverse to ensure user defined // methods are listed before server defined methods return array_reverse(array_keys($this->callbacks)); } - function multiCall($methodcalls) { + + function multiCall($methodcalls) + { // See http://www.xmlrpc.com/discuss/msgReader$1208 $return = array(); foreach ($methodcalls as $call) { @@ -452,13 +581,16 @@ EOD; * IXR_Request * * @package IXR - * @since 1.5 + * @since 1.5.0 */ -class IXR_Request { +class IXR_Request +{ var $method; var $args; var $xml; - function IXR_Request($method, $args) { + + function IXR_Request($method, $args) + { $this->method = $method; $this->args = $args; $this->xml = <<xml .= ''; } - function getLength() { + + function getLength() + { return strlen($this->xml); } - function getXml() { + + function getXml() + { return $this->xml; } } @@ -488,9 +624,11 @@ EOD; * IXR_Client * * @package IXR - * @since 1.5 + * @since 1.5.0 + * */ -class IXR_Client { +class IXR_Client +{ var $server; var $port; var $path; @@ -499,19 +637,28 @@ class IXR_Client { var $message = false; var $debug = false; var $timeout; + var $headers = array(); + // Storage place for an error message var $error = false; - function IXR_Client($server, $path = false, $port = 80, $timeout = false) { + + function IXR_Client($server, $path = false, $port = 80, $timeout = 15) + { if (!$path) { // Assume we have been given a URL instead $bits = parse_url($server); $this->server = $bits['host']; $this->port = isset($bits['port']) ? $bits['port'] : 80; $this->path = isset($bits['path']) ? $bits['path'] : '/'; + // Make absolutely sure we have a path if (!$this->path) { $this->path = '/'; } + + if ( ! empty( $bits['query'] ) ) { + $this->path .= '?' . $bits['query']; + } } else { $this->server = $server; $this->path = $path; @@ -520,7 +667,9 @@ class IXR_Client { $this->useragent = 'The Incutio XML-RPC PHP Library'; $this->timeout = $timeout; } - function query() { + + function query() + { $args = func_get_args(); $method = array_shift($args); $request = new IXR_Request($method, $args); @@ -528,26 +677,37 @@ class IXR_Client { $xml = $request->getXml(); $r = "\r\n"; $request = "POST {$this->path} HTTP/1.0$r"; - $request .= "Host: {$this->server}$r"; - $request .= "Content-Type: text/xml$r"; - $request .= "User-Agent: {$this->useragent}$r"; - $request .= "Content-length: {$length}$r$r"; + + // Merged from WP #8145 - allow custom headers + $this->headers['Host'] = $this->server; + $this->headers['Content-Type'] = 'text/xml'; + $this->headers['User-Agent'] = $this->useragent; + $this->headers['Content-Length']= $length; + + foreach( $this->headers as $header => $value ) { + $request .= "{$header}: {$value}{$r}"; + } + $request .= $r; + $request .= $xml; + // Now send the request if ($this->debug) { - echo '
'.htmlspecialchars($request)."\n
\n\n"; + echo '
'.htmlspecialchars($request)."\n
\n\n"; } + if ($this->timeout) { $fp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout); } else { $fp = @fsockopen($this->server, $this->port, $errno, $errstr); } if (!$fp) { - $this->error = new IXR_Error(-32300, "transport error - could not open socket: $errno $errstr"); + $this->error = new IXR_Error(-32300, 'transport error - could not open socket'); return false; } fputs($fp, $request); $contents = ''; + $debugContents = ''; $gotFirstLine = false; $gettingHeaders = true; while (!feof($fp)) { @@ -564,12 +724,17 @@ class IXR_Client { $gettingHeaders = false; } if (!$gettingHeaders) { - $contents .= trim($line); + // merged from WP #12559 - remove trim + $contents .= $line; + } + if ($this->debug) { + $debugContents .= $line; } } if ($this->debug) { - echo '
'.htmlspecialchars($contents)."\n
\n\n"; + echo '
'.htmlspecialchars($debugContents)."\n
\n\n"; } + // Now parse what we've got back $this->message = new IXR_Message($contents); if (!$this->message->parse()) { @@ -577,44 +742,59 @@ class IXR_Client { $this->error = new IXR_Error(-32700, 'parse error. not well formed'); return false; } + // Is the message a fault? if ($this->message->messageType == 'fault') { $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString); return false; } + // Message must be OK return true; } - function getResponse() { + + function getResponse() + { // methodResponses can only have one param - return that return $this->message->params[0]; } - function isError() { + + function isError() + { return (is_object($this->error)); } - function getErrorCode() { + + function getErrorCode() + { return $this->error->code; } - function getErrorMessage() { + + function getErrorMessage() + { return $this->error->message; } } + /** * IXR_Error * * @package IXR - * @since 1.5 + * @since 1.5.0 */ -class IXR_Error { +class IXR_Error +{ var $code; var $message; - function IXR_Error($code, $message) { + + function IXR_Error($code, $message) + { $this->code = $code; - // WP adds htmlspecialchars(). See #5666 $this->message = htmlspecialchars($message); } - function getXml() { + + function getXml() + { $xml = << @@ -642,7 +822,7 @@ EOD; * IXR_Date * * @package IXR - * @since 1.5 + * @since 1.5.0 */ class IXR_Date { var $year; @@ -652,7 +832,9 @@ class IXR_Date { var $minute; var $second; var $timezone; - function IXR_Date($time) { + + function IXR_Date($time) + { // $time can be a PHP timestamp or an ISO one if (is_numeric($time)) { $this->parseTimestamp($time); @@ -660,34 +842,41 @@ class IXR_Date { $this->parseIso($time); } } - function parseTimestamp($timestamp) { + + function parseTimestamp($timestamp) + { $this->year = date('Y', $timestamp); $this->month = date('m', $timestamp); $this->day = date('d', $timestamp); $this->hour = date('H', $timestamp); $this->minute = date('i', $timestamp); $this->second = date('s', $timestamp); - // WP adds timezone. See #2036 $this->timezone = ''; } - function parseIso($iso) { + + function parseIso($iso) + { $this->year = substr($iso, 0, 4); $this->month = substr($iso, 4, 2); $this->day = substr($iso, 6, 2); $this->hour = substr($iso, 9, 2); $this->minute = substr($iso, 12, 2); $this->second = substr($iso, 15, 2); - // WP adds timezone. See #2036 $this->timezone = substr($iso, 17); } - function getIso() { - // WP adds timezone. See #2036 + + function getIso() + { return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone; } - function getXml() { + + function getXml() + { return ''.$this->getIso().''; } - function getTimestamp() { + + function getTimestamp() + { return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); } } @@ -696,14 +885,19 @@ class IXR_Date { * IXR_Base64 * * @package IXR - * @since 1.5 + * @since 1.5.0 */ -class IXR_Base64 { +class IXR_Base64 +{ var $data; - function IXR_Base64($data) { + + function IXR_Base64($data) + { $this->data = $data; } - function getXml() { + + function getXml() + { return ''.base64_encode($this->data).''; } } @@ -712,12 +906,15 @@ class IXR_Base64 { * IXR_IntrospectionServer * * @package IXR - * @since 1.5 + * @since 1.5.0 */ -class IXR_IntrospectionServer extends IXR_Server { +class IXR_IntrospectionServer extends IXR_Server +{ var $signatures; var $help; - function IXR_IntrospectionServer() { + + function IXR_IntrospectionServer() + { $this->setCallbacks(); $this->setCapabilities(); $this->capabilities['introspection'] = array( @@ -749,16 +946,21 @@ class IXR_IntrospectionServer extends IXR_Server { 'Returns a documentation string for the specified method' ); } - function addCallback($method, $callback, $args, $help) { + + function addCallback($method, $callback, $args, $help) + { $this->callbacks[$method] = $callback; $this->signatures[$method] = $args; $this->help[$method] = $help; } - function call($methodname, $args) { + + function call($methodname, $args) + { // Make sure it's in an array if ($args && !is_array($args)) { $args = array($args); } + // Over-rides default call method, adds signature check if (!$this->hasMethod($methodname)) { return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.'); @@ -766,10 +968,12 @@ class IXR_IntrospectionServer extends IXR_Server { $method = $this->callbacks[$methodname]; $signature = $this->signatures[$methodname]; $returnType = array_shift($signature); + // Check the number of arguments if (count($args) != count($signature)) { return new IXR_Error(-32602, 'server error. wrong number of method parameters'); } + // Check the argument types $ok = true; $argsbackup = $args; @@ -814,7 +1018,9 @@ class IXR_IntrospectionServer extends IXR_Server { // It passed the test - run the "real" method call return parent::call($methodname, $argsbackup); } - function methodSignature($method) { + + function methodSignature($method) + { if (!$this->hasMethod($method)) { return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.'); } @@ -852,7 +1058,9 @@ class IXR_IntrospectionServer extends IXR_Server { } return $return; } - function methodHelp($method) { + + function methodHelp($method) + { return $this->help[$method]; } } @@ -861,15 +1069,20 @@ class IXR_IntrospectionServer extends IXR_Server { * IXR_ClientMulticall * * @package IXR - * @since 1.5 + * @since 1.5.0 */ -class IXR_ClientMulticall extends IXR_Client { +class IXR_ClientMulticall extends IXR_Client +{ var $calls = array(); - function IXR_ClientMulticall($server, $path = false, $port = 80) { + + function IXR_ClientMulticall($server, $path = false, $port = 80) + { parent::IXR_Client($server, $path, $port); $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)'; } - function addCall() { + + function addCall() + { $args = func_get_args(); $methodName = array_shift($args); $struct = array( @@ -878,10 +1091,10 @@ class IXR_ClientMulticall extends IXR_Client { ); $this->calls[] = $struct; } - function query() { + + function query() + { // Prepare multicall, then call the parent::query() method return parent::query('system.multicall', $this->calls); } } - -?>