]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/class-IXR.php
Wordpress 3.6-scripts
[autoinstalls/wordpress.git] / wp-includes / class-IXR.php
index 2b23a1d1357afdf77f07ce12751929f10750e9ab..f8fbc00b10f67b8d154c4dc9a8e8d50bf8de229a 100644 (file)
@@ -1,23 +1,63 @@
 <?php
 <?php
-/*
-   IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002-2005
-   Version 1.7 (beta) - Simon Willison, 23rd May 2005
-   Site:   http://scripts.incutio.com/xmlrpc/
-   Manual: http://scripts.incutio.com/xmlrpc/manual.php
-   Made available under the BSD License: http://www.opensource.org/licenses/bsd-license.php
-*/
+/**
+ * IXR - The Incutio XML-RPC Library
+ *
+ * Copyright (c) 2010, Incutio Ltd.
+ * 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 Incutio Ltd. 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 COPYRIGHT HOLDER 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.
+ *
+ * @package IXR
+ * @since 1.5
+ *
+ * @copyright  Incutio Ltd 2010 (http://www.incutio.com)
+ * @version    1.7.4 7th September 2010
+ * @author     Simon Willison
+ * @link       http://scripts.incutio.com/xmlrpc/ Site/manual
+ * @license    http://www.opensource.org/licenses/bsd-license.php BSD
+ */
 
 
+/**
+ * IXR_Value
+ *
+ * @package IXR
+ * @since 1.5
+ */
 class IXR_Value {
     var $data;
     var $type;
 class IXR_Value {
     var $data;
     var $type;
-    function IXR_Value ($data, $type = false) {
+
+    function IXR_Value($data, $type = false)
+    {
         $this->data = $data;
         if (!$type) {
             $type = $this->calculateType();
         }
         $this->type = $type;
         if ($type == 'struct') {
         $this->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);
             }
             foreach ($this->data as $key => $value) {
                 $this->data[$key] = new IXR_Value($value);
             }
@@ -28,7 +68,9 @@ class IXR_Value {
             }
         }
     }
             }
         }
     }
-    function calculateType() {
+
+    function calculateType()
+    {
         if ($this->data === true || $this->data === false) {
             return 'boolean';
         }
         if ($this->data === true || $this->data === false) {
             return 'boolean';
         }
@@ -38,6 +80,7 @@ class IXR_Value {
         if (is_double($this->data)) {
             return 'double';
         }
         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';
         // Deal with IXR object types base64 and date
         if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
             return 'date';
@@ -45,24 +88,27 @@ class IXR_Value {
         if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
             return 'base64';
         }
         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)) {
         // 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';
         }
             $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 {
             return 'array';
         }
     }
         if ($this->isStruct($this->data)) {
             return 'struct';
         } else {
             return 'array';
         }
     }
