[ Index ]

WordPress Cross Reference

title

Body

[close]

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

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


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu