[ Index ]
 

Code source de Dotclear 2.0-beta6

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/inc/clearbricks/net.xmlrpc/ -> class.net.xmlrpc.php (source)

   1  <?php
   2  # ***** BEGIN LICENSE BLOCK *****
   3  # This file is part of Clearbricks.
   4  # Copyright (c) 2007 Olivier Meunier and contributors.
   5  # All rights reserved.
   6  #
   7  # Clearbricks is free software; you can redistribute it and/or modify
   8  # it under the terms of the GNU General Public License as published by
   9  # the Free Software Foundation; either version 2 of the License, or
  10  # (at your option) any later version.
  11  # 
  12  # Clearbricks is distributed in the hope that it will be useful,
  13  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  # GNU General Public License for more details.
  16  # 
  17  # You should have received a copy of the GNU General Public License
  18  # along with Clearbricks; if not, write to the Free Software
  19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20  #
  21  # ***** END LICENSE BLOCK *****
  22  
  23  class xmlrpcException extends Exception
  24  {
  25  	public function __construct($message,$code=0)
  26      {
  27          parent::__construct($message,$code);
  28      }
  29  }
  30  
  31  class xmlrpcValue
  32  {
  33      protected  $data;
  34      protected  $type;
  35      
  36  	public function __construct($data, $type = false)
  37      {
  38          $this->data = $data;
  39          if (!$type) {
  40              $type = $this->calculateType();
  41          }
  42          $this->type = $type;
  43          if ($type == 'struct') {
  44              # Turn all the values in the array in to new xmlrpcValue objects
  45              foreach ($this->data as $key => $value) {
  46                  $this->data[$key] = new xmlrpcValue($value);
  47              }
  48          }
  49          if ($type == 'array') {
  50              for ($i = 0, $j = count($this->data); $i < $j; $i++) {
  51                  $this->data[$i] = new xmlrpcValue($this->data[$i]);
  52              }
  53          }
  54      }
  55      
  56  	public function getXml()
  57      {
  58          # Return XML for this value
  59          switch ($this->type)
  60          {
  61              case 'boolean':
  62                  return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
  63                  break;
  64              case 'int':
  65                  return '<int>'.$this->data.'</int>';
  66                  break;
  67              case 'double':
  68                  return '<double>'.$this->data.'</double>';
  69                  break;
  70              case 'string':
  71                  return '<string>'.htmlspecialchars($this->data).'</string>';
  72                  break;
  73              case 'array':
  74                  $return = '<array><data>'."\n";
  75                  foreach ($this->data as $item) {
  76                      $return .= '  <value>'.$item->getXml()."</value>\n";
  77                  }
  78                  $return .= '</data></array>';
  79                  return $return;
  80                  break;
  81              case 'struct':
  82                  $return = '<struct>'."\n";
  83                  foreach ($this->data as $name => $value) {
  84                      $return .= "  <member><name>$name</name><value>";
  85                      $return .= $value->getXml()."</value></member>\n";
  86                  }
  87                  $return .= '</struct>';
  88                  return $return;
  89                  break;
  90              case 'date':
  91              case 'base64':
  92                  return $this->data->getXml();
  93                  break;
  94          }
  95          return false;
  96      }
  97      
  98  	protected function calculateType()
  99      {
 100          if ($this->data === true || $this->data === false) {
 101              return 'boolean';
 102          }
 103          if (is_integer($this->data)) {
 104              return 'int';
 105          }
 106          if (is_double($this->data)) {
 107              return 'double';
 108          }
 109          # Deal with xmlrpc object types base64 and date
 110          if (is_object($this->data) && $this->data instanceof xmlrpcDate) {
 111              return 'date';
 112          }
 113          if (is_object($this->data) && $this->data instanceof xmlrpcBase64) {
 114              return 'base64';
 115          }
 116          # If it is a normal PHP object convert it in to a struct
 117          if (is_object($this->data)) {
 118              $this->data = get_object_vars($this->data);
 119              return 'struct';
 120          }
 121          if (!is_array($this->data)) {
 122              return 'string';
 123          }
 124          # We have an array - is it an array or a struct ?
 125          if ($this->isStruct($this->data)) {
 126              return 'struct';
 127          } else {
 128              return 'array';
 129          }
 130      }
 131      
 132  	protected function isStruct($array)
 133      {
 134          # Nasty function to check if an array is a struct or not
 135          $expected = 0;
 136          foreach ($array as $key => $value) {
 137              if ((string)$key != (string)$expected) {
 138                  return true;
 139              }
 140              $expected++;
 141          }
 142          return false;
 143      }
 144  }
 145  
 146  class xmlrpcMessage
 147  {
 148      protected $brutxml;
 149      protected $message;
 150      
 151      public $messageType;  # methodCall / methodResponse / fault
 152      public $faultCode;
 153      public $faultString;
 154      public $methodName;
 155      public $params;
 156      
 157      # Current variable stacks
 158      protected $_arraystructs = array();   # The stack used to keep track of the current array/struct
 159      protected $_arraystructstypes = array(); # Stack keeping track of if things are structs or array
 160      protected $_currentStructName = array();  # A stack as well
 161      protected $_param;
 162      protected $_value;
 163      protected $_currentTag;
 164      protected $_currentTagContents;
 165      
 166      # The XML parser
 167      protected $_parser;
 168      
 169  	public function __construct($message)
 170      {
 171          $this->brutxml = $this->message = $message;
 172      }
 173      
 174  	public function parse()
 175      {
 176          // first remove the XML declaration
 177          $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
 178          
 179          if (trim($this->message) == '') {
 180              throw new Exception('XML Parser Error. Empty message');
 181          }
 182          
 183          $this->_parser = xml_parser_create();
 184          
 185          # Set XML parser to take the case of tags in to account
 186          xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
 187          
 188          # Set XML parser callback functions
 189          xml_set_object($this->_parser, $this);
 190          xml_set_element_handler($this->_parser, 'tag_open','tag_close');
 191          xml_set_character_data_handler($this->_parser, 'cdata');
 192          
 193          if (!xml_parse($this->_parser, $this->message))
 194          {
 195              $c = xml_get_error_code($this->_parser);
 196              $e = xml_error_string($c);
 197              $e .= ' on line '.xml_get_current_line_number($this->_parser);
 198              throw new Exception('XML Parser Error. '.$e,$c);
 199          }
 200          
 201          xml_parser_free($this->_parser);
 202          
 203          # Grab the error messages, if any
 204          if ($this->messageType == 'fault')
 205          {
 206              $this->faultCode = $this->params[0]['faultCode'];
 207              $this->faultString = $this->params[0]['faultString'];
 208          }
 209          return true;
 210      }
 211      
 212  	protected function tag_open($parser,$tag,$attr)
 213      {
 214          $this->currentTag = $tag;
 215          
 216          switch($tag)
 217          {
 218              case 'methodCall':
 219              case 'methodResponse':
 220              case 'fault':
 221                  $this->messageType = $tag;
 222                  break;
 223              # Deal with stacks of arrays and structs
 224              case 'data':    # data is to all intents and puposes more interesting than array
 225                  $this->_arraystructstypes[] = 'array';
 226                  $this->_arraystructs[] = array();
 227                  break;
 228              case 'struct':
 229                  $this->_arraystructstypes[] = 'struct';
 230                  $this->_arraystructs[] = array();
 231                  break;
 232          }
 233      }
 234      
 235  	protected function cdata($parser,$cdata)
 236      {
 237          $this->_currentTagContents .= $cdata;
 238      }
 239      
 240  	protected function tag_close($parser,$tag)
 241      {
 242          $valueFlag = false;
 243          
 244          switch($tag)
 245          {
 246              case 'int':
 247              case 'i4':
 248                  $value = (int)trim($this->_currentTagContents);
 249                  $this->_currentTagContents = '';
 250                  $valueFlag = true;
 251                  break;
 252              case 'double':
 253                  $value = (double)trim($this->_currentTagContents);
 254                  $this->_currentTagContents = '';
 255                  $valueFlag = true;
 256                  break;
 257              case 'string':
 258                  $value = (string)trim($this->_currentTagContents);
 259                  $this->_currentTagContents = '';
 260                  $valueFlag = true;
 261                  break;
 262              case 'dateTime.iso8601':
 263                  $value = new xmlrpcDate(trim($this->_currentTagContents));
 264                  # $value = $iso->getTimestamp();
 265                  $this->_currentTagContents = '';
 266                  $valueFlag = true;
 267                  break;
 268              case 'value':
 269                  # "If no type is indicated, the type is string."
 270                  if (trim($this->_currentTagContents) != '')
 271                  {
 272                      $value = (string)$this->_currentTagContents;
 273                      $this->_currentTagContents = '';
 274                      $valueFlag = true;
 275                  }
 276                  break;
 277              case 'boolean':
 278                  $value = (boolean)trim($this->_currentTagContents);
 279                  $this->_currentTagContents = '';
 280                  $valueFlag = true;
 281                  break;
 282              case 'base64':
 283                  $value = base64_decode($this->_currentTagContents);
 284                  $this->_currentTagContents = '';
 285                  $valueFlag = true;
 286                  break;
 287              # Deal with stacks of arrays and structs
 288              case 'data':
 289              case 'struct':
 290                  $value = array_pop($this->_arraystructs);
 291                  array_pop($this->_arraystructstypes);
 292                  $valueFlag = true;
 293                  break;
 294              case 'member':
 295                  array_pop($this->_currentStructName);
 296                  break;
 297              case 'name':
 298                  $this->_currentStructName[] = trim($this->_currentTagContents);
 299                  $this->_currentTagContents = '';
 300                  break;
 301              case 'methodName':
 302                  $this->methodName = trim($this->_currentTagContents);
 303                  $this->_currentTagContents = '';
 304                  break;
 305          }
 306          
 307          if ($valueFlag)
 308          {
 309              if (count($this->_arraystructs) > 0)
 310              {
 311                  # Add value to struct or array
 312                  if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
 313                      # Add to struct
 314                      $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
 315                  } else {
 316                      # Add to array
 317                      $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
 318                  }
 319              }
 320              else
 321              {
 322                  # Just add as a paramater
 323                  $this->params[] = $value;
 324              }
 325          }
 326      }       
 327  }
 328  
 329  class xmlrpcRequest
 330  {
 331      public $method;
 332      public $args;
 333      public $xml;
 334      
 335  	function __construct($method, $args)
 336      {
 337          $this->method = $method;
 338          $this->args = $args;
 339          
 340          $this->xml =
 341          '<?xml version="1.0"?>'."\n".
 342          "<methodCall>\n".
 343          '  <methodName>'.$this->method."</methodName>\n".
 344          "  <params>\n";
 345          
 346          foreach ($this->args as $arg)
 347          {
 348              $this->xml .= '    <param><value>';
 349              $v = new xmlrpcValue($arg);
 350              $this->xml .= $v->getXml();
 351              $this->xml .= "</value></param>\n";
 352          }
 353          
 354          $this->xml .= '  </params></methodCall>';
 355      }
 356      
 357  	public function getLength()
 358      {
 359          return strlen($this->xml);
 360      }
 361      
 362  	public function getXml()
 363      {
 364          return $this->xml;
 365      }
 366  }
 367  
 368  class xmlrpcDate
 369  {
 370      protected $year;
 371      protected $month;
 372      protected $day;
 373      protected $hour;
 374      protected $minute;
 375      protected $second;
 376      
 377  	public function __construct($time)
 378      {
 379          # $time can be a PHP timestamp or an ISO one
 380          if (is_numeric($time)) {
 381              $this->parseTimestamp($time);
 382          } else {
 383              $this->parseTimestamp(strtotime($time));
 384          }
 385      }
 386      
 387  	protected function parseTimestamp($timestamp)
 388      {
 389          $this->year = date('Y', $timestamp);
 390          $this->month = date('m', $timestamp);
 391          $this->day = date('d', $timestamp);
 392          $this->hour = date('H', $timestamp);
 393          $this->minute = date('i', $timestamp);
 394          $this->second = date('s', $timestamp);
 395          $this->ts = $timestamp;
 396      }
 397      
 398  	public function getIso()
 399      {
 400          return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second;
 401      }
 402      
 403  	public function getXml()
 404      {
 405          return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
 406      }
 407      
 408  	public function getTimestamp()
 409      {
 410          return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
 411      }
 412  }
 413  
 414  class xmlrpcBase64
 415  {
 416      protected $data;
 417      
 418  	public function __construct($data)
 419      {
 420          $this->data = $data;
 421      }
 422      
 423  	public function getXml()
 424      {
 425          return '<base64>'.base64_encode($this->data).'</base64>';
 426      }
 427  }
 428  
 429  class xmlrpcClient extends netHttp
 430  {
 431      protected $request;
 432      protected $message;
 433      
 434  	public function __construct($url)
 435      {
 436          if (!$this->readUrl($url,$ssl,$host,$port,$path,$user,$pass)) {
 437              return false;
 438          }
 439          
 440          parent::__construct($host,$port);
 441          $this->useSSL($ssl);
 442          $this->setAuthorization($user,$pass);
 443          
 444          $this->path = $path;
 445          $this->user_agent = 'Clearbricks XML/RPC Client';
 446      }
 447      
 448  	public function query()
 449      {
 450          $args = func_get_args();
 451          $method = array_shift($args);
 452          $this->request = new xmlrpcRequest($method, $args);
 453          
 454          $this->doRequest();
 455          
 456          if ($this->status != 200) {
 457              throw new Exception('HTTP Error. '.$this->status.' '.$this->status_string);
 458          }
 459          
 460          # Now parse what we've got back
 461          $this->message = new xmlrpcMessage($this->content);
 462          $this->message->parse();
 463          
 464          # Is the message a fault?
 465          if ($this->message->messageType == 'fault')
 466          {
 467              throw new xmlrpcException($this->message->faultString,$this->message->faultCode);
 468          }
 469          
 470          return $this->message->params[0];
 471      }
 472      
 473      # Overloading netHttp::buildRequest method, we don't need all the stuff of
 474      # HTTP client.
 475  	protected function buildRequest()
 476      {
 477          if ($this->proxy_host) {
 478              $path = $this->getRequestURL();
 479          } else {
 480              $path = $this->path;
 481          }
 482          
 483          return array(
 484              'POST '.$path.' HTTP/1.0',
 485              'Host: '.$this->host,
 486              'Content-Type: text/xml',
 487              'User-Agent: '.$this->user_agent,
 488              'Content-Length: '.$this->request->getLength(),
 489              '',
 490              $this->request->getXML()
 491          );
 492      }
 493  }
 494  
 495  class xmlrpcClientMulticall extends xmlrpcClient
 496  {
 497      protected $calls = array();
 498      
 499  	function __construct($url)
 500      {
 501          parent::__construct($url);
 502      }
 503      
 504  	function addCall()
 505      {
 506          $args = func_get_args();
 507          $methodName = array_shift($args);
 508          
 509          $struct = array(
 510              'methodName' => $methodName,
 511              'params' => $args
 512          );
 513          
 514          $this->calls[] = $struct;
 515      }
 516      
 517  	function query()
 518      {
 519          # Prepare multicall, then call the parent::query() method
 520          return parent::query('system.multicall',$this->calls);
 521      }
 522  }
 523  
 524  class xmlrpcServer
 525  {
 526      protected $callbacks = array();
 527      protected $data;
 528      protected $encoding;
 529      protected $message;
 530      protected $capabilities;
 531      
 532      public $strict_check = false;
 533      
 534  	public function __construct($callbacks=false,$data=false,$encoding='UTF-8')
 535      {
 536          $this->encoding = $encoding;
 537          $this->setCapabilities();
 538          if ($callbacks) {
 539              $this->callbacks = $callbacks;
 540          }
 541          $this->setCallbacks();
 542          $this->serve($data);
 543      }
 544      
 545  	public function serve($data=false)
 546      {
 547          if (!$data)
 548          {
 549              try
 550              {
 551                  # Check HTTP Method
 552                  if ($_SERVER['REQUEST_METHOD'] != 'POST') {
 553                      throw new Exception('XML-RPC server accepts POST requests only.',405);
 554                  }
 555                  
 556                  # Check HTTP_HOST
 557                  if (!isset($_SERVER['HTTP_HOST'])) {
 558                      throw new Exception('No Host Specified',400);
 559                  }
 560                  
 561                  global $HTTP_RAW_POST_DATA;
 562                  if (!$HTTP_RAW_POST_DATA) {
 563                      throw new Exception('No Message',400);
 564                  }
 565                  
 566                  if ($strict_check)
 567                  {
 568                      # Check USER_AGENT
 569                      if (!isset($_SERVER['HTTP_USER_AGENT'])) {
 570                          throw new Exception('No User Agent Specified',400);
 571                      }
 572                      
 573                      # Check CONTENT_TYPE
 574                      if (!isset($_SERVER['CONTENT_TYPE']) || strpos($_SERVER['CONTENT_TYPE'],'text/xml') !== 0) {
 575                          throw new Exception('Invalid Content-Type',400);
 576                      }
 577                      
 578                      # Check CONTENT_LENGTH
 579                      if (!isset($_SERVER['CONTENT_LENGTH']) || $_SERVER['CONTENT_LENGTH'] != strlen($HTTP_RAW_POST_DATA)) {
 580                          throw new Exception('Invalid Content-Lenth',400);
 581                      }
 582                  }
 583                  
 584                  $data = $HTTP_RAW_POST_DATA;
 585              }
 586              catch (Exception $e)
 587              {
 588                  if ($e->getCode() == 400) {
 589                      $this->head(400,'Bad Request');
 590                  } elseif ($e->getCode() == 405) {
 591                      $this->head(405,'Method Not Allowed');
 592                      header('Allow: POST');
 593                  }
 594                  
 595                  header('Content-Type: text/plain');
 596                  echo $e->getMessage();
 597                  exit;
 598              }
 599          }
 600          
 601          $this->message = new xmlrpcMessage($data);
 602          
 603          try
 604          {
 605              $this->message->parse();
 606              
 607              if ($this->message->messageType != 'methodCall') {
 608                  throw new xmlrpcException('Server error. Invalid xml-rpc. not conforming to spec. Request must be a methodCall',-32600);
 609              }
 610              
 611              $result = $this->call($this->message->methodName,$this->message->params);
 612          }
 613          catch (Exception $e)
 614          {
 615              $this->error($e);
 616          }
 617          
 618          # Encode the result
 619          $r = new xmlrpcValue($result);
 620          $resultxml = $r->getXml();
 621          
 622          # Create the XML
 623          $xml =
 624          "<methodResponse>\n".
 625          "<params>\n".
 626          "<param>\n".
 627          "  <value>\n".
 628          '   '.$resultxml."\n".
 629          "  </value>\n".
 630          "</param>\n".
 631          "</params>\n".
 632          "</methodResponse>";
 633          
 634          # Send it
 635          $this->output($xml);
 636      }
 637      
 638  	protected function head($code,$msg)
 639      {
 640          $status_mode = preg_match('/cgi/',php_sapi_name());
 641          
 642          if ($status_mode) {
 643              header('Status: '.$code.' '.$msg);
 644          } else {
 645              if (version_compare(phpversion(),'4.3.0','>=')) {
 646                  header($msg,true,$code);
 647              } else {
 648                  header('HTTP/1.x '.$code.' '.$msg);
 649              }
 650          }
 651      }
 652      
 653  	protected function call($methodname,$args)
 654      {
 655          if (!$this->hasMethod($methodname)) {
 656              throw new xmlrpcException('server error. requested method "'.$methodname.'" does not exist.',-32601);
 657          }
 658          
 659          $method = $this->callbacks[$methodname];
 660          
 661          # Perform the callback and send the response
 662          if (!is_callable($method)) {
 663              throw new xmlrpcException('server error. internal requested function for "'.$methodname.'" does not exist.',-32601);
 664          }
 665          
 666          return call_user_func_array($method,$args);
 667      }
 668      
 669  	protected function error($e)
 670      {
 671          $msg = $e->getMessage();
 672          
 673          $this->output(
 674          "<methodResponse>\n".
 675          "  <fault>\n".
 676          "    <value>\n".
 677          "      <struct>\n".
 678          "        <member>\n".
 679          "          <name>faultCode</name>\n".
 680          '          <value><int>'.$e->getCode()."</int></value>\n".
 681          "        </member>\n".
 682          "        <member>\n".
 683          "          <name>faultString</name>\n".
 684          '          <value><string>'.$msg."</string></value>\n".
 685          "        </member>\n".
 686          "      </struct>\n".
 687          "    </value>\n".
 688          "  </fault>\n".
 689          "</methodResponse>\n"
 690          );
 691      }
 692      
 693  	protected function output($xml)
 694      {
 695          $xml = '<?xml version="1.0" encoding="'.$this->encoding.'"?>'."\n".$xml;
 696          $length = strlen($xml);
 697          header('Connection: close');
 698          header('Content-Length: '.$length);
 699          header('Content-Type: text/xml');
 700          header('Date: '.date('r'));
 701          echo $xml;
 702          exit;
 703      }
 704      
 705  	protected function hasMethod($method)
 706      {
 707          return in_array($method, array_keys($this->callbacks));
 708      }
 709      
 710  	protected function setCapabilities()
 711      {
 712          # Initialises capabilities array
 713          $this->capabilities = array(
 714              'xmlrpc' => array(
 715                  'specUrl' => 'http://www.xmlrpc.com/spec',
 716                  'specVersion' => 1
 717              ),
 718              'faults_interop' => array(
 719                  'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
 720                  'specVersion' => 20010516
 721              ),
 722              'system.multicall' => array(
 723                  'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
 724                  'specVersion' => 1
 725              ),
 726          );   
 727      }
 728      
 729  	protected function getCapabilities()
 730      {
 731          return $this->capabilities;
 732      }
 733      
 734  	protected function setCallbacks()
 735      {
 736          $this->callbacks['system.getCapabilities'] = array($this,'getCapabilities');
 737          $this->callbacks['system.listMethods'] = array($this,'listMethods');
 738          $this->callbacks['system.multicall'] = array($this,'multiCall');
 739      }
 740      
 741  	protected function listMethods()
 742      {
 743          # Returns a list of methods - uses array_reverse to ensure user defined
 744          # methods are listed before server defined methods
 745          return array_reverse(array_keys($this->callbacks));
 746      }
 747      
 748  	protected function multiCall($methodcalls)
 749      {
 750          # See http://www.xmlrpc.com/discuss/msgReader$1208
 751          $return = array();
 752          foreach ($methodcalls as $call)
 753          {
 754              $method = $call['methodName'];
 755              $params = $call['params'];
 756              
 757              try
 758              {
 759                  if ($method == 'system.multicall') {
 760                      throw new xmlrpcException('Recursive calls to system.multicall are forbidden',-32600);
 761                  }
 762                  
 763                  $result = $this->call($method, $params);
 764                  $return[] = array($result);
 765              }
 766              catch (Exception $e)
 767              {
 768                  $return[] = array(
 769                      'faultCode' => $e->getCode(),
 770                      'faultString' => $e->getMessage()
 771                  );
 772              }
 773          }
 774          
 775          return $return;
 776      }
 777  }
 778  
 779  class xmlrpcIntrospectionServer extends xmlrpcServer
 780  {
 781      protected $signatures;
 782      protected $help;
 783      
 784  	public function __construct($encoding='UTF-8')
 785      {
 786          $this->encoding = $encoding;
 787          $this->setCallbacks();
 788          $this->setCapabilities();
 789          
 790          $this->capabilities['introspection'] = array (
 791              'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
 792              'specVersion' => 1
 793          );
 794          
 795          $this->addCallback(
 796              'system.methodSignature', 
 797              array($this,'methodSignature'), 
 798              array('array','string'), 
 799              'Returns an array describing the return type and required parameters of a method'
 800          );
 801          
 802          $this->addCallback(
 803              'system.getCapabilities', 
 804              array($this,'getCapabilities'), 
 805              array('struct'), 
 806              'Returns a struct describing the XML-RPC specifications supported by this server'
 807          );
 808          
 809          $this->addCallback(
 810              'system.listMethods', 
 811              array($this,'listMethods'), 
 812              array('array'), 
 813              'Returns an array of available methods on this server'
 814          );
 815          
 816          $this->addCallback(
 817              'system.methodHelp', 
 818              array($this,'methodHelp'), 
 819              array('string','string'), 
 820              'Returns a documentation string for the specified method'
 821          );
 822          
 823          $this->addCallback(
 824              'system.multicall',
 825              array($this,'multiCall'),
 826              array('struct','array'),
 827              'Returns result of multiple methods calls'
 828          );
 829      }
 830      
 831  	protected function addCallback($method, $callback, $args, $help)
 832      {
 833          $this->callbacks[$method] = $callback;
 834          $this->signatures[$method] = $args;
 835          $this->help[$method] = $help;
 836      }
 837      
 838  	protected function call($methodname,$args)
 839      {
 840          # Make sure it's in an array
 841          if ($args && !is_array($args)) {
 842              $args = array($args);
 843          }
 844          
 845          # Over-rides default call method, adds signature check
 846          if (!$this->hasMethod($methodname)) {
 847              throw new xmlrpcException('Server error. Requested method "'.$methodname.'" not specified.',-32601);
 848          }
 849          
 850          $method = $this->callbacks[$methodname];
 851          $signature = $this->signatures[$methodname];
 852          
 853          if (!is_array($signature)) {
 854              throw new xmlrpcException('Server error. Wrong method signature',-36600);
 855          }
 856          
 857          $return_type = array_shift($signature);
 858          
 859          # Check the number of arguments
 860          if (count($args) != count($signature)) {
 861              throw new xmlrpcException('Server error. Wrong number of method parameters',-32602);
 862          }
 863          
 864          # Check the argument types
 865          if (!$this->checkArgs($args,$signature)) {
 866              throw new xmlrpcException('Server error. Invalid method parameters',-32602);
 867          }
 868          
 869          # It passed the test - run the "real" method call
 870          return parent::call($methodname, $args);
 871      }
 872      
 873  	protected function checkArgs($args,$signature)
 874      {
 875          for ($i = 0, $j = count($args); $i < $j; $i++)
 876          {
 877              $arg = array_shift($args);
 878              $type = array_shift($signature);
 879              
 880              switch ($type)
 881              {
 882                  case 'int':
 883                  case 'i4':
 884                      if (is_array($arg) || !is_int($arg)) {
 885                          return false;
 886                      }
 887                      break;
 888                  case 'base64':
 889                  case 'string':
 890                      if (!is_string($arg)) {
 891                          return false;
 892                      }
 893                      break;
 894                  case 'boolean':
 895                      if ($arg !== false && $arg !== true) {
 896                          return false;
 897                      }
 898                      break;
 899                  case 'float':
 900                  case 'double':
 901                      if (!is_float($arg)) {
 902                          return false;
 903                      }
 904                      break;
 905                  case 'date':
 906                  case 'dateTime.iso8601':
 907                      if (!($arg instanceof xmlrpcDate)) {
 908                          return false;
 909                      }
 910                      break;
 911              }
 912          }
 913          return true;
 914      }
 915      
 916  	protected function methodSignature($method)
 917      {
 918          if (!$this->hasMethod($method)) {
 919              throw new xmlrpcException('Server error. Requested method "'.$method.'" not specified.',-32601);
 920              
 921          }
 922          
 923          # We should be returning an array of types
 924          $types = $this->signatures[$method];
 925          $return = array();
 926          
 927          foreach ($types as $type)
 928          {
 929              switch ($type)
 930              {
 931                  case 'string':
 932                      $return[] = 'string';
 933                      break;
 934                  case 'int':
 935                  case 'i4':
 936                      $return[] = 42;
 937                      break;
 938                  case 'double':
 939                      $return[] = 3.1415;
 940                      break;
 941                  case 'dateTime.iso8601':
 942                      $return[] = new xmlrpcDate(time());
 943                      break;
 944                  case 'boolean':
 945                      $return[] = true;
 946                      break;
 947                  case 'base64':
 948                      $return[] = new xmlrpcBase64('base64');
 949                      break;
 950                  case 'array':
 951                      $return[] = array('array');
 952                      break;
 953                  case 'struct':
 954                      $return[] = array('struct' => 'struct');
 955                      break;
 956              }
 957          }
 958          return $return;
 959      }
 960      
 961  	protected function methodHelp($method)
 962      {
 963          return $this->help[$method];
 964      }
 965  }
 966  ?>


Généré le : Fri Feb 23 22:16:06 2007 par Balluche grâce à PHPXref 0.7