Jlog PHP Cross Reference Blogging Systems

Source: /scripts/ixr-library.inc.php - 817 lines - 27590 bytes - Summary - Text - Print

   1  <?php
   2  
   3  /* 
   4     IXR - The Inutio XML-RPC Library - (c) Incutio Ltd 2002
   5     Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
   6     Site:   http://scripts.incutio.com/xmlrpc/
   7     Manual: http://scripts.incutio.com/xmlrpc/manual.php
   8     Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
   9  */
  10  
  11  
  12  class IXR_Value {
  13      var $data;
  14      var $type;
  15      function IXR_Value ($data, $type = false) {
  16          $this->data = $data;
  17          if (!$type) {
  18              $type = $this->calculateType();
  19          }
  20          $this->type = $type;
  21          if ($type == 'struct') {
  22              /* Turn all the values in the array in to new IXR_Value objects */
  23              foreach ($this->data as $key => $value) {
  24                  $this->data[$key] = new IXR_Value($value);
  25              }
  26          }
  27          if ($type == 'array') {
  28              for ($i = 0, $j = count($this->data); $i < $j; $i++) {
  29                  $this->data[$i] = new IXR_Value($this->data[$i]);
  30              }
  31          }
  32      }
  33      function calculateType() {
  34          if ($this->data === true || $this->data === false) {
  35              return 'boolean';
  36          }
  37          if (is_integer($this->data)) {
  38              return 'int';
  39          }
  40          if (is_double($this->data)) {
  41              return 'double';
  42          }
  43          // Deal with IXR object types base64 and date
  44          if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
  45              return 'date';
  46          }
  47          if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
  48              return 'base64';
  49          }
  50          // If it is a normal PHP object convert it in to a struct
  51          if (is_object($this->data)) {
  52              $this->data = get_object_vars($this->data);
  53              return 'struct';
  54          }
  55          if (!is_array($this->data)) {
  56              return 'string';
  57          }
  58          /* We have an array - is it an array or a struct ? */
  59          if ($this->isStruct($this->data)) {
  60              return 'struct';
  61          } else {
  62              return 'array';
  63          }
  64      }
  65      function getXml() {
  66          /* Return XML for this value */
  67          switch ($this->type) {
  68              case 'boolean':
  69                  return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
  70                  break;
  71              case 'int':
  72                  return '<int>'.$this->data.'</int>';
  73                  break;
  74              case 'double':
  75                  return '<double>'.$this->data.'</double>';
  76                  break;
  77              case 'string':
  78                  return '<string>'.htmlspecialchars($this->data).'</string>';
  79                  break;
  80              case 'array':
  81                  $return = '<array><data>'."\n";
  82                  foreach ($this->data as $item) {
  83                      $return .= '  <value>'.$item->getXml()."</value>\n";
  84                  }
  85                  $return .= '</data></array>';
  86                  return $return;
  87                  break;
  88              case 'struct':
  89                  $return = '<struct>'."\n";
  90                  foreach ($this->data as $name => $value) {
  91                      $return .= "  <member><name>$name</name><value>";
  92                      $return .= $value->getXml()."</value></member>\n";
  93                  }
  94                  $return .= '</struct>';
  95                  return $return;
  96                  break;
  97              case 'date':
  98              case 'base64':
  99                  return $this->data->getXml();
 100                  break;
 101          }
 102          return false;
 103      }
 104      function isStruct($array) {
 105          /* Nasty function to check if an array is a struct or not */
 106          $expected = 0;
 107          foreach ($array as $key => $value) {
 108              if ((string)$key != (string)$expected) {
 109                  return true;
 110              }
 111              $expected++;
 112          }
 113          return false;
 114      }
 115  }
 116  
 117  
 118  class IXR_Message {
 119      var $message;
 120      var $messageType;  // methodCall / methodResponse / fault
 121      var $faultCode;
 122      var $faultString;
 123      var $methodName;
 124      var $params;
 125      // Current variable stacks
 126      var $_arraystructs = array();   // The stack used to keep track of the current array/struct
 127      var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
 128      var $_currentStructName = array();  // A stack as well
 129      var $_param;
 130      var $_value;
 131      var $_currentTag;
 132      var $_currentTagContents;
 133      // The XML parser
 134      var $_parser;
 135      function IXR_Message ($message) {
 136          $this->message = $message;
 137      }
 138      function parse() {
 139          // first remove the XML declaration
 140          $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
 141          if (trim($this->message) == '') {
 142              return false;
 143          }
 144          $this->_parser = xml_parser_create();
 145          // Set XML parser to take the case of tags in to account
 146          xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
 147          // Set XML parser callback functions
 148          xml_set_object($this->_parser, $this);
 149          xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
 150          xml_set_character_data_handler($this->_parser, 'cdata');
 151          if (!xml_parse($this->_parser, $this->message)) {
 152              /* die(sprintf('XML error: %s at line %d',
 153                  xml_error_string(xml_get_error_code($this->_parser)),
 154                  xml_get_current_line_number($this->_parser))); */
 155              return false;
 156          }
 157          xml_parser_free($this->_parser);
 158          // Grab the error messages, if any
 159          if ($this->messageType == 'fault') {
 160              $this->faultCode = $this->params[0]['faultCode'];
 161              $this->faultString = $this->params[0]['faultString'];
 162          }
 163          return true;
 164      }
 165      function tag_open($parser, $tag, $attr) {
 166          $this->currentTag = $tag;
 167          switch($tag) {
 168              case 'methodCall':
 169              case 'methodResponse':
 170              case 'fault':
 171                  $this->messageType = $tag;
 172                  break;
 173              /* Deal with stacks of arrays and structs */
 174              case 'data':    // data is to all intents and puposes more interesting than array
 175                  $this->_arraystructstypes[] = 'array';
 176                  $this->_arraystructs[] = array();
 177                  break;
 178              case 'struct':
 179                  $this->_arraystructstypes[] = 'struct';
 180                  $this->_arraystructs[] = array();
 181                  break;
 182          }
 183      }
 184      function cdata($parser, $cdata) {
 185          $this->_currentTagContents .= $cdata;
 186      }
 187      function tag_close($parser, $tag) {
 188          $valueFlag = false;
 189          switch($tag) {
 190              case 'int':
 191              case 'i4':
 192                  $value = (int)trim($this->_currentTagContents);
 193                  $this->_currentTagContents = '';
 194                  $valueFlag = true;
 195                  break;
 196              case 'double':
 197                  $value = (double)trim($this->_currentTagContents);
 198                  $this->_currentTagContents = '';
 199                  $valueFlag = true;
 200                  break;
 201              case 'string':
 202                  $value = (string)trim($this->_currentTagContents);
 203                  $this->_currentTagContents = '';
 204                  $valueFlag = true;
 205                  break;
 206              case 'dateTime.iso8601':
 207                  $value = new IXR_Date(trim($this->_currentTagContents));
 208                  // $value = $iso->getTimestamp();
 209                  $this->_currentTagContents = '';
 210                  $valueFlag = true;
 211                  break;
 212              case 'value':
 213                  // "If no type is indicated, the type is string."
 214                  if (trim($this->_currentTagContents) != '') {
 215                      $value = (string)$this->_currentTagContents;
 216                      $this->_currentTagContents = '';
 217                      $valueFlag = true;
 218                  }
 219                  break;
 220              case 'boolean':
 221                  $value = (boolean)trim($this->_currentTagContents);
 222                  $this->_currentTagContents = '';
 223                  $valueFlag = true;
 224                  break;
 225              case 'base64':
 226                  $value = base64_decode($this->_currentTagContents);
 227                  $this->_currentTagContents = '';
 228                  $valueFlag = true;
 229                  break;
 230              /* Deal with stacks of arrays and structs */
 231              case 'data':
 232              case 'struct':
 233                  $value = array_pop($this->_arraystructs);
 234                  array_pop($this->_arraystructstypes);
 235                  $valueFlag = true;
 236                  break;
 237              case 'member':
 238                  array_pop($this->_currentStructName);
 239                  break;
 240              case 'name':
 241                  $this->_currentStructName[] = trim($this->_currentTagContents);
 242                  $this->_currentTagContents = '';
 243                  break;
 244              case 'methodName':
 245                  $this->methodName = trim($this->_currentTagContents);
 246                  $this->_currentTagContents = '';
 247                  break;
 248          }
 249          if ($valueFlag) {
 250              /*
 251              if (!is_array($value) && !is_object($value)) {
 252                  $value = trim($value);
 253              }
 254              */
 255              if (count($this->_arraystructs) > 0) {
 256                  // Add value to struct or array
 257                  if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
 258                      // Add to struct
 259                      $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
 260                  } else {
 261                      // Add to array
 262                      $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
 263                  }
 264              } else {
 265                  // Just add as a paramater
 266                  $this->params[] = $value;
 267              }
 268          }
 269      }       
 270  }
 271  
 272  
 273  class IXR_Server {
 274      var $data;
 275      var $callbacks = array();
 276      var $message;
 277      var $capabilities;
 278      function IXR_Server($callbacks = false, $data = false) {
 279          $this->setCapabilities();
 280          if ($callbacks) {
 281              $this->callbacks = $callbacks;
 282          }
 283          $this->setCallbacks();
 284          $this->serve($data);
 285      }
 286      function serve($data = false) {
 287          if (!$data) {
 288              global $HTTP_RAW_POST_DATA;
 289              if (!$HTTP_RAW_POST_DATA) {
 290                 die('XML-RPC server accepts POST requests only.');
 291              }
 292              $data = $HTTP_RAW_POST_DATA;
 293          }
 294          $this->message = new IXR_Message($data);
 295          if (!$this->message->parse()) {
 296              $this->error(-32700, 'parse error. not well formed');
 297          }
 298          if ($this->message->messageType != 'methodCall') {
 299              $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
 300          }
 301          $result = $this->call($this->message->methodName, $this->message->params);
 302          // Is the result an error?
 303          if (is_a($result, 'IXR_Error')) {
 304              $this->error($result);
 305          }
 306          // Encode the result
 307          $r = new IXR_Value($result);
 308          $resultxml = $r->getXml();
 309          // Create the XML
 310          $xml = <<<EOD
 311  <methodResponse>
 312    <params>
 313      <param>
 314        <value>
 315          $resultxml
 316        </value>
 317      </param>
 318    </params>
 319  </methodResponse>
 320  
 321  EOD;
 322          // Send it
 323          $this->output($xml);
 324      }
 325      function call($methodname, $args) {
 326          if (!$this->hasMethod($methodname)) {
 327              return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
 328          }
 329          $method = $this->callbacks[$methodname];
 330          // Perform the callback and send the response
 331          if (count($args) == 1) {
 332              // If only one paramater just send that instead of the whole array
 333              $args = $args[0];
 334          }
 335          // Are we dealing with a function or a method?
 336          if (substr($method, 0, 5) == 'this:') {
 337              // It's a class method - check it exists
 338              $method = substr($method, 5);
 339              if (!method_exists($this, $method)) {
 340                  return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
 341              }
 342              // Call the method
 343              $result = $this->$method($args);
 344          } else {
 345              // It's a function - does it exist?
 346              if (!function_exists($method)) {
 347                  return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
 348              }
 349              // Call the function
 350              $result = $method($args);
 351          }
 352          return $result;
 353      }
 354  
 355      function error($error, $message = false) {
 356          // Accepts either an error object or an error code and message
 357          if ($message && !is_object($error)) {
 358              $error = new IXR_Error($error, $message);
 359          }
 360          $this->output($error->getXml());
 361      }
 362      function output($xml) {
 363          $xml = '<?xml version="1.0"?>'."\n".$xml;
 364          $length = strlen($xml);
 365          header('Connection: close');
 366          header('Content-Length: '.$length);
 367          header('Content-Type: text/xml');
 368          header('Date: '.date('r'));
 369          echo $xml;
 370          exit;
 371      }
 372      function hasMethod($method) {
 373          return in_array($method, array_keys($this->callbacks));
 374      }
 375      function setCapabilities() {
 376          // Initialises capabilities array
 377          $this->capabilities = array(
 378              'xmlrpc' => array(
 379                  'specUrl' => 'http://www.xmlrpc.com/spec',
 380                  'specVersion' => 1
 381              ),
 382              'faults_interop' => array(
 383                  'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
 384                  'specVersion' => 20010516
 385              ),
 386              'system.multicall' => array(
 387                  'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
 388                  'specVersion' => 1
 389              ),
 390          );   
 391      }
 392      function getCapabilities($args) {
 393          return $this->capabilities;
 394      }
 395      function setCallbacks() {
 396          $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
 397          $this->callbacks['system.listMethods'] = 'this:listMethods';
 398          $this->callbacks['system.multicall'] = 'this:multiCall';
 399      }
 400      function listMethods($args) {
 401          // Returns a list of methods - uses array_reverse to ensure user defined
 402          // methods are listed before server defined methods
 403          return array_reverse(array_keys($this->callbacks));
 404      }
 405      function multiCall($methodcalls) {
 406          // See http://www.xmlrpc.com/discuss/msgReader$1208
 407          $return = array();
 408          foreach ($methodcalls as $call) {
 409              $method = $call['methodName'];
 410              $params = $call['params'];
 411              if ($method == 'system.multicall') {
 412                  $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
 413              } else {
 414                  $result = $this->call($method, $params);
 415              }
 416              if (is_a($result, 'IXR_Error')) {
 417                  $return[] = array(
 418                      'faultCode' => $result->code,
 419                      'faultString' => $result->message
 420                  );
 421              } else {
 422                  $return[] = array($result);
 423              }
 424          }
 425          return $return;
 426      }
 427  }
 428  
 429  class IXR_Request {
 430      var $method;
 431      var $args;
 432      var $xml;
 433      function IXR_Request($method, $args) {
 434          $this->method = $method;
 435          $this->args = $args;
 436          $this->xml = <<<EOD
 437  <?xml version="1.0"?>
 438  <methodCall>
 439  <methodName>{$this->method}</methodName>
 440  <params>
 441  
 442  EOD;
 443          foreach ($this->args as $arg) {
 444              $this->xml .= '<param><value>';
 445              $v = new IXR_Value($arg);
 446              $this->xml .= $v->getXml();
 447              $this->xml .= "</value></param>\n";
 448          }
 449          $this->xml .= '</params></methodCall>';
 450      }
 451      function getLength() {
 452          return strlen($this->xml);
 453      }
 454      function getXml() {
 455          return $this->xml;
 456      }
 457  }
 458  
 459  
 460  class IXR_Client {
 461      var $server;
 462      var $port;
 463      var $path;
 464      var $useragent;
 465      var $response;
 466      var $message = false;
 467      var $debug = false;
 468      // Storage place for an error message
 469      var $error = false;
 470      function IXR_Client($server, $path = false, $port = 80) {
 471          if (!$path) {
 472              // Assume we have been given a URL instead
 473              $bits = parse_url($server);
 474              $this->server = $bits['host'];
 475              $this->port = isset($bits['port']) ? $bits['port'] : 80;
 476              $this->path = isset($bits['path']) ? $bits['path'] : '/';
 477              // Make absolutely sure we have a path
 478              if (!$this->path) {
 479                  $this->path = '/';
 480              }
 481          } else {
 482              $this->server = $server;
 483              $this->path = $path;
 484              $this->port = $port;
 485          }
 486          $this->useragent = 'The Incutio XML-RPC PHP Library';
 487      }
 488      function query() {
 489          $args = func_get_args();
 490          $method = array_shift($args);
 491          $request = new IXR_Request($method, $args);
 492          $length = $request->getLength();
 493          $xml = $request->getXml();
 494          $r = "\r\n";
 495          $request  = "POST {$this->path} HTTP/1.0$r";
 496          $request .= "Host: {$this->server}$r";
 497          $request .= "Content-Type: text/xml$r";
 498          $request .= "User-Agent: {$this->useragent}$r";
 499          $request .= "Content-length: {$length}$r$r";
 500          $request .= $xml;
 501          // Now send the request
 502          if ($this->debug) {
 503              echo '<pre>'.htmlspecialchars($request)."\n</pre>\n\n";
 504          }
 505          $fp = @fsockopen($this->server, $this->port);
 506          if (!$fp) {
 507              $this->error = new IXR_Error(-32300, 'transport error - could not open socket');
 508              return false;
 509          }
 510          fputs($fp, $request);
 511          $contents = '';
 512          $gotFirstLine = false;
 513          $gettingHeaders = true;
 514          while (!feof($fp)) {
 515              $line = fgets($fp, 4096);
 516              if (!$gotFirstLine) {
 517                  // Check line for '200'
 518                  if (strstr($line, '200') === false) {
 519                      $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
 520                      return false;
 521                  }
 522                  $gotFirstLine = true;
 523              }
 524              if (trim($line) == '') {
 525                  $gettingHeaders = false;
 526              }
 527              if (!$gettingHeaders) {
 528                  $contents .= trim($line)."\n";
 529              }
 530          }
 531          if ($this->debug) {
 532              echo '<pre>'.htmlspecialchars($contents)."\n</pre>\n\n";
 533          }
 534          // Now parse what we've got back
 535          $this->message = new IXR_Message($contents);
 536          if (!$this->message->parse()) {
 537              // XML error
 538              $this->error = new IXR_Error(-32700, 'parse error. not well formed');
 539              return false;
 540          }
 541          // Is the message a fault?
 542          if ($this->message->messageType == 'fault') {
 543              $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
 544              return false;
 545          }
 546          // Message must be OK
 547          return true;
 548      }
 549      function getResponse() {
 550          // methodResponses can only have one param - return that
 551          return $this->message->params[0];
 552      }
 553      function isError() {
 554          return (is_object($this->error));
 555      }
 556      function getErrorCode() {
 557          return $this->error->code;
 558      }
 559      function getErrorMessage() {
 560          return $this->error->message;
 561      }
 562  }
 563  
 564  
 565  class IXR_Error {
 566      var $code;
 567      var $message;
 568      function IXR_Error($code, $message) {
 569          $this->code = $code;
 570          $this->message = $message;
 571      }
 572      function getXml() {
 573          $xml = <<<EOD
 574  <methodResponse>
 575    <fault>
 576      <value>
 577        <struct>
 578          <member>
 579            <name>faultCode</name>
 580            <value><int>{$this->code}</int></value>
 581          </member>
 582          <member>
 583            <name>faultString</name>
 584            <value><string>{$this->message}</string></value>
 585          </member>
 586        </struct>
 587      </value>
 588    </fault>
 589  </methodResponse> 
 590  
 591  EOD;
 592          return $xml;
 593      }
 594  }
 595  
 596  
 597  class IXR_Date {
 598      var $year;
 599      var $month;
 600      var $day;
 601      var $hour;
 602      var $minute;
 603      var $second;
 604      function IXR_Date($time) {
 605          // $time can be a PHP timestamp or an ISO one
 606          if (is_numeric($time)) {
 607              $this->parseTimestamp($time);
 608          } else {
 609              $this->parseIso($time);
 610          }
 611      }
 612      function parseTimestamp($timestamp) {
 613          $this->year = date('Y', $timestamp);
 614          $this->month = date('Y', $timestamp);
 615          $this->day = date('Y', $timestamp);
 616          $this->hour = date('H', $timestamp);
 617          $this->minute = date('i', $timestamp);
 618          $this->second = date('s', $timestamp);
 619      }
 620      function parseIso($iso) {
 621          $this->year = substr($iso, 0, 4);
 622          $this->month = substr($iso, 4, 2); 
 623          $this->day = substr($iso, 6, 2);
 624          $this->hour = substr($iso, 9, 2);
 625          $this->minute = substr($iso, 12, 2);
 626          $this->second = substr($iso, 15, 2);
 627      }
 628      function getIso() {
 629          return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second;
 630      }
 631      function getXml() {
 632          return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
 633      }
 634      function getTimestamp() {
 635          return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
 636      }
 637  }
 638  
 639  
 640  class IXR_Base64 {
 641      var $data;
 642      function IXR_Base64($data) {
 643          $this->data = $data;
 644      }
 645      function getXml() {
 646          return '<base64>'.base64_encode($this->data).'</base64>';
 647      }
 648  }
 649  
 650  
 651  class IXR_IntrospectionServer extends IXR_Server {
 652      var $signatures;
 653      var $help;
 654      function IXR_IntrospectionServer() {
 655          $this->setCallbacks();
 656          $this->setCapabilities();
 657          $this->capabilities['introspection'] = array(
 658              'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
 659              'specVersion' => 1
 660          );
 661          $this->addCallback(
 662              'system.methodSignature', 
 663              'this:methodSignature', 
 664              array('array', 'string'), 
 665              'Returns an array describing the return type and required parameters of a method'
 666          );
 667          $this->addCallback(
 668              'system.getCapabilities', 
 669              'this:getCapabilities', 
 670              array('struct'), 
 671              'Returns a struct describing the XML-RPC specifications supported by this server'
 672          );
 673          $this->addCallback(
 674              'system.listMethods', 
 675              'this:listMethods', 
 676              array('array'), 
 677              'Returns an array of available methods on this server'
 678          );
 679          $this->addCallback(
 680              'system.methodHelp', 
 681              'this:methodHelp', 
 682              array('string', 'string'), 
 683              'Returns a documentation string for the specified method'
 684          );
 685      }
 686      function addCallback($method, $callback, $args, $help) {
 687          $this->callbacks[$method] = $callback;
 688          $this->signatures[$method] = $args;
 689          $this->help[$method] = $help;
 690      }
 691      function call($methodname, $args) {
 692          // Make sure it's in an array
 693          if ($args && !is_array($args)) {
 694              $args = array($args);
 695          }
 696          // Over-rides default call method, adds signature check
 697          if (!$this->hasMethod($methodname)) {
 698              return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.');
 699          }
 700          $method = $this->callbacks[$methodname];
 701          $signature = $this->signatures[$methodname];
 702          $returnType = array_shift($signature);
 703          // Check the number of arguments
 704          if (count($args) != count($signature)) {
 705              // print 'Num of args: '.count($args).' Num in signature: '.count($signature);
 706              return new IXR_Error(-32602, 'server error. wrong number of method parameters');
 707          }
 708          // Check the argument types
 709          $ok = true;
 710          $argsbackup = $args;
 711          for ($i = 0, $j = count($args); $i < $j; $i++) {
 712              $arg = array_shift($args);
 713              $type = array_shift($signature);
 714              switch ($type) {
 715                  case 'int':
 716                  case 'i4':
 717                      if (is_array($arg) || !is_int($arg)) {
 718                          $ok = false;
 719                      }
 720                      break;
 721                  case 'base64':
 722                  case 'string':
 723                      if (!is_string($arg)) {
 724                          $ok = false;
 725                      }
 726                      break;
 727                  case 'boolean':
 728                      if ($arg !== false && $arg !== true) {
 729                          $ok = false;
 730                      }
 731                      break;
 732                  case 'float':
 733                  case 'double':
 734                      if (!is_float($arg)) {
 735                          $ok = false;
 736                      }
 737                      break;
 738                  case 'date':
 739                  case 'dateTime.iso8601':
 740                      if (!is_a($arg, 'IXR_Date')) {
 741                          $ok = false;
 742                      }
 743                      break;
 744              }
 745              if (!$ok) {
 746                  return new IXR_Error(-32602, 'server error. invalid method parameters');
 747              }
 748          }
 749          // It passed the test - run the "real" method call
 750          return parent::call($methodname, $argsbackup);
 751      }
 752      function methodSignature($method) {
 753          if (!$this->hasMethod($method)) {
 754              return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
 755          }
 756          // We should be returning an array of types
 757          $types = $this->signatures[$method];
 758          $return = array();
 759          foreach ($types as $type) {
 760              switch ($type) {
 761                  case 'string':
 762                      $return[] = 'string';
 763                      break;
 764                  case 'int':
 765                  case 'i4':
 766                      $return[] = 42;
 767                      break;
 768                  case 'double':
 769                      $return[] = 3.1415;
 770                      break;
 771                  case 'dateTime.iso8601':
 772                      $return[] = new IXR_Date(time());
 773                      break;
 774                  case 'boolean':
 775                      $return[] = true;
 776                      break;
 777                  case 'base64':
 778                      $return[] = new IXR_Base64('base64');
 779                      break;
 780                  case 'array':
 781                      $return[] = array('array');
 782                      break;
 783                  case 'struct':
 784                      $return[] = array('struct' => 'struct');
 785                      break;
 786              }
 787          }
 788          return $return;
 789      }
 790      function methodHelp($method) {
 791          return $this->help[$method];
 792      }
 793  }
 794  
 795  
 796  class IXR_ClientMulticall extends IXR_Client {
 797      var $calls = array();
 798      function IXR_ClientMulticall($server, $path = false, $port = 80) {
 799          parent::IXR_Client($server, $path, $port);
 800          $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
 801      }
 802      function addCall() {
 803          $args = func_get_args();
 804          $methodName = array_shift($args);
 805          $struct = array(
 806              'methodName' => $methodName,
 807              'params' => $args
 808          );
 809          $this->calls[] = $struct;
 810      }
 811      function query() {
 812          // Prepare multicall, then call the parent::query() method
 813          return parent::query('system.multicall', $this->calls);
 814      }
 815  }
 816  
 817  ?>

title

Description

title

Description

title

Description

title

title

Body