[ Index ]

PHP Cross Reference of Wordpress 2.9.1

title

Body

[close]

/wp-includes/ -> class-IXR.php (source)

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


Generated: Fri Jan 8 00:19:48 2010 Cross-referenced by PHPXref 0.7