-    function getXml() {
-        /* Return XML for this value */
+
+    function getXml()
+    {
+        // Return XML for this value
         switch ($this->type) {
             case 'boolean':
                 return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
         switch ($this->type) {
             case 'boolean':
                 return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
@@ -101,8 +147,15 @@ class IXR_Value {
         }
         return false;
     }
         }
         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) {
         $expected = 0;
         foreach ($array as $key => $value) {
             if ((string)$key != (string)$expected) {
@@ -114,14 +167,22 @@ class IXR_Value {
     }
 }
 
     }
 }
 
-
-class IXR_Message {
+/**
+ * IXR_MESSAGE
+ *
+ * @package IXR
+ * @since 1.5
+ *
+ */
+class IXR_Message
+{
     var $message;
     var $messageType;  // methodCall / methodResponse / fault
     var $faultCode;
     var $faultString;
     var $methodName;
     var $params;
     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
     // 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
@@ -132,12 +193,18 @@ class IXR_Message {
     var $_currentTagContents;
     // The XML parser
     var $_parser;
     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
         // first remove the XML declaration
-        $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
+        // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages
+        $header = preg_replace( '/<\?xml.*?\?'.'>/', '', substr($this->message, 0, 100), 1);
+        $this->message = substr_replace($this->message, $header, 0, 100);
         if (trim($this->message) == '') {
             return false;
         }
         if (trim($this->message) == '') {
             return false;
         }
@@ -148,13 +215,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');
         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);
         xml_parser_free($this->_parser);
+
         // Grab the error messages, if any
         if ($this->messageType == 'fault') {
             $this->faultCode = $this->params[0]['faultCode'];
         // Grab the error messages, if any
         if ($this->messageType == 'fault') {
             $this->faultCode = $this->params[0]['faultCode'];
@@ -162,8 +239,10 @@ class IXR_Message {
         }
         return true;
     }
         }
         return true;
     }
-    function tag_open($parser, $tag, $attr) {
-               $this->_currentTagContents = '';
+
+    function tag_open($parser, $tag, $attr)
+    {
+        $this->_currentTagContents = '';
         $this->currentTag = $tag;
         switch($tag) {
             case 'methodCall':
         $this->currentTag = $tag;
         switch($tag) {
             case 'methodCall':
@@ -171,7 +250,7 @@ class IXR_Message {
             case 'fault':
                 $this->messageType = $tag;
                 break;
             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();
             case 'data':    // data is to all intents and puposes more interesting than array
                 $this->_arraystructstypes[] = 'array';
                 $this->_arraystructs[] = array();
@@ -182,28 +261,31 @@ class IXR_Message {
                 break;
         }
     }
                 break;
         }
     }
-    function cdata($parser, $cdata) {
+
+    function cdata($parser, $cdata)
+    {
         $this->_currentTagContents .= $cdata;
     }
         $this->_currentTagContents .= $cdata;
     }
-    function tag_close($parser, $tag) {
+
+    function tag_close($parser, $tag)
+    {
         $valueFlag = false;
         switch($tag) {
             case 'int':
             case 'i4':
         $valueFlag = false;
         switch($tag) {
             case 'int':
             case 'i4':
-                $value = (int) trim($this->_currentTagContents);
+                $value = (int)trim($this->_currentTagContents);
                 $valueFlag = true;
                 break;
             case 'double':
                 $valueFlag = true;
                 break;
             case 'double':
-                $value = (double) trim($this->_currentTagContents);
+                $value = (double)trim($this->_currentTagContents);
                 $valueFlag = true;
                 break;
             case 'string':
                 $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));
                 $valueFlag = true;
                 break;
             case 'dateTime.iso8601':
                 $value = new IXR_Date(trim($this->_currentTagContents));
-                // $value = $iso->getTimestamp();
                 $valueFlag = true;
                 break;
             case 'value':
                 $valueFlag = true;
                 break;
             case 'value':
@@ -214,14 +296,14 @@ class IXR_Message {
                 }
                 break;
             case 'boolean':
                 }
                 break;
             case 'boolean':
-                $value = (boolean) trim($this->_currentTagContents);
+                $value = (boolean)trim($this->_currentTagContents);
                 $valueFlag = true;
                 break;
             case 'base64':
                 $valueFlag = true;
                 break;
             case 'base64':
-                $value = base64_decode( trim( $this->_currentTagContents ) );
+                $value = base64_decode($this->_currentTagContents);
                 $valueFlag = true;
                 break;
                 $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);
             case 'data':
             case 'struct':
                 $value = array_pop($this->_arraystructs);
@@ -238,6 +320,7 @@ class IXR_Message {
                 $this->methodName = trim($this->_currentTagContents);
                 break;
         }
                 $this->methodName = trim($this->_currentTagContents);
                 break;
         }
+
         if ($valueFlag) {
             if (count($this->_arraystructs) > 0) {
                 // Add value to struct or array
         if ($valueFlag) {
             if (count($this->_arraystructs) > 0) {
                 // Add value to struct or array
@@ -253,31 +336,50 @@ class IXR_Message {
                 $this->params[] = $value;
             }
         }
                 $this->params[] = $value;
             }
         }
-               $this->_currentTagContents = '';
+        $this->_currentTagContents = '';
     }
 }
 
     }
 }
 
