[ Index ]

PHP Cross Reference of bbPress

title

Body

[close]

/bb-includes/backpress/ -> class.ixr.php (source)

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


Generated: Thu May 23 03:58:37 2013 Hosted by follow the white rabbit.