[ Index ] [ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]

PHP Cross Reference of TXP stable 4.0.6

title

Body

[close]

/textpattern/lib/ -> IXRClass.php (source)

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


Generated: Mon Feb 18 03:42:45 2008 Cross-referenced by PHPXref 0.7