-
-class IXR_Server {
+/**
+ * IXR_Server
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Server
+{
     var $data;
     var $callbacks = array();
     var $message;
     var $capabilities;
     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->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 (!$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;
             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()) {
         }
         $this->message = new IXR_Message($data);
         if (!$this->message->parse()) {
@@ -287,114 +389,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);
             $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);
         }
         // 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();
         // Encode the result
         $r = new IXR_Value($result);
         $resultxml = $r->getXml();
+
         // Create the XML
         $xml = <<<EOD
 <methodResponse>
   <params>
     <param>
       <value>
         // Create the XML
         $xml = <<<EOD
 <methodResponse>
   <params>
     <param>
       <value>
-        $resultxml
+      $resultxml
       </value>
     </param>
   </params>
 </methodResponse>
 
 EOD;
       </value>
     </param>
   </params>
 </methodResponse>
 
 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.');
         }
         $method = $this->callbacks[$methodname];
         if (!$this->hasMethod($methodname)) {
             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
             $args = $args[0];
         }
         // Perform the callback and send the response
         if (count($args) == 1) {
             // If only one paramater just send that instead of the whole array
             $args = $args[0];
         }
+
         // Are we dealing with a function or a method?
         // 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.');
             }
             // 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.');
             }
-            // Call the method
+
+            //Call the method
             $result = $this->$method($args);
         } else {
             // It's a function - does it exist?
             if (is_array($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.');
             }
             } else if (!function_exists($method)) {
                 return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
             }
+
             // Call the function
             $result = call_user_func($method, $args);
         }
         return $result;
     }
 
             // 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());
     }
         // 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 = '<?xml version="1.0"?>'."\n".$xml;
+
+    function output($xml)
+    {
+        $charset = function_exists('get_option') ? get_option('blog_charset') : '';
+        if ($charset)
+            $xml = '<?xml version="1.0" encoding="'.$charset.'"?>'."\n".$xml;
+        else
+            $xml = '<?xml version="1.0"?>'."\n".$xml;
         $length = strlen($xml);
         header('Connection: close');
         header('Content-Length: '.$length);
         $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;
     }
         header('Date: '.date('r'));
         echo $xml;
         exit;
     }
-    function hasMethod($method) {
+
+    function hasMethod($method)
+    {
         return in_array($method, array_keys($this->callbacks));
     }
         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
         // 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
             '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
             'system.multicall' => array(
                 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
                 'specVersion' => 1
-            ),
+        ),
         );
     }
         );
     }
-    function getCapabilities($args) {
+
+    function getCapabilities($args)
+    {
         return $this->capabilities;
     }
         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';
     }
         $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));
     }
         // 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) {
         // See http://www.xmlrpc.com/discuss/msgReader$1208
         $return = array();
         foreach ($methodcalls as $call) {
@@ -418,11 +551,20 @@ EOD;
     }
 }
 
     }
 }
 
-class IXR_Request {
+/**
+ * IXR_Request
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Request
+{
     var $method;
     var $args;
     var $xml;
     var $method;
     var $args;
     var $xml;
-    function IXR_Request($method, $args) {
+
+    function IXR_Request($method, $args)
+    {
         $this->method = $method;
         $this->args = $args;
         $this->xml = <<<EOD
         $this->method = $method;
         $this->args = $args;
         $this->xml = <<<EOD
@@ -440,16 +582,27 @@ EOD;
         }
         $this->xml .= '</params></methodCall>';
     }
         }
         $this->xml .= '</params></methodCall>';
     }
-    function getLength() {
+
+    function getLength()
+    {
         return strlen($this->xml);
     }
         return strlen($this->xml);
     }
-    function getXml() {
+
+    function getXml()
+    {
         return $this->xml;
     }
 }
 
         return $this->xml;
     }
 }
 
-
-class IXR_Client {
+/**
+ * IXR_Client
+ *
+ * @package IXR
+ * @since 1.5
+ *
+ */
+class IXR_Client
+{
     var $server;
     var $port;
     var $path;
     var $server;
     var $port;
     var $path;
@@ -457,16 +610,21 @@ class IXR_Client {
     var $response;
     var $message = false;
     var $debug = false;
     var $response;
     var $message = false;
     var $debug = false;
-       var $timeout;
+    var $timeout;
+    var $headers = array();
+
     // Storage place for an error message
     var $error = false;
     // 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'] : '/';
         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 = '/';
             // Make absolutely sure we have a path
             if (!$this->path) {
                 $this->path = '/';
@@ -476,10 +634,12 @@ class IXR_Client {
             $this->path = $path;
             $this->port = $port;
         }
             $this->path = $path;
             $this->port = $port;
         }
-        $this->useragent = 'Incutio XML-RPC';
-               $this->timeout = $timeout;
+        $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);
         $args = func_get_args();
         $method = array_shift($args);
         $request = new IXR_Request($method, $args);
@@ -487,26 +647,37 @@ class IXR_Client {
         $xml = $request->getXml();
         $r = "\r\n";
         $request  = "POST {$this->path} HTTP/1.0$r";
         $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;
         $request .= $xml;
+
         // Now send the request
         if ($this->debug) {
         // Now send the request
         if ($this->debug) {
-            echo '<pre>'.htmlspecialchars($request)."\n</pre>\n\n";
+            echo '<pre class="ixr_request">'.htmlspecialchars($request)."\n</pre>\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) {
         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 = '';
             return false;
         }
         fputs($fp, $request);
         $contents = '';
+        $debugContents = '';
         $gotFirstLine = false;
         $gettingHeaders = true;
         while (!feof($fp)) {
         $gotFirstLine = false;
         $gettingHeaders = true;
         while (!feof($fp)) {
@@ -523,12 +694,17 @@ class IXR_Client {
                 $gettingHeaders = false;
             }
             if (!$gettingHeaders) {
                 $gettingHeaders = false;
             }
             if (!$gettingHeaders) {
-                $contents .= trim($line)."\n";
+               // merged from WP #12559 - remove trim
+                $contents .= $line;
+            }
+            if ($this->debug) {
+               $debugContents .= $line;
             }
         }
         if ($this->debug) {
             }
         }
         if ($this->debug) {
-            echo '<pre>'.htmlspecialchars($contents)."\n</pre>\n\n";
+            echo '<pre class="ixr_response">'.htmlspecialchars($debugContents)."\n</pre>\n\n";
         }
         }
+
         // Now parse what we've got back
         $this->message = new IXR_Message($contents);
         if (!$this->message->parse()) {
         // Now parse what we've got back
         $this->message = new IXR_Message($contents);
         if (!$this->message->parse()) {
@@ -536,38 +712,59 @@ class IXR_Client {
             $this->error = new IXR_Error(-32700, 'parse error. not well formed');
             return false;
         }
             $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;
         }
         // 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;
     }
         // Message must be OK
         return true;
     }
-    function getResponse() {
+
+    function getResponse()
+    {
         // methodResponses can only have one param - return that
         return $this->message->params[0];
     }
         // methodResponses can only have one param - return that
         return $this->message->params[0];
     }
-    function isError() {
+
+    function isError()
+    {
         return (is_object($this->error));
     }
         return (is_object($this->error));
     }
-    function getErrorCode() {
+
+    function getErrorCode()
+    {
         return $this->error->code;
     }
         return $this->error->code;
     }
-    function getErrorMessage() {
+
+    function getErrorMessage()
+    {
         return $this->error->message;
     }
 }
 
 
         return $this->error->message;
     }
 }
 
 
