[ Index ]

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


Generated: Mon Mar 23 16:23:02 2009 Cross-referenced by PHPXref 0.7