web/wp-includes/class-IXR.php
changeset 194 32102edaa81b
parent 136 bde1974c263b
child 204 09a1c134465b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * IXR - The Inutio XML-RPC Library
     3  * IXR - The Incutio XML-RPC Library
       
     4  *
       
     5  * Copyright (c) 2010, Incutio Ltd.
       
     6  * All rights reserved.
       
     7  *
       
     8  * Redistribution and use in source and binary forms, with or without
       
     9  * modification, are permitted provided that the following conditions are met:
       
    10  *
       
    11  *  - Redistributions of source code must retain the above copyright notice,
       
    12  *    this list of conditions and the following disclaimer.
       
    13  *  - Redistributions in binary form must reproduce the above copyright
       
    14  *    notice, this list of conditions and the following disclaimer in the
       
    15  *    documentation and/or other materials provided with the distribution.
       
    16  *  - Neither the name of Incutio Ltd. nor the names of its contributors
       
    17  *    may be used to endorse or promote products derived from this software
       
    18  *    without specific prior written permission.
       
    19  *
       
    20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
       
    24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    28  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
       
    30  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     4  *
    31  *
     5  * @package IXR
    32  * @package IXR
     6  * @since 1.5
    33  * @since 1.5
     7  *
    34  *
     8  * @copyright Incutio Ltd 2002-2005
    35  * @copyright  Incutio Ltd 2010 (http://www.incutio.com)
     9  * @version 1.7 (beta) 23rd May 2005
    36  * @version    1.7.4 7th September 2010
    10  * @author Simon Willison
    37  * @author     Simon Willison
    11  * @link http://scripts.incutio.com/xmlrpc/ Site
    38  * @link       http://scripts.incutio.com/xmlrpc/ Site/manual
    12  * @link http://scripts.incutio.com/xmlrpc/manual.php Manual
    39  * @license    http://www.opensource.org/licenses/bsd-license.php BSD
    13  * @license BSD License http://www.opensource.org/licenses/bsd-license.php
       
    14  */
    40  */
    15 
    41 
    16 /**
    42 /**
    17  * IXR_Value
    43  * IXR_Value
    18  *
    44  *
    21  */
    47  */
    22 class IXR_Value {
    48 class IXR_Value {
    23     var $data;
    49     var $data;
    24     var $type;
    50     var $type;
    25 
    51 
    26     function IXR_Value ($data, $type = false) {
    52     function IXR_Value($data, $type = false)
       
    53     {
    27         $this->data = $data;
    54         $this->data = $data;
    28         if (!$type) {
    55         if (!$type) {
    29             $type = $this->calculateType();
    56             $type = $this->calculateType();
    30         }
    57         }
    31         $this->type = $type;
    58         $this->type = $type;
    32         if ($type == 'struct') {
    59         if ($type == 'struct') {
    33             /* Turn all the values in the array in to new IXR_Value objects */
    60             // Turn all the values in the array in to new IXR_Value objects
    34             foreach ($this->data as $key => $value) {
    61             foreach ($this->data as $key => $value) {
    35                 $this->data[$key] = new IXR_Value($value);
    62                 $this->data[$key] = new IXR_Value($value);
    36             }
    63             }
    37         }
    64         }
    38         if ($type == 'array') {
    65         if ($type == 'array') {
    40                 $this->data[$i] = new IXR_Value($this->data[$i]);
    67                 $this->data[$i] = new IXR_Value($this->data[$i]);
    41             }
    68             }
    42         }
    69         }
    43     }
    70     }
    44 
    71 
    45     function calculateType() {
    72     function calculateType()
       
    73     {
    46         if ($this->data === true || $this->data === false) {
    74         if ($this->data === true || $this->data === false) {
    47             return 'boolean';
    75             return 'boolean';
    48         }
    76         }
    49         if (is_integer($this->data)) {
    77         if (is_integer($this->data)) {
    50             return 'int';
    78             return 'int';
    51         }
    79         }
    52         if (is_double($this->data)) {
    80         if (is_double($this->data)) {
    53             return 'double';
    81             return 'double';
    54         }
    82         }
       
    83 
    55         // Deal with IXR object types base64 and date
    84         // Deal with IXR object types base64 and date
    56         if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
    85         if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
    57             return 'date';
    86             return 'date';
    58         }
    87         }
    59         if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
    88         if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
    60             return 'base64';
    89             return 'base64';
    61         }
    90         }
       
    91 
    62         // If it is a normal PHP object convert it in to a struct
    92         // If it is a normal PHP object convert it in to a struct
    63         if (is_object($this->data)) {
    93         if (is_object($this->data)) {
    64 
       
    65             $this->data = get_object_vars($this->data);
    94             $this->data = get_object_vars($this->data);
    66             return 'struct';
    95             return 'struct';
    67         }
    96         }
    68         if (!is_array($this->data)) {
    97         if (!is_array($this->data)) {
    69             return 'string';
    98             return 'string';
    70         }
    99         }
    71         /* We have an array - is it an array or a struct ? */
   100 
       
   101         // We have an array - is it an array or a struct?
    72         if ($this->isStruct($this->data)) {
   102         if ($this->isStruct($this->data)) {
    73             return 'struct';
   103             return 'struct';
    74         } else {
   104         } else {
    75             return 'array';
   105             return 'array';
    76         }
   106         }
    77     }
   107     }
    78 
   108 
    79     function getXml() {
   109     function getXml()
    80         /* Return XML for this value */
   110     {
       
   111         // Return XML for this value
    81         switch ($this->type) {
   112         switch ($this->type) {
    82             case 'boolean':
   113             case 'boolean':
    83                 return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
   114                 return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
    84                 break;
   115                 break;
    85             case 'int':
   116             case 'int':
   115                 break;
   146                 break;
   116         }
   147         }
   117         return false;
   148         return false;
   118     }
   149     }
   119 
   150 
   120     function isStruct($array) {
   151     /**
   121         /* Nasty function to check if an array is a struct or not */
   152      * Checks whether or not the supplied array is a struct or not
       
   153      *
       
   154      * @param unknown_type $array
       
   155      * @return boolean
       
   156      */
       
   157     function isStruct($array)
       
   158     {
   122         $expected = 0;
   159         $expected = 0;
   123         foreach ($array as $key => $value) {
   160         foreach ($array as $key => $value) {
   124             if ((string)$key != (string)$expected) {
   161             if ((string)$key != (string)$expected) {
   125                 return true;
   162                 return true;
   126             }
   163             }
   129         return false;
   166         return false;
   130     }
   167     }
   131 }
   168 }
   132 
   169 
   133 /**
   170 /**
   134  * IXR_Message
   171  * IXR_MESSAGE
   135  *
   172  *
   136  * @package IXR
   173  * @package IXR
   137  * @since 1.5
   174  * @since 1.5
       
   175  *
   138  */
   176  */
   139 class IXR_Message {
   177 class IXR_Message
       
   178 {
   140     var $message;
   179     var $message;
   141     var $messageType;  // methodCall / methodResponse / fault
   180     var $messageType;  // methodCall / methodResponse / fault
   142     var $faultCode;
   181     var $faultCode;
   143     var $faultString;
   182     var $faultString;
   144     var $methodName;
   183     var $methodName;
   145     var $params;
   184     var $params;
       
   185 
   146     // Current variable stacks
   186     // Current variable stacks
   147     var $_arraystructs = array();   // The stack used to keep track of the current array/struct
   187     var $_arraystructs = array();   // The stack used to keep track of the current array/struct
   148     var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
   188     var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
   149     var $_currentStructName = array();  // A stack as well
   189     var $_currentStructName = array();  // A stack as well
   150     var $_param;
   190     var $_param;
   151     var $_value;
   191     var $_value;
   152     var $_currentTag;
   192     var $_currentTag;
   153     var $_currentTagContents;
   193     var $_currentTagContents;
   154     // The XML parser
   194     // The XML parser
   155     var $_parser;
   195     var $_parser;
   156     function IXR_Message (&$message) {
   196 
   157         $this->message = &$message;
   197     function IXR_Message($message)
   158     }
   198     {
   159     function parse() {
   199         $this->message =& $message;
   160 		// first remove the XML declaration
   200     }
   161 		// this method avoids the RAM usage of preg_replace on very large messages
   201 
   162 		$header = preg_replace( '/<\?xml.*?\?'.'>/', '', substr( $this->message, 0, 100 ), 1 );
   202     function parse()
   163 		$this->message = substr_replace($this->message, $header, 0, 100);
   203     {
       
   204         // first remove the XML declaration
       
   205         // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages
       
   206         $header = preg_replace( '/<\?xml.*?\?'.'>/', '', substr($this->message, 0, 100), 1);
       
   207         $this->message = substr_replace($this->message, $header, 0, 100);
   164         if (trim($this->message) == '') {
   208         if (trim($this->message) == '') {
   165             return false;
   209             return false;
   166 		}
   210         }
   167         $this->_parser = xml_parser_create();
   211         $this->_parser = xml_parser_create();
   168         // Set XML parser to take the case of tags in to account
   212         // Set XML parser to take the case of tags in to account
   169         xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
   213         xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
   170         // Set XML parser callback functions
   214         // Set XML parser callback functions
   171         xml_set_object($this->_parser, $this);
   215         xml_set_object($this->_parser, $this);
   172         xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
   216         xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
   173 		xml_set_character_data_handler($this->_parser, 'cdata');
   217         xml_set_character_data_handler($this->_parser, 'cdata');
   174 		$chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages
   218         $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages
   175 		do {
   219         $final = false;
   176 			if ( strlen($this->message) <= $chunk_size )
   220         do {
   177 				$final=true;
   221             if (strlen($this->message) <= $chunk_size) {
   178 			$part = substr( $this->message, 0, $chunk_size );
   222                 $final = true;
   179 			$this->message = substr( $this->message, $chunk_size );
   223             }
   180 			if ( !xml_parse( $this->_parser, $part, $final ) )
   224             $part = substr($this->message, 0, $chunk_size);
   181 				return false;
   225             $this->message = substr($this->message, $chunk_size);
   182 			if ( $final )
   226             if (!xml_parse($this->_parser, $part, $final)) {
   183 				break;
   227                 return false;
   184 		} while ( true );
   228             }
   185 		xml_parser_free($this->_parser);
   229             if ($final) {
       
   230                 break;
       
   231             }
       
   232         } while (true);
       
   233         xml_parser_free($this->_parser);
       
   234 
   186         // Grab the error messages, if any
   235         // Grab the error messages, if any
   187         if ($this->messageType == 'fault') {
   236         if ($this->messageType == 'fault') {
   188             $this->faultCode = $this->params[0]['faultCode'];
   237             $this->faultCode = $this->params[0]['faultCode'];
   189             $this->faultString = $this->params[0]['faultString'];
   238             $this->faultString = $this->params[0]['faultString'];
   190 		}
   239         }
   191         return true;
   240         return true;
   192     }
   241     }
   193     function tag_open($parser, $tag, $attr) {
   242 
       
   243     function tag_open($parser, $tag, $attr)
       
   244     {
   194         $this->_currentTagContents = '';
   245         $this->_currentTagContents = '';
   195         $this->currentTag = $tag;
   246         $this->currentTag = $tag;
   196         switch($tag) {
   247         switch($tag) {
   197             case 'methodCall':
   248             case 'methodCall':
   198             case 'methodResponse':
   249             case 'methodResponse':
   199             case 'fault':
   250             case 'fault':
   200                 $this->messageType = $tag;
   251                 $this->messageType = $tag;
   201                 break;
   252                 break;
   202             /* Deal with stacks of arrays and structs */
   253                 /* Deal with stacks of arrays and structs */
   203             case 'data':    // data is to all intents and puposes more interesting than array
   254             case 'data':    // data is to all intents and puposes more interesting than array
   204                 $this->_arraystructstypes[] = 'array';
   255                 $this->_arraystructstypes[] = 'array';
   205                 $this->_arraystructs[] = array();
   256                 $this->_arraystructs[] = array();
   206                 break;
   257                 break;
   207             case 'struct':
   258             case 'struct':
   208                 $this->_arraystructstypes[] = 'struct';
   259                 $this->_arraystructstypes[] = 'struct';
   209                 $this->_arraystructs[] = array();
   260                 $this->_arraystructs[] = array();
   210                 break;
   261                 break;
   211         }
   262         }
   212     }
   263     }
   213     function cdata($parser, $cdata) {
   264 
       
   265     function cdata($parser, $cdata)
       
   266     {
   214         $this->_currentTagContents .= $cdata;
   267         $this->_currentTagContents .= $cdata;
   215     }
   268     }
   216     function tag_close($parser, $tag) {
   269 
       
   270     function tag_close($parser, $tag)
       
   271     {
   217         $valueFlag = false;
   272         $valueFlag = false;
   218         switch($tag) {
   273         switch($tag) {
   219             case 'int':
   274             case 'int':
   220             case 'i4':
   275             case 'i4':
   221                 $value = (int) trim($this->_currentTagContents);
   276                 $value = (int)trim($this->_currentTagContents);
   222                 $valueFlag = true;
   277                 $valueFlag = true;
   223                 break;
   278                 break;
   224             case 'double':
   279             case 'double':
   225                 $value = (double) trim($this->_currentTagContents);
   280                 $value = (double)trim($this->_currentTagContents);
   226                 $valueFlag = true;
   281                 $valueFlag = true;
   227                 break;
   282                 break;
   228             case 'string':
   283             case 'string':
   229                 $value = $this->_currentTagContents;
   284                 $value = (string)trim($this->_currentTagContents);
   230                 $valueFlag = true;
   285                 $valueFlag = true;
   231                 break;
   286                 break;
   232             case 'dateTime.iso8601':
   287             case 'dateTime.iso8601':
   233                 $value = new IXR_Date(trim($this->_currentTagContents));
   288                 $value = new IXR_Date(trim($this->_currentTagContents));
   234                 // $value = $iso->getTimestamp();
       
   235                 $valueFlag = true;
   289                 $valueFlag = true;
   236                 break;
   290                 break;
   237             case 'value':
   291             case 'value':
   238                 // "If no type is indicated, the type is string."
   292                 // "If no type is indicated, the type is string."
   239                 if (trim($this->_currentTagContents) != '') {
   293                 if (trim($this->_currentTagContents) != '') {
   240                     $value = (string)$this->_currentTagContents;
   294                     $value = (string)$this->_currentTagContents;
   241                     $valueFlag = true;
   295                     $valueFlag = true;
   242                 }
   296                 }
   243                 break;
   297                 break;
   244             case 'boolean':
   298             case 'boolean':
   245                 $value = (boolean) trim($this->_currentTagContents);
   299                 $value = (boolean)trim($this->_currentTagContents);
   246                 $valueFlag = true;
   300                 $valueFlag = true;
   247                 break;
   301                 break;
   248             case 'base64':
   302             case 'base64':
   249                 $value = base64_decode( trim( $this->_currentTagContents ) );
   303                 $value = base64_decode($this->_currentTagContents);
   250                 $valueFlag = true;
   304                 $valueFlag = true;
   251                 break;
   305                 break;
   252             /* Deal with stacks of arrays and structs */
   306                 /* Deal with stacks of arrays and structs */
   253             case 'data':
   307             case 'data':
   254             case 'struct':
   308             case 'struct':
   255                 $value = array_pop($this->_arraystructs);
   309                 $value = array_pop($this->_arraystructs);
   256                 array_pop($this->_arraystructstypes);
   310                 array_pop($this->_arraystructstypes);
   257                 $valueFlag = true;
   311                 $valueFlag = true;
   264                 break;
   318                 break;
   265             case 'methodName':
   319             case 'methodName':
   266                 $this->methodName = trim($this->_currentTagContents);
   320                 $this->methodName = trim($this->_currentTagContents);
   267                 break;
   321                 break;
   268         }
   322         }
       
   323 
   269         if ($valueFlag) {
   324         if ($valueFlag) {
   270             if (count($this->_arraystructs) > 0) {
   325             if (count($this->_arraystructs) > 0) {
   271                 // Add value to struct or array
   326                 // Add value to struct or array
   272                 if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
   327                 if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
   273                     // Add to struct
   328                     // Add to struct
   289  * IXR_Server
   344  * IXR_Server
   290  *
   345  *
   291  * @package IXR
   346  * @package IXR
   292  * @since 1.5
   347  * @since 1.5
   293  */
   348  */
   294 class IXR_Server {
   349 class IXR_Server
       
   350 {
   295     var $data;
   351     var $data;
   296     var $callbacks = array();
   352     var $callbacks = array();
   297     var $message;
   353     var $message;
   298     var $capabilities;
   354     var $capabilities;
   299     function IXR_Server($callbacks = false, $data = false) {
   355 
       
   356     function IXR_Server($callbacks = false, $data = false, $wait = false)
       
   357     {
   300         $this->setCapabilities();
   358         $this->setCapabilities();
   301         if ($callbacks) {
   359         if ($callbacks) {
   302             $this->callbacks = $callbacks;
   360             $this->callbacks = $callbacks;
   303         }
   361         }
   304         $this->setCallbacks();
   362         $this->setCallbacks();
   305         $this->serve($data);
   363         if (!$wait) {
   306     }
   364             $this->serve($data);
   307     function serve($data = false) {
   365         }
       
   366     }
       
   367 
       
   368     function serve($data = false)
       
   369     {
   308         if (!$data) {
   370         if (!$data) {
       
   371             if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') {
       
   372             	header('Content-Type: text/plain'); // merged from WP #9093
       
   373                 die('XML-RPC server accepts POST requests only.');
       
   374             }
       
   375 
   309             global $HTTP_RAW_POST_DATA;
   376             global $HTTP_RAW_POST_DATA;
   310             if (!$HTTP_RAW_POST_DATA) {
   377             if (empty($HTTP_RAW_POST_DATA)) {
   311                header( 'Content-Type: text/plain' );
   378                 // workaround for a bug in PHP 5.2.2 - http://bugs.php.net/bug.php?id=41293
   312                die('XML-RPC server accepts POST requests only.');
   379                 $data = file_get_contents('php://input');
   313             }
   380             } else {
   314             $data = &$HTTP_RAW_POST_DATA;
   381                 $data =& $HTTP_RAW_POST_DATA;
       
   382             }
   315         }
   383         }
   316         $this->message = new IXR_Message($data);
   384         $this->message = new IXR_Message($data);
   317         if (!$this->message->parse()) {
   385         if (!$this->message->parse()) {
   318             $this->error(-32700, 'parse error. not well formed');
   386             $this->error(-32700, 'parse error. not well formed');
   319         }
   387         }
   320         if ($this->message->messageType != 'methodCall') {
   388         if ($this->message->messageType != 'methodCall') {
   321             $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
   389             $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
   322         }
   390         }
   323         $result = $this->call($this->message->methodName, $this->message->params);
   391         $result = $this->call($this->message->methodName, $this->message->params);
       
   392 
   324         // Is the result an error?
   393         // Is the result an error?
   325         if (is_a($result, 'IXR_Error')) {
   394         if (is_a($result, 'IXR_Error')) {
   326             $this->error($result);
   395             $this->error($result);
   327         }
   396         }
       
   397 
   328         // Encode the result
   398         // Encode the result
   329         $r = new IXR_Value($result);
   399         $r = new IXR_Value($result);
   330         $resultxml = $r->getXml();
   400         $resultxml = $r->getXml();
       
   401 
   331         // Create the XML
   402         // Create the XML
   332         $xml = <<<EOD
   403         $xml = <<<EOD
   333 <methodResponse>
   404 <methodResponse>
   334   <params>
   405   <params>
   335     <param>
   406     <param>
   336       <value>
   407       <value>
   337         $resultxml
   408       $resultxml
   338       </value>
   409       </value>
   339     </param>
   410     </param>
   340   </params>
   411   </params>
   341 </methodResponse>
   412 </methodResponse>
   342 
   413 
   343 EOD;
   414 EOD;
   344         // Send it
   415       // Send it
   345         $this->output($xml);
   416       $this->output($xml);
   346     }
   417     }
   347     function call($methodname, $args) {
   418 
       
   419     function call($methodname, $args)
       
   420     {
   348         if (!$this->hasMethod($methodname)) {
   421         if (!$this->hasMethod($methodname)) {
   349             return new IXR_Error(-32601, 'server error. requested method '.
   422             return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
   350                 $methodname.' does not exist.');
       
   351         }
   423         }
   352         $method = $this->callbacks[$methodname];
   424         $method = $this->callbacks[$methodname];
       
   425 
   353         // Perform the callback and send the response
   426         // Perform the callback and send the response
   354         if (count($args) == 1) {
   427         if (count($args) == 1) {
   355             // If only one paramater just send that instead of the whole array
   428             // If only one paramater just send that instead of the whole array
   356             $args = $args[0];
   429             $args = $args[0];
   357         }
   430         }
       
   431 
   358         // Are we dealing with a function or a method?
   432         // Are we dealing with a function or a method?
   359         if (substr($method, 0, 5) == 'this:') {
   433         if (is_string($method) && substr($method, 0, 5) == 'this:') {
   360             // It's a class method - check it exists
   434             // It's a class method - check it exists
   361             $method = substr($method, 5);
   435             $method = substr($method, 5);
   362             if (!method_exists($this, $method)) {
   436             if (!method_exists($this, $method)) {
   363                 return new IXR_Error(-32601, 'server error. requested class method "'.
   437                 return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
   364                     $method.'" does not exist.');
   438             }
   365             }
   439 
   366             // Call the method
   440             //Call the method
   367             $result = $this->$method($args);
   441             $result = $this->$method($args);
   368         } else {
   442         } else {
   369             // It's a function - does it exist?
   443             // It's a function - does it exist?
   370             if (is_array($method)) {
   444             if (is_array($method)) {
   371                 if (!method_exists($method[0], $method[1])) {
   445                 if (!is_callable(array($method[0], $method[1]))) {
   372                     return new IXR_Error(-32601, 'server error. requested object method "'.
   446                     return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.');
   373                         $method[1].'" does not exist.');
       
   374                 }
   447                 }
   375             } else if (!function_exists($method)) {
   448             } else if (!function_exists($method)) {
   376                 return new IXR_Error(-32601, 'server error. requested function "'.
   449                 return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
   377                     $method.'" does not exist.');
   450             }
   378             }
   451 
   379             // Call the function
   452             // Call the function
   380             $result = call_user_func($method, $args);
   453             $result = call_user_func($method, $args);
   381         }
   454         }
   382         return $result;
   455         return $result;
   383     }
   456     }
   384 
   457 
   385     function error($error, $message = false) {
   458     function error($error, $message = false)
       
   459     {
   386         // Accepts either an error object or an error code and message
   460         // Accepts either an error object or an error code and message
   387         if ($message && !is_object($error)) {
   461         if ($message && !is_object($error)) {
   388             $error = new IXR_Error($error, $message);
   462             $error = new IXR_Error($error, $message);
   389         }
   463         }
   390         $this->output($error->getXml());
   464         $this->output($error->getXml());
   391     }
   465     }
   392     function output($xml) {
   466 
       
   467     function output($xml)
       
   468     {
   393         $xml = '<?xml version="1.0"?>'."\n".$xml;
   469         $xml = '<?xml version="1.0"?>'."\n".$xml;
   394         $length = strlen($xml);
   470         $length = strlen($xml);
   395         header('Connection: close');
   471         header('Connection: close');
   396         header('Content-Length: '.$length);
   472         header('Content-Length: '.$length);
   397         header('Content-Type: text/xml');
   473         header('Content-Type: text/xml');
   398         header('Date: '.date('r'));
   474         header('Date: '.date('r'));
   399         echo $xml;
   475         echo $xml;
   400         exit;
   476         exit;
   401     }
   477     }
   402     function hasMethod($method) {
   478 
       
   479     function hasMethod($method)
       
   480     {
   403         return in_array($method, array_keys($this->callbacks));
   481         return in_array($method, array_keys($this->callbacks));
   404     }
   482     }
   405     function setCapabilities() {
   483 
       
   484     function setCapabilities()
       
   485     {
   406         // Initialises capabilities array
   486         // Initialises capabilities array
   407         $this->capabilities = array(
   487         $this->capabilities = array(
   408             'xmlrpc' => array(
   488             'xmlrpc' => array(
   409                 'specUrl' => 'http://www.xmlrpc.com/spec',
   489                 'specUrl' => 'http://www.xmlrpc.com/spec',
   410                 'specVersion' => 1
   490                 'specVersion' => 1
   411             ),
   491         ),
   412             'faults_interop' => array(
   492             'faults_interop' => array(
   413                 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
   493                 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
   414                 'specVersion' => 20010516
   494                 'specVersion' => 20010516
   415             ),
   495         ),
   416             'system.multicall' => array(
   496             'system.multicall' => array(
   417                 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
   497                 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
   418                 'specVersion' => 1
   498                 'specVersion' => 1
   419             ),
   499         ),
   420         );
   500         );
   421     }
   501     }
   422     function getCapabilities($args) {
   502 
       
   503     function getCapabilities($args)
       
   504     {
   423         return $this->capabilities;
   505         return $this->capabilities;
   424     }
   506     }
   425     function setCallbacks() {
   507 
       
   508     function setCallbacks()
       
   509     {
   426         $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
   510         $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
   427         $this->callbacks['system.listMethods'] = 'this:listMethods';
   511         $this->callbacks['system.listMethods'] = 'this:listMethods';
   428         $this->callbacks['system.multicall'] = 'this:multiCall';
   512         $this->callbacks['system.multicall'] = 'this:multiCall';
   429     }
   513     }
   430     function listMethods($args) {
   514 
       
   515     function listMethods($args)
       
   516     {
   431         // Returns a list of methods - uses array_reverse to ensure user defined
   517         // Returns a list of methods - uses array_reverse to ensure user defined
   432         // methods are listed before server defined methods
   518         // methods are listed before server defined methods
   433         return array_reverse(array_keys($this->callbacks));
   519         return array_reverse(array_keys($this->callbacks));
   434     }
   520     }
   435     function multiCall($methodcalls) {
   521 
       
   522     function multiCall($methodcalls)
       
   523     {
   436         // See http://www.xmlrpc.com/discuss/msgReader$1208
   524         // See http://www.xmlrpc.com/discuss/msgReader$1208
   437         $return = array();
   525         $return = array();
   438         foreach ($methodcalls as $call) {
   526         foreach ($methodcalls as $call) {
   439             $method = $call['methodName'];
   527             $method = $call['methodName'];
   440             $params = $call['params'];
   528             $params = $call['params'];
   460  * IXR_Request
   548  * IXR_Request
   461  *
   549  *
   462  * @package IXR
   550  * @package IXR
   463  * @since 1.5
   551  * @since 1.5
   464  */
   552  */
   465 class IXR_Request {
   553 class IXR_Request
       
   554 {
   466     var $method;
   555     var $method;
   467     var $args;
   556     var $args;
   468     var $xml;
   557     var $xml;
   469     function IXR_Request($method, $args) {
   558 
       
   559     function IXR_Request($method, $args)
       
   560     {
   470         $this->method = $method;
   561         $this->method = $method;
   471         $this->args = $args;
   562         $this->args = $args;
   472         $this->xml = <<<EOD
   563         $this->xml = <<<EOD
   473 <?xml version="1.0"?>
   564 <?xml version="1.0"?>
   474 <methodCall>
   565 <methodCall>
   482             $this->xml .= $v->getXml();
   573             $this->xml .= $v->getXml();
   483             $this->xml .= "</value></param>\n";
   574             $this->xml .= "</value></param>\n";
   484         }
   575         }
   485         $this->xml .= '</params></methodCall>';
   576         $this->xml .= '</params></methodCall>';
   486     }
   577     }
   487     function getLength() {
   578 
       
   579     function getLength()
       
   580     {
   488         return strlen($this->xml);
   581         return strlen($this->xml);
   489     }
   582     }
   490     function getXml() {
   583 
       
   584     function getXml()
       
   585     {
   491         return $this->xml;
   586         return $this->xml;
   492     }
   587     }
   493 }
   588 }
   494 
   589 
   495 /**
   590 /**
   496  * IXR_Client
   591  * IXR_Client
   497  *
   592  *
   498  * @package IXR
   593  * @package IXR
   499  * @since 1.5
   594  * @since 1.5
       
   595  *
   500  */
   596  */
   501 class IXR_Client {
   597 class IXR_Client
       
   598 {
   502     var $server;
   599     var $server;
   503     var $port;
   600     var $port;
   504     var $path;
   601     var $path;
   505     var $useragent;
   602     var $useragent;
   506 	var $headers;
       
   507     var $response;
   603     var $response;
   508     var $message = false;
   604     var $message = false;
   509     var $debug = false;
   605     var $debug = false;
   510     var $timeout;
   606     var $timeout;
       
   607     var $headers = array();
       
   608 
   511     // Storage place for an error message
   609     // Storage place for an error message
   512     var $error = false;
   610     var $error = false;
   513     function IXR_Client($server, $path = false, $port = 80, $timeout = false) {
   611 
       
   612     function IXR_Client($server, $path = false, $port = 80, $timeout = 15)
       
   613     {
   514         if (!$path) {
   614         if (!$path) {
   515             // Assume we have been given a URL instead
   615             // Assume we have been given a URL instead
   516             $bits = parse_url($server);
   616             $bits = parse_url($server);
   517             $this->server = $bits['host'];
   617             $this->server = $bits['host'];
   518             $this->port = isset($bits['port']) ? $bits['port'] : 80;
   618             $this->port = isset($bits['port']) ? $bits['port'] : 80;
   519             $this->path = isset($bits['path']) ? $bits['path'] : '/';
   619             $this->path = isset($bits['path']) ? $bits['path'] : '/';
       
   620 
   520             // Make absolutely sure we have a path
   621             // Make absolutely sure we have a path
   521             if (!$this->path) {
   622             if (!$this->path) {
   522                 $this->path = '/';
   623                 $this->path = '/';
   523             }
   624             }
   524         } else {
   625         } else {
   527             $this->port = $port;
   628             $this->port = $port;
   528         }
   629         }
   529         $this->useragent = 'The Incutio XML-RPC PHP Library';
   630         $this->useragent = 'The Incutio XML-RPC PHP Library';
   530         $this->timeout = $timeout;
   631         $this->timeout = $timeout;
   531     }
   632     }
   532     function query() {
   633 
       
   634     function query()
       
   635     {
   533         $args = func_get_args();
   636         $args = func_get_args();
   534         $method = array_shift($args);
   637         $method = array_shift($args);
   535         $request = new IXR_Request($method, $args);
   638         $request = new IXR_Request($method, $args);
   536         $length = $request->getLength();
   639         $length = $request->getLength();
   537         $xml = $request->getXml();
   640         $xml = $request->getXml();
   538         $r = "\r\n";
   641         $r = "\r\n";
   539         $request  = "POST {$this->path} HTTP/1.0$r";
   642         $request  = "POST {$this->path} HTTP/1.0$r";
   540 
   643 
   541 		$this->headers['Host']			= $this->server;
   644         // Merged from WP #8145 - allow custom headers
   542 		$this->headers['Content-Type']	= 'text/xml';
   645         $this->headers['Host']          = $this->server;
   543 		$this->headers['User-Agent']	= $this->useragent;
   646         $this->headers['Content-Type']  = 'text/xml';
   544 		$this->headers['Content-Length']= $length;
   647         $this->headers['User-Agent']    = $this->useragent;
   545 
   648         $this->headers['Content-Length']= $length;
   546 		foreach( $this->headers as $header => $value ) {
   649 
   547 			$request .= "{$header}: {$value}{$r}";
   650         foreach( $this->headers as $header => $value ) {
   548 		}
   651             $request .= "{$header}: {$value}{$r}";
   549 		$request .= $r;
   652         }
       
   653         $request .= $r;
   550 
   654 
   551         $request .= $xml;
   655         $request .= $xml;
       
   656 
   552         // Now send the request
   657         // Now send the request
   553         if ($this->debug) {
   658         if ($this->debug) {
   554             echo '<pre class="ixr_request">'.htmlspecialchars($request)."\n</pre>\n\n";
   659             echo '<pre class="ixr_request">'.htmlspecialchars($request)."\n</pre>\n\n";
   555         }
   660         }
       
   661 
   556         if ($this->timeout) {
   662         if ($this->timeout) {
   557             $fp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout);
   663             $fp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout);
   558         } else {
   664         } else {
   559             $fp = @fsockopen($this->server, $this->port, $errno, $errstr);
   665             $fp = @fsockopen($this->server, $this->port, $errno, $errstr);
   560         }
   666         }
   561         if (!$fp) {
   667         if (!$fp) {
   562             $this->error = new IXR_Error(-32300, "transport error - could not open socket: $errno $errstr");
   668             $this->error = new IXR_Error(-32300, 'transport error - could not open socket');
   563             return false;
   669             return false;
   564         }
   670         }
   565         fputs($fp, $request);
   671         fputs($fp, $request);
   566         $contents = '';
   672         $contents = '';
   567         $debug_contents = '';
   673         $debugContents = '';
   568         $gotFirstLine = false;
   674         $gotFirstLine = false;
   569         $gettingHeaders = true;
   675         $gettingHeaders = true;
   570         while (!feof($fp)) {
   676         while (!feof($fp)) {
   571             $line = fgets($fp, 4096);
   677             $line = fgets($fp, 4096);
   572             if (!$gotFirstLine) {
   678             if (!$gotFirstLine) {
   573                 // Check line for '200'
   679                 // Check line for '200'
   574                 if (strstr($line, '200') === false) {
   680                 if (strstr($line, '200') === false) {
   575                     $this->error = new IXR_Error(-32301, 'transport error - HTTP status code was not 200');
   681                     $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
   576                     return false;
   682                     return false;
   577                 }
   683                 }
   578                 $gotFirstLine = true;
   684                 $gotFirstLine = true;
   579             }
   685             }
   580             if (trim($line) == '') {
   686             if (trim($line) == '') {
   581                 $gettingHeaders = false;
   687                 $gettingHeaders = false;
   582             }
   688             }
   583             if (!$gettingHeaders) {
   689             if (!$gettingHeaders) {
   584                 $contents .= trim($line);
   690             	// merged from WP #12559 - remove trim
       
   691                 $contents .= $line;
   585             }
   692             }
   586             if ($this->debug) {
   693             if ($this->debug) {
   587                 $debug_contents .= $line;
   694             	$debugContents .= $line;
   588             }
   695             }
   589         }
   696         }
   590         if ($this->debug) {
   697         if ($this->debug) {
   591             echo '<pre class="ixr_response">'.htmlspecialchars($debug_contents)."\n</pre>\n\n";
   698             echo '<pre class="ixr_response">'.htmlspecialchars($debugContents)."\n</pre>\n\n";
   592         }
   699         }
       
   700 
   593         // Now parse what we've got back
   701         // Now parse what we've got back
   594         $this->message = new IXR_Message($contents);
   702         $this->message = new IXR_Message($contents);
   595         if (!$this->message->parse()) {
   703         if (!$this->message->parse()) {
   596             // XML error
   704             // XML error
   597             $this->error = new IXR_Error(-32700, 'parse error. not well formed');
   705             $this->error = new IXR_Error(-32700, 'parse error. not well formed');
   598             return false;
   706             return false;
   599         }
   707         }
       
   708 
   600         // Is the message a fault?
   709         // Is the message a fault?
   601         if ($this->message->messageType == 'fault') {
   710         if ($this->message->messageType == 'fault') {
   602             $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
   711             $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
   603             return false;
   712             return false;
   604         }
   713         }
       
   714 
   605         // Message must be OK
   715         // Message must be OK
   606         return true;
   716         return true;
   607     }
   717     }
   608     function getResponse() {
   718 
       
   719     function getResponse()
       
   720     {
   609         // methodResponses can only have one param - return that
   721         // methodResponses can only have one param - return that
   610         return $this->message->params[0];
   722         return $this->message->params[0];
   611     }
   723     }
   612     function isError() {
   724 
       
   725     function isError()
       
   726     {
   613         return (is_object($this->error));
   727         return (is_object($this->error));
   614     }
   728     }
   615     function getErrorCode() {
   729 
       
   730     function getErrorCode()
       
   731     {
   616         return $this->error->code;
   732         return $this->error->code;
   617     }
   733     }
   618     function getErrorMessage() {
   734 
       
   735     function getErrorMessage()
       
   736     {
   619         return $this->error->message;
   737         return $this->error->message;
   620     }
   738     }
   621 }
   739 }
       
   740 
   622 
   741 
   623 /**
   742 /**
   624  * IXR_Error
   743  * IXR_Error
   625  *
   744  *
   626  * @package IXR
   745  * @package IXR
   627  * @since 1.5
   746  * @since 1.5
   628  */
   747  */
   629 class IXR_Error {
   748 class IXR_Error
       
   749 {
   630     var $code;
   750     var $code;
   631     var $message;
   751     var $message;
   632     function IXR_Error($code, $message) {
   752 
       
   753     function IXR_Error($code, $message)
       
   754     {
   633         $this->code = $code;
   755         $this->code = $code;
   634         // WP adds htmlspecialchars(). See #5666
       
   635         $this->message = htmlspecialchars($message);
   756         $this->message = htmlspecialchars($message);
   636     }
   757     }
   637     function getXml() {
   758 
       
   759     function getXml()
       
   760     {
   638         $xml = <<<EOD
   761         $xml = <<<EOD
   639 <methodResponse>
   762 <methodResponse>
   640   <fault>
   763   <fault>
   641     <value>
   764     <value>
   642       <struct>
   765       <struct>
   670     var $day;
   793     var $day;
   671     var $hour;
   794     var $hour;
   672     var $minute;
   795     var $minute;
   673     var $second;
   796     var $second;
   674     var $timezone;
   797     var $timezone;
   675     function IXR_Date($time) {
   798 
       
   799     function IXR_Date($time)
       
   800     {
   676         // $time can be a PHP timestamp or an ISO one
   801         // $time can be a PHP timestamp or an ISO one
   677         if (is_numeric($time)) {
   802         if (is_numeric($time)) {
   678             $this->parseTimestamp($time);
   803             $this->parseTimestamp($time);
   679         } else {
   804         } else {
   680             $this->parseIso($time);
   805             $this->parseIso($time);
   681         }
   806         }
   682     }
   807     }
   683     function parseTimestamp($timestamp) {
   808 
       
   809     function parseTimestamp($timestamp)
       
   810     {
   684         $this->year = date('Y', $timestamp);
   811         $this->year = date('Y', $timestamp);
   685         $this->month = date('m', $timestamp);
   812         $this->month = date('m', $timestamp);
   686         $this->day = date('d', $timestamp);
   813         $this->day = date('d', $timestamp);
   687         $this->hour = date('H', $timestamp);
   814         $this->hour = date('H', $timestamp);
   688         $this->minute = date('i', $timestamp);
   815         $this->minute = date('i', $timestamp);
   689         $this->second = date('s', $timestamp);
   816         $this->second = date('s', $timestamp);
   690         // WP adds timezone. See #2036
       
   691         $this->timezone = '';
   817         $this->timezone = '';
   692     }
   818     }
   693     function parseIso($iso) {
   819 
       
   820     function parseIso($iso)
       
   821     {
   694         $this->year = substr($iso, 0, 4);
   822         $this->year = substr($iso, 0, 4);
   695         $this->month = substr($iso, 4, 2);
   823         $this->month = substr($iso, 4, 2);
   696         $this->day = substr($iso, 6, 2);
   824         $this->day = substr($iso, 6, 2);
   697         $this->hour = substr($iso, 9, 2);
   825         $this->hour = substr($iso, 9, 2);
   698         $this->minute = substr($iso, 12, 2);
   826         $this->minute = substr($iso, 12, 2);
   699         $this->second = substr($iso, 15, 2);
   827         $this->second = substr($iso, 15, 2);
   700         // WP adds timezone. See #2036
       
   701         $this->timezone = substr($iso, 17);
   828         $this->timezone = substr($iso, 17);
   702     }
   829     }
   703     function getIso() {
   830 
   704     	// WP adds timezone. See #2036
   831     function getIso()
       
   832     {
   705         return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
   833         return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
   706     }
   834     }
   707     function getXml() {
   835 
       
   836     function getXml()
       
   837     {
   708         return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
   838         return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
   709     }
   839     }
   710     function getTimestamp() {
   840 
       
   841     function getTimestamp()
       
   842     {
   711         return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
   843         return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
   712     }
   844     }
   713 }
   845 }
   714 
   846 
   715 /**
   847 /**
   716  * IXR_Base64
   848  * IXR_Base64
   717  *
   849  *
   718  * @package IXR
   850  * @package IXR
   719  * @since 1.5
   851  * @since 1.5
   720  */
   852  */
   721 class IXR_Base64 {
   853 class IXR_Base64
       
   854 {
   722     var $data;
   855     var $data;
   723     function IXR_Base64($data) {
   856 
       
   857     function IXR_Base64($data)
       
   858     {
   724         $this->data = $data;
   859         $this->data = $data;
   725     }
   860     }
   726     function getXml() {
   861 
       
   862     function getXml()
       
   863     {
   727         return '<base64>'.base64_encode($this->data).'</base64>';
   864         return '<base64>'.base64_encode($this->data).'</base64>';
   728     }
   865     }
   729 }
   866 }
   730 
   867 
   731 /**
   868 /**
   732  * IXR_IntrospectionServer
   869  * IXR_IntrospectionServer
   733  *
   870  *
   734  * @package IXR
   871  * @package IXR
   735  * @since 1.5
   872  * @since 1.5
   736  */
   873  */
   737 class IXR_IntrospectionServer extends IXR_Server {
   874 class IXR_IntrospectionServer extends IXR_Server
       
   875 {
   738     var $signatures;
   876     var $signatures;
   739     var $help;
   877     var $help;
   740     function IXR_IntrospectionServer() {
   878 
       
   879     function IXR_IntrospectionServer()
       
   880     {
   741         $this->setCallbacks();
   881         $this->setCallbacks();
   742         $this->setCapabilities();
   882         $this->setCapabilities();
   743         $this->capabilities['introspection'] = array(
   883         $this->capabilities['introspection'] = array(
   744             'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
   884             'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
   745             'specVersion' => 1
   885             'specVersion' => 1
   767             'this:methodHelp',
   907             'this:methodHelp',
   768             array('string', 'string'),
   908             array('string', 'string'),
   769             'Returns a documentation string for the specified method'
   909             'Returns a documentation string for the specified method'
   770         );
   910         );
   771     }
   911     }
   772     function addCallback($method, $callback, $args, $help) {
   912 
       
   913     function addCallback($method, $callback, $args, $help)
       
   914     {
   773         $this->callbacks[$method] = $callback;
   915         $this->callbacks[$method] = $callback;
   774         $this->signatures[$method] = $args;
   916         $this->signatures[$method] = $args;
   775         $this->help[$method] = $help;
   917         $this->help[$method] = $help;
   776     }
   918     }
   777     function call($methodname, $args) {
   919 
       
   920     function call($methodname, $args)
       
   921     {
   778         // Make sure it's in an array
   922         // Make sure it's in an array
   779         if ($args && !is_array($args)) {
   923         if ($args && !is_array($args)) {
   780             $args = array($args);
   924             $args = array($args);
   781         }
   925         }
       
   926 
   782         // Over-rides default call method, adds signature check
   927         // Over-rides default call method, adds signature check
   783         if (!$this->hasMethod($methodname)) {
   928         if (!$this->hasMethod($methodname)) {
   784             return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.');
   929             return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.');
   785         }
   930         }
   786         $method = $this->callbacks[$methodname];
   931         $method = $this->callbacks[$methodname];
   787         $signature = $this->signatures[$methodname];
   932         $signature = $this->signatures[$methodname];
   788         $returnType = array_shift($signature);
   933         $returnType = array_shift($signature);
       
   934 
   789         // Check the number of arguments
   935         // Check the number of arguments
   790         if (count($args) != count($signature)) {
   936         if (count($args) != count($signature)) {
   791             return new IXR_Error(-32602, 'server error. wrong number of method parameters');
   937             return new IXR_Error(-32602, 'server error. wrong number of method parameters');
   792         }
   938         }
       
   939 
   793         // Check the argument types
   940         // Check the argument types
   794         $ok = true;
   941         $ok = true;
   795         $argsbackup = $args;
   942         $argsbackup = $args;
   796         for ($i = 0, $j = count($args); $i < $j; $i++) {
   943         for ($i = 0, $j = count($args); $i < $j; $i++) {
   797             $arg = array_shift($args);
   944             $arg = array_shift($args);
   832             }
   979             }
   833         }
   980         }
   834         // It passed the test - run the "real" method call
   981         // It passed the test - run the "real" method call
   835         return parent::call($methodname, $argsbackup);
   982         return parent::call($methodname, $argsbackup);
   836     }
   983     }
   837     function methodSignature($method) {
   984 
       
   985     function methodSignature($method)
       
   986     {
   838         if (!$this->hasMethod($method)) {
   987         if (!$this->hasMethod($method)) {
   839             return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
   988             return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
   840         }
   989         }
   841         // We should be returning an array of types
   990         // We should be returning an array of types
   842         $types = $this->signatures[$method];
   991         $types = $this->signatures[$method];
   870                     break;
  1019                     break;
   871             }
  1020             }
   872         }
  1021         }
   873         return $return;
  1022         return $return;
   874     }
  1023     }
   875     function methodHelp($method) {
  1024 
       
  1025     function methodHelp($method)
       
  1026     {
   876         return $this->help[$method];
  1027         return $this->help[$method];
   877     }
  1028     }
   878 }
  1029 }
   879 
  1030 
   880 /**
  1031 /**
   881  * IXR_ClientMulticall
  1032  * IXR_ClientMulticall
   882  *
  1033  *
   883  * @package IXR
  1034  * @package IXR
   884  * @since 1.5
  1035  * @since 1.5
   885  */
  1036  */
   886 class IXR_ClientMulticall extends IXR_Client {
  1037 class IXR_ClientMulticall extends IXR_Client
       
  1038 {
   887     var $calls = array();
  1039     var $calls = array();
   888     function IXR_ClientMulticall($server, $path = false, $port = 80) {
  1040 
       
  1041     function IXR_ClientMulticall($server, $path = false, $port = 80)
       
  1042     {
   889         parent::IXR_Client($server, $path, $port);
  1043         parent::IXR_Client($server, $path, $port);
   890         $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
  1044         $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
   891     }
  1045     }
   892     function addCall() {
  1046 
       
  1047     function addCall()
       
  1048     {
   893         $args = func_get_args();
  1049         $args = func_get_args();
   894         $methodName = array_shift($args);
  1050         $methodName = array_shift($args);
   895         $struct = array(
  1051         $struct = array(
   896             'methodName' => $methodName,
  1052             'methodName' => $methodName,
   897             'params' => $args
  1053             'params' => $args
   898         );
  1054         );
   899         $this->calls[] = $struct;
  1055         $this->calls[] = $struct;
   900     }
  1056     }
   901     function query() {
  1057 
       
  1058     function query()
       
  1059     {
   902         // Prepare multicall, then call the parent::query() method
  1060         // Prepare multicall, then call the parent::query() method
   903         return parent::query('system.multicall', $this->calls);
  1061         return parent::query('system.multicall', $this->calls);
   904     }
  1062     }
   905 }
  1063 }
   906 
       
   907 ?>