-class IXR_Error {
+/**
+ * IXR_Error
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Error
+{
     var $code;
     var $message;
     var $code;
     var $message;
-    function IXR_Error($code, $message) {
+
+    function IXR_Error($code, $message)
+    {
         $this->code = $code;
         $this->code = $code;
-        $this->message = $message;
+        $this->message = htmlspecialchars($message);
     }
     }
-    function getXml() {
+
+    function getXml()
+    {
         $xml = <<<EOD
 <methodResponse>
   <fault>
         $xml = <<<EOD
 <methodResponse>
   <fault>
@@ -591,7 +788,12 @@ EOD;
     }
 }
 
     }
 }
 
-
+/**
+ * IXR_Date
+ *
+ * @package IXR
+ * @since 1.5
+ */
 class IXR_Date {
     var $year;
     var $month;
 class IXR_Date {
     var $year;
     var $month;
@@ -599,7 +801,10 @@ class IXR_Date {
     var $hour;
     var $minute;
     var $second;
     var $hour;
     var $minute;
     var $second;
-    function IXR_Date($time) {
+    var $timezone;
+
+    function IXR_Date($time)
+    {
         // $time can be a PHP timestamp or an ISO one
         if (is_numeric($time)) {
             $this->parseTimestamp($time);
         // $time can be a PHP timestamp or an ISO one
         if (is_numeric($time)) {
             $this->parseTimestamp($time);
@@ -607,15 +812,20 @@ class IXR_Date {
             $this->parseIso($time);
         }
     }
             $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);
         $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);
+        $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->year = substr($iso, 0, 4);
         $this->month = substr($iso, 4, 2);
         $this->day = substr($iso, 6, 2);
@@ -624,33 +834,57 @@ class IXR_Date {
         $this->second = substr($iso, 15, 2);
         $this->timezone = substr($iso, 17);
     }
         $this->second = substr($iso, 15, 2);
         $this->timezone = substr($iso, 17);
     }
-    function getIso() {
+
+    function getIso()
+    {
         return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
     }
         return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
     }
-    function getXml() {
+
+    function getXml()
+    {
         return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
     }
         return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
     }
-    function getTimestamp() {
+
+    function getTimestamp()
+    {
         return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
     }
 }
 
         return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
     }
 }
 
-
-class IXR_Base64 {
+/**
+ * IXR_Base64
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Base64
+{
     var $data;
     var $data;
-    function IXR_Base64($data) {
+
+    function IXR_Base64($data)
+    {
         $this->data = $data;
     }
         $this->data = $data;
     }
-    function getXml() {
+
+    function getXml()
+    {
         return '<base64>'.base64_encode($this->data).'</base64>';
     }
 }
 
         return '<base64>'.base64_encode($this->data).'</base64>';
     }
 }
 
-
-class IXR_IntrospectionServer extends IXR_Server {
+/**
+ * IXR_IntrospectionServer
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_IntrospectionServer extends IXR_Server
+{
     var $signatures;
     var $help;
     var $signatures;
     var $help;
-    function IXR_IntrospectionServer() {
+
+    function IXR_IntrospectionServer()
+    {
         $this->setCallbacks();
         $this->setCapabilities();
         $this->capabilities['introspection'] = array(
         $this->setCallbacks();
         $this->setCapabilities();
         $this->capabilities['introspection'] = array(
@@ -682,16 +916,21 @@ class IXR_IntrospectionServer extends IXR_Server {
             'Returns a documentation string for the specified method'
         );
     }
             '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;
     }
         $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);
         }
         // 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.');
         // 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.');
@@ -699,10 +938,12 @@ class IXR_IntrospectionServer extends IXR_Server {
         $method = $this->callbacks[$methodname];
         $signature = $this->signatures[$methodname];
         $returnType = array_shift($signature);
         $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 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;
         // Check the argument types
         $ok = true;
         $argsbackup = $args;
@@ -747,7 +988,9 @@ class IXR_IntrospectionServer extends IXR_Server {
         // It passed the test - run the "real" method call
         return parent::call($methodname, $argsbackup);
     }
         // 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.');
         }
         if (!$this->hasMethod($method)) {
             return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
         }
@@ -785,19 +1028,31 @@ class IXR_IntrospectionServer extends IXR_Server {
         }
         return $return;
     }
         }
         return $return;
     }
-    function methodHelp($method) {
+
+    function methodHelp($method)
+    {
         return $this->help[$method];
     }
 }
 
         return $this->help[$method];
     }
 }
 
-
-class IXR_ClientMulticall extends IXR_Client {
+/**
+ * IXR_ClientMulticall
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_ClientMulticall extends IXR_Client
+{
     var $calls = array();
     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)';
     }
         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(
         $args = func_get_args();
         $methodName = array_shift($args);
         $struct = array(
@@ -806,10 +1061,10 @@ class IXR_ClientMulticall extends IXR_Client {
         );
         $this->calls[] = $struct;
     }
         );
         $this->calls[] = $struct;
     }
-    function query() {
+
+    function query()
+    {
         // Prepare multicall, then call the parent::query() method
         return parent::query('system.multicall', $this->calls);
     }
 }
         // Prepare multicall, then call the parent::query() method
         return parent::query('system.multicall', $this->calls);
     }
 }
-
-?>
\ No newline at end of file