[ Index ]
 

Code source de Serendipity 1.2

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/bundled-libs/XML/ -> RPC.php (source)

   1  <?php
   2  
   3  /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   4  
   5  /**
   6   * PHP implementation of the XML-RPC protocol
   7   *
   8   * This is a PEAR-ified version of Useful inc's XML-RPC for PHP.
   9   * It has support for HTTP transport, proxies and authentication.
  10   *
  11   * PHP versions 4 and 5
  12   *
  13   * LICENSE: License is granted to use or modify this software
  14   * ("XML-RPC for PHP") for commercial or non-commercial use provided the
  15   * copyright of the author is preserved in any distributed or derivative work.
  16   *
  17   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESSED OR
  18   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27   *
  28   * @category   Web Services
  29   * @package    XML_RPC
  30   * @author     Edd Dumbill <edd@usefulinc.com>
  31   * @author     Stig Bakken <stig@php.net>
  32   * @author     Martin Jansen <mj@php.net>
  33   * @author     Daniel Convissor <danielc@php.net>
  34   * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
  35   * @version    CVS: $Id: RPC.php,v 1.83 2005/08/14 20:25:35 danielc Exp $
  36   * @link       http://pear.php.net/package/XML_RPC
  37   */
  38  
  39  
  40  if (!function_exists('xml_parser_create')) {
  41      PEAR::loadExtension('xml');
  42  }
  43  
  44  /**#@+
  45   * Error constants
  46   */
  47  /**
  48   * Parameter values don't match parameter types
  49   */
  50  define('XML_RPC_ERROR_INVALID_TYPE', 101);
  51  /**
  52   * Parameter declared to be numeric but the values are not
  53   */
  54  define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
  55  /**
  56   * Communication error
  57   */
  58  define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
  59  /**
  60   * The array or struct has already been started
  61   */
  62  define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
  63  /**
  64   * Incorrect parameters submitted
  65   */
  66  define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
  67  /**
  68   * Programming error by developer
  69   */
  70  define('XML_RPC_ERROR_PROGRAMMING', 106);
  71  /**#@-*/
  72  
  73  
  74  /**
  75   * Data types
  76   * @global string $GLOBALS['XML_RPC_I4']
  77   */
  78  $GLOBALS['XML_RPC_I4'] = 'i4';
  79  
  80  /**
  81   * Data types
  82   * @global string $GLOBALS['XML_RPC_Int']
  83   */
  84  $GLOBALS['XML_RPC_Int'] = 'int';
  85  
  86  /**
  87   * Data types
  88   * @global string $GLOBALS['XML_RPC_Boolean']
  89   */
  90  $GLOBALS['XML_RPC_Boolean'] = 'boolean';
  91  
  92  /**
  93   * Data types
  94   * @global string $GLOBALS['XML_RPC_Double']
  95   */
  96  $GLOBALS['XML_RPC_Double'] = 'double';
  97  
  98  /**
  99   * Data types
 100   * @global string $GLOBALS['XML_RPC_String']
 101   */
 102  $GLOBALS['XML_RPC_String'] = 'string';
 103  
 104  /**
 105   * Data types
 106   * @global string $GLOBALS['XML_RPC_DateTime']
 107   */
 108  $GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
 109  
 110  /**
 111   * Data types
 112   * @global string $GLOBALS['XML_RPC_Base64']
 113   */
 114  $GLOBALS['XML_RPC_Base64'] = 'base64';
 115  
 116  /**
 117   * Data types
 118   * @global string $GLOBALS['XML_RPC_Array']
 119   */
 120  $GLOBALS['XML_RPC_Array'] = 'array';
 121  
 122  /**
 123   * Data types
 124   * @global string $GLOBALS['XML_RPC_Struct']
 125   */
 126  $GLOBALS['XML_RPC_Struct'] = 'struct';
 127  
 128  
 129  /**
 130   * Data type meta-types
 131   * @global array $GLOBALS['XML_RPC_Types']
 132   */
 133  $GLOBALS['XML_RPC_Types'] = array(
 134      $GLOBALS['XML_RPC_I4']       => 1,
 135      $GLOBALS['XML_RPC_Int']      => 1,
 136      $GLOBALS['XML_RPC_Boolean']  => 1,
 137      $GLOBALS['XML_RPC_String']   => 1,
 138      $GLOBALS['XML_RPC_Double']   => 1,
 139      $GLOBALS['XML_RPC_DateTime'] => 1,
 140      $GLOBALS['XML_RPC_Base64']   => 1,
 141      $GLOBALS['XML_RPC_Array']    => 2,
 142      $GLOBALS['XML_RPC_Struct']   => 3,
 143  );
 144  
 145  
 146  /**
 147   * Error message numbers
 148   * @global array $GLOBALS['XML_RPC_err']
 149   */
 150  $GLOBALS['XML_RPC_err'] = array(
 151      'unknown_method'      => 1,
 152      'invalid_return'      => 2,
 153      'incorrect_params'    => 3,
 154      'introspect_unknown'  => 4,
 155      'http_error'          => 5,
 156      'not_response_object' => 6,
 157      'invalid_request'     => 7,
 158  );
 159  
 160  /**
 161   * Error message strings
 162   * @global array $GLOBALS['XML_RPC_str']
 163   */
 164  $GLOBALS['XML_RPC_str'] = array(
 165      'unknown_method'      => 'Unknown method',
 166      'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
 167      'incorrect_params'    => 'Incorrect parameters passed to method',
 168      'introspect_unknown'  => 'Can\'t introspect: method unknown',
 169      'http_error'          => 'Didn\'t receive 200 OK from remote server.',
 170      'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
 171      'invalid_request'     => 'Invalid request payload',
 172  );
 173  
 174  
 175  /**
 176   * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
 177   * @global string $GLOBALS['XML_RPC_defencoding']
 178   */
 179  $GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
 180  
 181  /**
 182   * User error codes start at 800
 183   * @global int $GLOBALS['XML_RPC_erruser']
 184   */
 185  $GLOBALS['XML_RPC_erruser'] = 800;
 186  
 187  /**
 188   * XML parse error codes start at 100
 189   * @global int $GLOBALS['XML_RPC_errxml']
 190   */
 191  $GLOBALS['XML_RPC_errxml'] = 100;
 192  
 193  
 194  /**
 195   * Compose backslashes for escaping regexp
 196   * @global string $GLOBALS['XML_RPC_backslash']
 197   */
 198  $GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
 199  
 200  
 201  /**
 202   * Valid parents of XML elements
 203   * @global array $GLOBALS['XML_RPC_valid_parents']
 204   */
 205  $GLOBALS['XML_RPC_valid_parents'] = array(
 206      'BOOLEAN' => array('VALUE'),
 207      'I4' => array('VALUE'),
 208      'INT' => array('VALUE'),
 209      'STRING' => array('VALUE'),
 210      'DOUBLE' => array('VALUE'),
 211      'DATETIME.ISO8601' => array('VALUE'),
 212      'BASE64' => array('VALUE'),
 213      'ARRAY' => array('VALUE'),
 214      'STRUCT' => array('VALUE'),
 215      'PARAM' => array('PARAMS'),
 216      'METHODNAME' => array('METHODCALL'),
 217      'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
 218      'MEMBER' => array('STRUCT'),
 219      'NAME' => array('MEMBER'),
 220      'DATA' => array('ARRAY'),
 221      'FAULT' => array('METHODRESPONSE'),
 222      'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
 223  );
 224  
 225  
 226  /**
 227   * Stores state during parsing
 228   *
 229   * quick explanation of components:
 230   *   + ac     = accumulates values
 231   *   + qt     = decides if quotes are needed for evaluation
 232   *   + cm     = denotes struct or array (comma needed)
 233   *   + isf    = indicates a fault
 234   *   + lv     = indicates "looking for a value": implements the logic
 235   *               to allow values with no types to be strings
 236   *   + params = stores parameters in method calls
 237   *   + method = stores method name
 238   *
 239   * @global array $GLOBALS['XML_RPC_xh']
 240   */
 241  $GLOBALS['XML_RPC_xh'] = array();
 242  
 243  
 244  /**
 245   * Start element handler for the XML parser
 246   *
 247   * @return void
 248   */
 249  function XML_RPC_se($parser_resource, $name, $attrs)
 250  {
 251      global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String, $XML_RPC_valid_parents;
 252      $parser = (int) $parser_resource;
 253  
 254      // if invalid xmlrpc already detected, skip all processing
 255      if ($XML_RPC_xh[$parser]['isf'] >= 2) {
 256          return;
 257      }
 258  
 259      // check for correct element nesting
 260      // top level element can only be of 2 types
 261      if (count($XML_RPC_xh[$parser]['stack']) == 0) {
 262          if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
 263              $XML_RPC_xh[$parser]['isf'] = 2;
 264              $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
 265              return;
 266          }
 267      } else {
 268          // not top level element: see if parent is OK
 269          if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
 270              $name = preg_replace('[^a-zA-Z0-9._-]', '', $name);
 271              $XML_RPC_xh[$parser]['isf'] = 2;
 272              $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}";
 273              return;
 274          }
 275      }
 276  
 277      switch ($name) {
 278      case 'STRUCT':
 279          $XML_RPC_xh[$parser]['cm']++;
 280  
 281          // turn quoting off
 282          $XML_RPC_xh[$parser]['qt'] = 0;
 283  
 284          $cur_val = array();
 285          $cur_val['value'] = array();
 286          $cur_val['members'] = 1;
 287          array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 288          break;
 289  
 290      case 'ARRAY':
 291          $XML_RPC_xh[$parser]['cm']++;
 292  
 293          // turn quoting off
 294          $XML_RPC_xh[$parser]['qt'] = 0;
 295  
 296          $cur_val = array();
 297          $cur_val['value'] = array();
 298          $cur_val['members'] = 0;
 299          array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 300          break;
 301  
 302      case 'NAME':
 303          $XML_RPC_xh[$parser]['ac'] = '';
 304          break;
 305  
 306      case 'FAULT':
 307          $XML_RPC_xh[$parser]['isf'] = 1;
 308          break;
 309  
 310      case 'PARAM':
 311          $XML_RPC_xh[$parser]['valuestack'] = array();
 312          break;
 313  
 314      case 'VALUE':
 315          $XML_RPC_xh[$parser]['lv'] = 1;
 316          $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
 317          $XML_RPC_xh[$parser]['ac'] = '';
 318          $XML_RPC_xh[$parser]['qt'] = 0;
 319          // look for a value: if this is still 1 by the
 320          // time we reach the first data segment then the type is string
 321          // by implication and we need to add in a quote
 322          break;
 323  
 324      case 'I4':
 325      case 'INT':
 326      case 'STRING':
 327      case 'BOOLEAN':
 328      case 'DOUBLE':
 329      case 'DATETIME.ISO8601':
 330      case 'BASE64':
 331          $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
 332  
 333          if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
 334              $XML_RPC_xh[$parser]['qt'] = 1;
 335  
 336              if ($name == 'DATETIME.ISO8601') {
 337                  $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
 338              }
 339  
 340          } elseif ($name == 'BASE64') {
 341              $XML_RPC_xh[$parser]['qt'] = 2;
 342          } else {
 343              // No quoting is required here -- but
 344              // at the end of the element we must check
 345              // for data format errors.
 346              $XML_RPC_xh[$parser]['qt'] = 0;
 347          }
 348          break;
 349  
 350      case 'MEMBER':
 351          $XML_RPC_xh[$parser]['ac'] = '';
 352          break;
 353  
 354      case 'DATA':
 355      case 'METHODCALL':
 356      case 'METHODNAME':
 357      case 'METHODRESPONSE':
 358      case 'PARAMS':
 359          // valid elements that add little to processing
 360          break;
 361      }
 362  
 363  
 364      // Save current element to stack
 365      array_unshift($XML_RPC_xh[$parser]['stack'], $name);
 366  
 367      if ($name != 'VALUE') {
 368          $XML_RPC_xh[$parser]['lv'] = 0;
 369      }
 370  }
 371  
 372  /**
 373   * End element handler for the XML parser
 374   *
 375   * @return void
 376   */
 377  function XML_RPC_ee($parser_resource, $name)
 378  {
 379      global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
 380      $parser = (int) $parser_resource;
 381  
 382      if ($XML_RPC_xh[$parser]['isf'] >= 2) {
 383          return;
 384      }
 385  
 386      // push this element from stack
 387      // NB: if XML validates, correct opening/closing is guaranteed and
 388      // we do not have to check for $name == $curr_elem.
 389      // we also checked for proper nesting at start of elements...
 390      $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
 391  
 392      switch ($name) {
 393      case 'STRUCT':
 394      case 'ARRAY':
 395      $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
 396      $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
 397          $XML_RPC_xh[$parser]['vt'] = strtolower($name);
 398          $XML_RPC_xh[$parser]['cm']--;
 399          break;
 400  
 401      case 'NAME':
 402      $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
 403          break;
 404  
 405      case 'BOOLEAN':
 406          // special case here: we translate boolean 1 or 0 into PHP
 407          // constants true or false
 408          if ($XML_RPC_xh[$parser]['ac'] == '1') {
 409              $XML_RPC_xh[$parser]['ac'] = 'true';
 410          } else {
 411              $XML_RPC_xh[$parser]['ac'] = 'false';
 412          }
 413  
 414          $XML_RPC_xh[$parser]['vt'] = strtolower($name);
 415          // Drop through intentionally.
 416  
 417      case 'I4':
 418      case 'INT':
 419      case 'STRING':
 420      case 'DOUBLE':
 421      case 'DATETIME.ISO8601':
 422      case 'BASE64':
 423          if ($XML_RPC_xh[$parser]['qt'] == 1) {
 424              // we use double quotes rather than single so backslashification works OK
 425              $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 426          } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
 427              $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
 428          } elseif ($name == 'BOOLEAN') {
 429              $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 430          } else {
 431              // we have an I4, INT or a DOUBLE
 432              // we must check that only 0123456789-.<space> are characters here
 433              if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
 434                  XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
 435                                           XML_RPC_ERROR_NON_NUMERIC_FOUND);
 436                  $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
 437              } else {
 438                  // it's ok, add it on
 439                  $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 440              }
 441          }
 442  
 443          $XML_RPC_xh[$parser]['ac'] = '';
 444          $XML_RPC_xh[$parser]['qt'] = 0;
 445          $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
 446          break;
 447  
 448      case 'VALUE':
 449          // deal with a string value
 450          if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
 451              $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
 452              $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
 453          }
 454  
 455          $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
 456  
 457          $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
 458          if (is_array($cur_val)) {
 459              if ($cur_val['members']==0) {
 460                  $cur_val['value'][] = $temp;
 461              } else {
 462                  $XML_RPC_xh[$parser]['value'] = $temp;
 463              }
 464              array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 465          } else {
 466              $XML_RPC_xh[$parser]['value'] = $temp;
 467          }
 468          break;
 469  
 470      case 'MEMBER':
 471          $XML_RPC_xh[$parser]['ac'] = '';
 472          $XML_RPC_xh[$parser]['qt'] = 0;
 473  
 474          $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
 475          if (is_array($cur_val)) {
 476              if ($cur_val['members']==1) {
 477                  $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
 478              }
 479              array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
 480          }
 481          break;
 482  
 483      case 'DATA':
 484          $XML_RPC_xh[$parser]['ac'] = '';
 485          $XML_RPC_xh[$parser]['qt'] = 0;
 486          break;
 487  
 488      case 'PARAM':
 489          $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
 490          break;
 491  
 492      case 'METHODNAME':
 493      case 'RPCMETHODNAME':
 494          $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
 495                                                        $XML_RPC_xh[$parser]['ac']);
 496          break;
 497      }
 498  
 499      // if it's a valid type name, set the type
 500      if (isset($XML_RPC_Types[strtolower($name)])) {
 501          $XML_RPC_xh[$parser]['vt'] = strtolower($name);
 502      }
 503  }
 504  
 505  /**
 506   * Character data handler for the XML parser
 507   *
 508   * @return void
 509   */
 510  function XML_RPC_cd($parser_resource, $data)
 511  {
 512      global $XML_RPC_xh, $XML_RPC_backslash;
 513      $parser = (int) $parser_resource;
 514  
 515      if ($XML_RPC_xh[$parser]['lv'] != 3) {
 516          // "lookforvalue==3" means that we've found an entire value
 517          // and should discard any further character data
 518  
 519          if ($XML_RPC_xh[$parser]['lv'] == 1) {
 520              // if we've found text and we're just in a <value> then
 521              // turn quoting on, as this will be a string
 522              $XML_RPC_xh[$parser]['qt'] = 1;
 523              // and say we've found a value
 524              $XML_RPC_xh[$parser]['lv'] = 2;
 525          }
 526  
 527          // replace characters that eval would
 528          // do special things with
 529          if (!isset($XML_RPC_xh[$parser]['ac'])) {
 530              $XML_RPC_xh[$parser]['ac'] = '';
 531          }
 532          $XML_RPC_xh[$parser]['ac'] .= $data;
 533      }
 534  }
 535  
 536  /**
 537   * The common methods and properties for all of the XML_RPC classes
 538   *
 539   * @category   Web Services
 540   * @package    XML_RPC
 541   * @author     Edd Dumbill <edd@usefulinc.com>
 542   * @author     Stig Bakken <stig@php.net>
 543   * @author     Martin Jansen <mj@php.net>
 544   * @author     Daniel Convissor <danielc@php.net>
 545   * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
 546   * @version    Release: 1.4.0
 547   * @link       http://pear.php.net/package/XML_RPC
 548   */
 549  class XML_RPC_Base {
 550  
 551      /**
 552       * PEAR Error handling
 553       *
 554       * @return object  PEAR_Error object
 555       */
 556      function raiseError($msg, $code)
 557      {
 558          include_once dirname(__FILE__) . '/../PEAR.php';
 559          if (is_object(@$this)) {
 560              return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
 561          } else {
 562              return PEAR::raiseError('XML_RPC: ' . $msg, $code);
 563          }
 564      }
 565  
 566      /**
 567       * Tell whether something is a PEAR_Error object
 568       *
 569       * @param mixed $value  the item to check
 570       *
 571       * @return bool  whether $value is a PEAR_Error object or not
 572       *
 573       * @access public
 574       */
 575      function isError($value)
 576      {
 577          return is_a($value, 'PEAR_Error');
 578      }
 579  }
 580  
 581  /**
 582   * The methods and properties for submitting XML RPC requests
 583   *
 584   * @category   Web Services
 585   * @package    XML_RPC
 586   * @author     Edd Dumbill <edd@usefulinc.com>
 587   * @author     Stig Bakken <stig@php.net>
 588   * @author     Martin Jansen <mj@php.net>
 589   * @author     Daniel Convissor <danielc@php.net>
 590   * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
 591   * @version    Release: 1.4.0
 592   * @link       http://pear.php.net/package/XML_RPC
 593   */
 594  class XML_RPC_Client extends XML_RPC_Base {
 595  
 596      /**
 597       * The path and name of the RPC server script you want the request to go to
 598       * @var string
 599       */
 600      var $path = '';
 601  
 602      /**
 603       * The name of the remote server to connect to
 604       * @var string
 605       */
 606      var $server = '';
 607  
 608      /**
 609       * The protocol to use in contacting the remote server
 610       * @var string
 611       */
 612      var $protocol = 'http://';
 613  
 614      /**
 615       * The port for connecting to the remote server
 616       *
 617       * The default is 80 for http:// connections
 618       * and 443 for https:// and ssl:// connections.
 619       *
 620       * @var integer
 621       */
 622      var $port = 80;
 623  
 624      /**
 625       * A user name for accessing the RPC server
 626       * @var string
 627       * @see XML_RPC_Client::setCredentials()
 628       */
 629      var $username = '';
 630  
 631      /**
 632       * A password for accessing the RPC server
 633       * @var string
 634       * @see XML_RPC_Client::setCredentials()
 635       */
 636      var $password = '';
 637  
 638      /**
 639       * The name of the proxy server to use, if any
 640       * @var string
 641       */
 642      var $proxy = '';
 643  
 644      /**
 645       * The protocol to use in contacting the proxy server, if any
 646       * @var string
 647       */
 648      var $proxy_protocol = 'http://';
 649  
 650      /**
 651       * The port for connecting to the proxy server
 652       *
 653       * The default is 8080 for http:// connections
 654       * and 443 for https:// and ssl:// connections.
 655       *
 656       * @var integer
 657       */
 658      var $proxy_port = 8080;
 659  
 660      /**
 661       * A user name for accessing the proxy server
 662       * @var string
 663       */
 664      var $proxy_user = '';
 665  
 666      /**
 667       * A password for accessing the proxy server
 668       * @var string
 669       */
 670      var $proxy_pass = '';
 671  
 672      /**
 673       * The error number, if any
 674       * @var integer
 675       */
 676      var $errno = 0;
 677  
 678      /**
 679       * The error message, if any
 680       * @var string
 681       */
 682      var $errstr = '';
 683  
 684      /**
 685       * The current debug mode (1 = on, 0 = off)
 686       * @var integer
 687       */
 688      var $debug = 0;
 689  
 690      /**
 691       * The HTTP headers for the current request.
 692       * @var string
 693       */
 694      var $headers = '';
 695  
 696  
 697      /**
 698       * Sets the object's properties
 699       *
 700       * @param string  $path        the path and name of the RPC server script
 701       *                              you want the request to go to
 702       * @param string  $server      the URL of the remote server to connect to.
 703       *                              If this parameter doesn't specify a
 704       *                              protocol and $port is 443, ssl:// is
 705       *                              assumed.
 706       * @param integer $port        a port for connecting to the remote server.
 707       *                              Defaults to 80 for http:// connections and
 708       *                              443 for https:// and ssl:// connections.
 709       * @param string  $proxy       the URL of the proxy server to use, if any.
 710       *                              If this parameter doesn't specify a
 711       *                              protocol and $port is 443, ssl:// is
 712       *                              assumed.
 713       * @param integer $proxy_port  a port for connecting to the remote server.
 714       *                              Defaults to 8080 for http:// connections and
 715       *                              443 for https:// and ssl:// connections.
 716       * @param string  $proxy_user  a user name for accessing the proxy server
 717       * @param string  $proxy_pass  a password for accessing the proxy server
 718       *
 719       * @return void
 720       */
 721      function XML_RPC_Client($path, $server, $port = 0,
 722                              $proxy = '', $proxy_port = 0,
 723                              $proxy_user = '', $proxy_pass = '')
 724      {
 725          $this->path       = $path;
 726          $this->proxy_user = $proxy_user;
 727          $this->proxy_pass = $proxy_pass;
 728  
 729          preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
 730          if ($match[1] == '') {
 731              if ($port == 443) {
 732                  $this->server   = $match[2];
 733                  $this->protocol = 'ssl://';
 734                  $this->port     = 443;
 735              } else {
 736                  $this->server = $match[2];
 737                  if ($port) {
 738                      $this->port = $port;
 739                  }
 740              }
 741          } elseif ($match[1] == 'http://') {
 742              $this->server = $match[2];
 743              if ($port) {
 744                  $this->port = $port;
 745              }
 746          } else {
 747              $this->server   = $match[2];
 748              $this->protocol = 'ssl://';
 749              if ($port) {
 750                  $this->port = $port;
 751              } else {
 752                  $this->port = 443;
 753              }
 754          }
 755  
 756          if ($proxy) {
 757              preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
 758              if ($match[1] == '') {
 759                  if ($proxy_port == 443) {
 760                      $this->proxy          = $match[2];
 761                      $this->proxy_protocol = 'ssl://';
 762                      $this->proxy_port     = 443;
 763                  } else {
 764                      $this->proxy = $match[2];
 765                      if ($proxy_port) {
 766                          $this->proxy_port = $proxy_port;
 767                      }
 768                  }
 769              } elseif ($match[1] == 'http://') {
 770                  $this->proxy = $match[2];
 771                  if ($proxy_port) {
 772                      $this->proxy_port = $proxy_port;
 773                  }
 774              } else {
 775                  $this->proxy          = $match[2];
 776                  $this->proxy_protocol = 'ssl://';
 777                  if ($proxy_port) {
 778                      $this->proxy_port = $proxy_port;
 779                  } else {
 780                      $this->proxy_port = 443;
 781                  }
 782              }
 783          }
 784      }
 785  
 786      /**
 787       * Change the current debug mode
 788       *
 789       * @param int $in  where 1 = on, 0 = off
 790       *
 791       * @return void
 792       */
 793      function setDebug($in)
 794      {
 795          if ($in) {
 796              $this->debug = 1;
 797          } else {
 798              $this->debug = 0;
 799          }
 800      }
 801  
 802      /**
 803       * Set username and password properties for connecting to the RPC server
 804       *
 805       * @param string $u  the user name
 806       * @param string $p  the password
 807       *
 808       * @return void
 809       *
 810       * @see XML_RPC_Client::$username, XML_RPC_Client::$password
 811       */
 812      function setCredentials($u, $p)
 813      {
 814          $this->username = $u;
 815          $this->password = $p;
 816      }
 817  
 818      /**
 819       * Transmit the RPC request via HTTP 1.0 protocol
 820       *
 821       * @param object $msg       the XML_RPC_Message object
 822       * @param int    $timeout   how many seconds to wait for the request
 823       *
 824       * @return object  an XML_RPC_Response object.  0 is returned if any
 825       *                  problems happen.
 826       *
 827       * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
 828       *      XML_RPC_Client::setCredentials()
 829       */
 830      function send($msg, $timeout = 0)
 831      {
 832          if (strtolower(get_class($msg)) != 'xml_rpc_message') {
 833              $this->errstr = 'send()\'s $msg parameter must be an'
 834                            . ' XML_RPC_Message object.';
 835              $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
 836              return 0;
 837          }
 838          $msg->debug = $this->debug;
 839          return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
 840                                          $timeout, $this->username,
 841                                          $this->password);
 842      }
 843  
 844      /**
 845       * Transmit the RPC request via HTTP 1.0 protocol
 846       *
 847       * Requests should be sent using XML_RPC_Client send() rather than
 848       * calling this method directly.
 849       *
 850       * @param object $msg       the XML_RPC_Message object
 851       * @param string $server    the server to send the request to
 852       * @param int    $port      the server port send the request to
 853       * @param int    $timeout   how many seconds to wait for the request
 854       *                           before giving up
 855       * @param string $username  a user name for accessing the RPC server
 856       * @param string $password  a password for accessing the RPC server
 857       *
 858       * @return object  an XML_RPC_Response object.  0 is returned if any
 859       *                  problems happen.
 860       *
 861       * @access protected
 862       * @see XML_RPC_Client::send()
 863       */
 864      function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
 865                                 $username = '', $password = '')
 866      {
 867          /*
 868           * If we're using a proxy open a socket to the proxy server
 869           * instead to the xml-rpc server
 870           */
 871          if ($this->proxy) {
 872              if ($this->proxy_protocol == 'http://') {
 873                  $protocol = '';
 874              } else {
 875                  $protocol = $this->proxy_protocol;
 876              }
 877              if ($timeout > 0) {
 878                  $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
 879                                   $this->errno, $this->errstr, $timeout);
 880              } else {
 881                  $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
 882                                   $this->errno, $this->errstr);
 883              }
 884          } else {
 885              if ($this->protocol == 'http://') {
 886                  $protocol = '';
 887              } else {
 888                  $protocol = $this->protocol;
 889              }
 890              if ($timeout > 0) {
 891                  $fp = @fsockopen($protocol . $server, $port,
 892                                   $this->errno, $this->errstr, $timeout);
 893              } else {
 894                  $fp = @fsockopen($protocol . $server, $port,
 895                                   $this->errno, $this->errstr);
 896              }
 897          }
 898  
 899          /*
 900           * Just raising the error without returning it is strange,
 901           * but keep it here for backwards compatibility.
 902           */
 903          if (!$fp && $this->proxy) {
 904              $this->raiseError('Connection to proxy server '
 905                                . $this->proxy . ':' . $this->proxy_port
 906                                . ' failed. ' . $this->errstr,
 907                                XML_RPC_ERROR_CONNECTION_FAILED);
 908              return 0;
 909          } elseif (!$fp) {
 910              $this->raiseError('Connection to RPC server '
 911                                . $server . ':' . $port
 912                                . ' failed. ' . $this->errstr,
 913                                XML_RPC_ERROR_CONNECTION_FAILED);
 914              return 0;
 915          }
 916  
 917          if ($timeout) {
 918              /*
 919               * Using socket_set_timeout() because stream_set_timeout()
 920               * was introduced in 4.3.0, but we need to support 4.2.0.
 921               */
 922              socket_set_timeout($fp, $timeout);
 923          }
 924  
 925          // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
 926          if ($username != $this->username) {
 927              $this->setCredentials($username, $password);
 928          }
 929  
 930          // Only create the payload if it was not created previously
 931          if (empty($msg->payload)) {
 932              $msg->createPayload();
 933          }
 934          $this->createHeaders($msg);
 935  
 936          $op  = $this->headers . "\r\n\r\n";
 937          $op .= $msg->payload;
 938  
 939          if (!fputs($fp, $op, strlen($op))) {
 940              $this->errstr = 'Write error';
 941              return 0;
 942          }
 943          $resp = $msg->parseResponseFile($fp);
 944  
 945          $meta = socket_get_status($fp);
 946          if ($meta['timed_out']) {
 947              fclose($fp);
 948              $this->errstr = 'RPC server did not send response before timeout.';
 949              $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
 950              return 0;
 951          }
 952  
 953          fclose($fp);
 954          return $resp;
 955      }
 956  
 957      /**
 958       * Determines the HTTP headers and puts it in the $headers property
 959       *
 960       * @param object $msg       the XML_RPC_Message object
 961       *
 962       * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
 963       *
 964       * @access protected
 965       */
 966      function createHeaders($msg)
 967      {
 968          if (empty($msg->payload)) {
 969              return false;
 970          }
 971          if ($this->proxy) {
 972              $this->headers = 'POST ' . $this->protocol . $this->server;
 973              if ($this->proxy_port) {
 974                  $this->headers .= ':' . $this->port;
 975              }
 976          } else {
 977             $this->headers = 'POST ';
 978          }
 979          $this->headers .= $this->path. " HTTP/1.0\r\n";
 980  
 981          $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
 982          $this->headers .= 'Host: ' . $this->server . "\r\n";
 983  
 984          if ($this->proxy && $this->proxy_user) {
 985              $this->headers .= 'Proxy-Authorization: Basic '
 986                       . base64_encode("$this->proxy_user:$this->proxy_pass")
 987                       . "\r\n";
 988          }
 989  
 990          // thanks to Grant Rauscher <grant7@firstworld.net> for this
 991          if ($this->username) {
 992              $this->headers .= 'Authorization: Basic '
 993                       . base64_encode("$this->username:$this->password")
 994                       . "\r\n";
 995          }
 996  
 997          $this->headers .= "Content-Type: text/xml\r\n";
 998          $this->headers .= 'Content-Length: ' . strlen($msg->payload);
 999          return true;
1000      }
1001  }
1002  
1003  /**
1004   * The methods and properties for interpreting responses to XML RPC requests
1005   *
1006   * @category   Web Services
1007   * @package    XML_RPC
1008   * @author     Edd Dumbill <edd@usefulinc.com>
1009   * @author     Stig Bakken <stig@php.net>
1010   * @author     Martin Jansen <mj@php.net>
1011   * @author     Daniel Convissor <danielc@php.net>
1012   * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
1013   * @version    Release: 1.4.0
1014   * @link       http://pear.php.net/package/XML_RPC
1015   */
1016  class XML_RPC_Response extends XML_RPC_Base
1017  {
1018      var $xv;
1019      var $fn;
1020      var $fs;
1021      var $hdrs;
1022  
1023      /**
1024       * @return void
1025       */
1026      function XML_RPC_Response($val, $fcode = 0, $fstr = '')
1027      {
1028          if ($fcode != 0) {
1029              $this->fn = $fcode;
1030              $this->fs = htmlspecialchars($fstr);
1031          } else {
1032              $this->xv = $val;
1033          }
1034      }
1035  
1036      /**
1037       * @return int  the error code
1038       */
1039      function faultCode()
1040      {
1041          if (isset($this->fn)) {
1042              return $this->fn;
1043          } else {
1044              return 0;
1045          }
1046      }
1047  
1048      /**
1049       * @return string  the error string
1050       */
1051      function faultString()
1052      {
1053          return $this->fs;
1054      }
1055  
1056      /**
1057       * @return mixed  the value
1058       */
1059      function value()
1060      {
1061          return $this->xv;
1062      }
1063  
1064      /**
1065       * @return string  the error message in XML format
1066       */
1067      function serialize()
1068      {
1069          $rs = "<methodResponse>\n";
1070          if ($this->fn) {
1071              $rs .= "<fault>
1072    <value>
1073      <struct>
1074        <member>
1075          <name>faultCode</name>
1076          <value><int>" . $this->fn . "</int></value>
1077        </member>
1078        <member>
1079          <name>faultString</name>
1080          <value><string>" . $this->fs . "</string></value>
1081        </member>
1082      </struct>
1083    </value>
1084  </fault>";
1085          } else {
1086              $rs .= "<params>\n<param>\n" . $this->xv->serialize() .
1087          "</param>\n</params>";
1088          }
1089          $rs .= "\n</methodResponse>";
1090          return $rs;
1091      }
1092  }
1093  
1094  /**
1095   * The methods and properties for composing XML RPC messages
1096   *
1097   * @category   Web Services
1098   * @package    XML_RPC
1099   * @author     Edd Dumbill <edd@usefulinc.com>
1100   * @author     Stig Bakken <stig@php.net>
1101   * @author     Martin Jansen <mj@php.net>
1102   * @author     Daniel Convissor <danielc@php.net>
1103   * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
1104   * @version    Release: 1.4.0
1105   * @link       http://pear.php.net/package/XML_RPC
1106   */
1107  class XML_RPC_Message extends XML_RPC_Base
1108  {
1109      /**
1110       * The current debug mode (1 = on, 0 = off)
1111       * @var integer
1112       */
1113      var $debug = 0;
1114  
1115      /**
1116       * The encoding to be used for outgoing messages
1117       *
1118       * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var>
1119       *
1120       * @var string
1121       * @see XML_RPC_Message::setSendEncoding(),
1122       *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
1123       */
1124      var $send_encoding = '';
1125  
1126      /**
1127       * The method presently being evaluated
1128       * @var string
1129       */
1130      var $methodname = '';
1131  
1132      /**
1133       * @var array
1134       */
1135      var $params = array();
1136  
1137      /**
1138       * The XML message being generated
1139       * @var string
1140       */
1141      var $payload = '';
1142  
1143      /**
1144       * @return void
1145       */
1146      function XML_RPC_Message($meth, $pars = 0)
1147      {
1148          $this->methodname = $meth;
1149          if (is_array($pars) && sizeof($pars) > 0) {
1150              for ($i = 0; $i < sizeof($pars); $i++) {
1151                  $this->addParam($pars[$i]);
1152              }
1153          }
1154      }
1155  
1156      /**
1157       * Produces the XML declaration including the encoding attribute
1158       *
1159       * The encoding is determined by this class' <var>$send_encoding</var>
1160       * property.  If the <var>$send_encoding</var> property is not set, use
1161       * <var>$GLOBALS['XML_RPC_defencoding']</var>.
1162       *
1163       * @return string  the XML declaration and <methodCall> element
1164       *
1165       * @see XML_RPC_Message::setSendEncoding(),
1166       *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
1167       */
1168      function xml_header()
1169      {
1170          global $XML_RPC_defencoding;
1171          if (!$this->send_encoding) {
1172              $this->send_encoding = $XML_RPC_defencoding;
1173          }
1174          return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>'
1175                 . "\n<methodCall>\n";
1176      }
1177  
1178      /**
1179       * @return string  the closing </methodCall> tag
1180       */
1181      function xml_footer()
1182      {
1183          return "</methodCall>\n";
1184      }
1185  
1186      /**
1187       * @return void
1188       *
1189       * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
1190       */
1191      function createPayload()
1192      {
1193          $this->payload = $this->xml_header();
1194          $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n";
1195          $this->payload .= "<params>\n";
1196          for ($i = 0; $i < sizeof($this->params); $i++) {
1197              $p = $this->params[$i];
1198              $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
1199          }
1200          $this->payload .= "</params>\n";
1201          $this->payload .= $this->xml_footer();
1202          $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
1203      }
1204  
1205      /**
1206       * @return string  the name of the method
1207       */
1208      function method($meth = '')
1209      {
1210          if ($meth != '') {
1211              $this->methodname = $meth;
1212          }
1213          return $this->methodname;
1214      }
1215  
1216      /**
1217       * @return string  the payload
1218       */
1219      function serialize()
1220      {
1221          $this->createPayload();
1222          return $this->payload;
1223      }
1224  
1225      /**
1226       * @return void
1227       */
1228      function addParam($par)
1229      {
1230          $this->params[] = $par;
1231      }
1232  
1233      /**
1234       * Obtains an XML_RPC_Value object for the given parameter
1235       *
1236       * @param int $i  the index number of the parameter to obtain
1237       *
1238       * @return object  the XML_RPC_Value object.
1239       *                  If the parameter doesn't exist, an XML_RPC_Response object.
1240       *
1241       * @since Returns XML_RPC_Response object on error since Release 1.3.0
1242       */
1243      function getParam($i)
1244      {
1245          global $XML_RPC_err, $XML_RPC_str;
1246  
1247          if (isset($this->params[$i])) {
1248              return $this->params[$i];
1249          } else {
1250              $this->raiseError('The submitted request did not contain this parameter',
1251                                XML_RPC_ERROR_INCORRECT_PARAMS);
1252              return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
1253                                          $XML_RPC_str['incorrect_params']);
1254          }
1255      }
1256  
1257      /**
1258       * @return int  the number of parameters
1259       */
1260      function getNumParams()
1261      {
1262          return sizeof($this->params);
1263      }
1264  
1265      /**
1266       * Sets the XML declaration's encoding attribute
1267       *
1268       * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
1269       *
1270       * @return void
1271       *
1272       * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
1273       * @since Method available since Release 1.2.0
1274       */
1275      function setSendEncoding($type)
1276      {
1277          $this->send_encoding = $type;
1278      }
1279  
1280      /**
1281       * Determine the XML's encoding via the encoding attribute
1282       * in the XML declaration
1283       *
1284       * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
1285       * or US-ASCII, $XML_RPC_defencoding will be returned.
1286       *
1287       * @param string $data  the XML that will be parsed
1288       *
1289       * @return string  the encoding to be used
1290       *
1291       * @link   http://php.net/xml_parser_create
1292       * @since  Method available since Release 1.2.0
1293       */
1294      function getEncoding($data)
1295      {
1296          global $XML_RPC_defencoding;
1297  
1298          if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
1299                         $data, $match))
1300          {
1301              $match[1] = trim(strtoupper($match[1]));
1302              switch ($match[1]) {
1303                  case 'ISO-8859-1':
1304                  case 'UTF-8':
1305                  case 'US-ASCII':
1306                      return $match[1];
1307                      break;
1308  
1309                  default:
1310                      return $XML_RPC_defencoding;
1311              }
1312          } else {
1313              return $XML_RPC_defencoding;
1314          }
1315      }
1316  
1317      /**
1318       * @return object  a new XML_RPC_Response object
1319       */
1320      function parseResponseFile($fp)
1321      {
1322          $ipd = '';
1323          while ($data = @fread($fp, 8192)) {
1324              $ipd .= $data;
1325          }
1326          return $this->parseResponse($ipd);
1327      }
1328  
1329      /**
1330       * @return object  a new XML_RPC_Response object
1331       */
1332      function parseResponse($data = '')
1333      {
1334          global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
1335  
1336          $encoding = $this->getEncoding($data);
1337          $parser_resource = xml_parser_create($encoding);
1338          $parser = (int) $parser_resource;
1339  
1340          $XML_RPC_xh = array();
1341          $XML_RPC_xh[$parser] = array();
1342  
1343          $XML_RPC_xh[$parser]['cm'] = 0;
1344          $XML_RPC_xh[$parser]['isf'] = 0;
1345          $XML_RPC_xh[$parser]['ac'] = '';
1346          $XML_RPC_xh[$parser]['qt'] = '';
1347          $XML_RPC_xh[$parser]['stack'] = array();
1348          $XML_RPC_xh[$parser]['valuestack'] = array();
1349  
1350          xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
1351          xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
1352          xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
1353  
1354          $hdrfnd = 0;
1355          if ($this->debug) {
1356              print "\n<pre>---GOT---\n";
1357              print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
1358              print "\n---END---</pre>\n";
1359          }
1360  
1361          // See if response is a 200 or a 100 then a 200, else raise error.
1362          // But only do this if we're using the HTTP protocol.
1363          if (ereg('^HTTP', $data) &&
1364              !ereg('^HTTP/[0-9\.]+ 200 ', $data) &&
1365              !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data))
1366          {
1367                  $errstr = substr($data, 0, strpos($data, "\n") - 1);
1368                  error_log('HTTP error, got response: ' . $errstr);
1369                  $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'],
1370                                            $XML_RPC_str['http_error'] . ' (' .
1371                                            $errstr . ')');
1372                  xml_parser_free($parser_resource);
1373                  return $r;
1374          }
1375  
1376          // gotta get rid of headers here
1377          if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) {
1378              $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
1379              $data = substr($data, $brpos + 4);
1380              $hdrfnd = 1;
1381          }
1382  
1383          /*
1384           * be tolerant of junk after methodResponse
1385           * (e.g. javascript automatically inserted by free hosts)
1386           * thanks to Luca Mariano <luca.mariano@email.it>
1387           */
1388          $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
1389  
1390          if (!xml_parse($parser_resource, $data, sizeof($data))) {
1391              // thanks to Peter Kocks <peter.kocks@baygate.com>
1392              if (xml_get_current_line_number($parser_resource) == 1) {
1393                  $errstr = 'XML error at line 1, check URL';
1394              } else {
1395                  $errstr = sprintf('XML error: %s at line %d',
1396                                    xml_error_string(xml_get_error_code($parser_resource)),
1397                                    xml_get_current_line_number($parser_resource));
1398              }
1399              error_log($errstr);
1400              $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1401                                        $XML_RPC_str['invalid_return']);
1402              xml_parser_free($parser_resource);
1403              return $r;
1404          }
1405  
1406          xml_parser_free($parser_resource);
1407  
1408          if ($this->debug) {
1409              print "\n<pre>---PARSED---\n";
1410              var_dump($XML_RPC_xh[$parser]['value']);
1411              print "---END---</pre>\n";
1412          }
1413  
1414          if ($XML_RPC_xh[$parser]['isf'] > 1) {
1415              $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1416                                        $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']);
1417          } elseif (!is_object($XML_RPC_xh[$parser]['value'])) {
1418              // then something odd has happened
1419              // and it's time to generate a client side error
1420              // indicating something odd went on
1421              $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1422                                        $XML_RPC_str['invalid_return']);
1423          } else {
1424              $v = $XML_RPC_xh[$parser]['value'];
1425              $allOK=1;
1426              if ($XML_RPC_xh[$parser]['isf']) {
1427                  $f = $v->structmem('faultCode');
1428                  $fs = $v->structmem('faultString');
1429                  $r = new XML_RPC_Response($v, $f->scalarval(),
1430                                            $fs->scalarval());
1431              } else {
1432                  $r = new XML_RPC_Response($v);
1433              }
1434          }
1435          $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
1436          return $r;
1437      }
1438  }
1439  
1440  /**
1441   * The methods and properties that represent data in XML RPC format
1442   *
1443   * @category   Web Services
1444   * @package    XML_RPC
1445   * @author     Edd Dumbill <edd@usefulinc.com>
1446   * @author     Stig Bakken <stig@php.net>
1447   * @author     Martin Jansen <mj@php.net>
1448   * @author     Daniel Convissor <danielc@php.net>
1449   * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
1450   * @version    Release: 1.4.0
1451   * @link       http://pear.php.net/package/XML_RPC
1452   */
1453  class XML_RPC_Value extends XML_RPC_Base
1454  {
1455      var $me = array();
1456      var $mytype = 0;
1457  
1458      /**
1459       * @return void
1460       */
1461      function XML_RPC_Value($val = -1, $type = '')
1462      {
1463          global $XML_RPC_Types;
1464          $this->me = array();
1465          $this->mytype = 0;
1466          if ($val != -1 || $type != '') {
1467              if ($type == '') {
1468                  $type = 'string';
1469              }
1470              if (!array_key_exists($type, $XML_RPC_Types)) {
1471                  // XXX
1472                  // need some way to report this error
1473              } elseif ($XML_RPC_Types[$type] == 1) {
1474                  $this->addScalar($val, $type);
1475              } elseif ($XML_RPC_Types[$type] == 2) {
1476                  $this->addArray($val);
1477              } elseif ($XML_RPC_Types[$type] == 3) {
1478                  $this->addStruct($val);
1479              }
1480          }
1481      }
1482  
1483      /**
1484       * @return int  returns 1 if successful or 0 if there are problems
1485       */
1486      function addScalar($val, $type = 'string')
1487      {
1488          global $XML_RPC_Types, $XML_RPC_Boolean;
1489  
1490          if ($this->mytype == 1) {
1491              $this->raiseError('Scalar can have only one value',
1492                                XML_RPC_ERROR_INVALID_TYPE);
1493              return 0;
1494          }
1495          $typeof = $XML_RPC_Types[$type];
1496          if ($typeof != 1) {
1497              $this->raiseError("Not a scalar type ($typeof})",
1498                                XML_RPC_ERROR_INVALID_TYPE);
1499              return 0;
1500          }
1501  
1502          if ($type == $XML_RPC_Boolean) {
1503              if (strcasecmp($val, 'true') == 0
1504                  || $val == 1
1505                  || ($val == true && strcasecmp($val, 'false')))
1506              {
1507                  $val = 1;
1508              } else {
1509                  $val = 0;
1510              }
1511          }
1512  
1513          if ($this->mytype == 2) {
1514              // we're adding to an array here
1515              $ar = $this->me['array'];
1516              $ar[] = new XML_RPC_Value($val, $type);
1517              $this->me['array'] = $ar;
1518          } else {
1519              // a scalar, so set the value and remember we're scalar
1520              $this->me[$type] = $val;
1521              $this->mytype = $typeof;
1522          }
1523          return 1;
1524      }
1525  
1526      /**
1527       * @return int  returns 1 if successful or 0 if there are problems
1528       */
1529      function addArray($vals)
1530      {
1531          global $XML_RPC_Types;
1532          if ($this->mytype != 0) {
1533              $this->raiseError(
1534                      'Already initialized as a [' . $this->kindOf() . ']',
1535                      XML_RPC_ERROR_ALREADY_INITIALIZED);
1536              return 0;
1537          }
1538          $this->mytype = $XML_RPC_Types['array'];
1539          $this->me['array'] = $vals;
1540          return 1;
1541      }
1542  
1543      /**
1544       * @return int  returns 1 if successful or 0 if there are problems
1545       */
1546      function addStruct($vals)
1547      {
1548          global $XML_RPC_Types;
1549          if ($this->mytype != 0) {
1550              $this->raiseError(
1551                      'Already initialized as a [' . $this->kindOf() . ']',
1552                      XML_RPC_ERROR_ALREADY_INITIALIZED);
1553              return 0;
1554          }
1555          $this->mytype = $XML_RPC_Types['struct'];
1556          $this->me['struct'] = $vals;
1557          return 1;
1558      }
1559  
1560      /**
1561       * @return void
1562       */
1563      function dump($ar)
1564      {
1565          reset($ar);
1566          foreach ($ar as $key => $val) {
1567              echo "$key => $val<br />";
1568              if ($key == 'array') {
1569                  foreach ($val as $key2 => $val2) {
1570                      echo "-- $key2 => $val2<br />";
1571                  }
1572              }
1573          }
1574      }
1575  
1576      /**
1577       * @return string  the data type of the current value
1578       */
1579      function kindOf()
1580      {
1581          switch ($this->mytype) {
1582          case 3:
1583              return 'struct';
1584  
1585          case 2:
1586              return 'array';
1587  
1588          case 1:
1589              return 'scalar';
1590  
1591          default:
1592              return 'undef';
1593          }
1594      }
1595  
1596      /**
1597       * @return string  the data in XML format
1598       */
1599      function serializedata($typ, $val)
1600      {
1601          $rs = '';
1602          global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean;
1603          if (!array_key_exists($typ, $XML_RPC_Types)) {
1604              // XXX
1605              // need some way to report this error
1606              return;
1607          }
1608          switch ($XML_RPC_Types[$typ]) {
1609          case 3:
1610              // struct
1611              $rs .= "<struct>\n";
1612              reset($val);
1613              foreach ($val as $key2 => $val2) {
1614                  $rs .= "<member><name>$key2}</name>\n";
1615                  $rs .= $this->serializeval($val2);
1616                  $rs .= "</member>\n";
1617              }
1618              $rs .= '</struct>';
1619              break;
1620  
1621          case 2:
1622              // array
1623              $rs .= "<array>\n<data>\n";
1624              for ($i = 0; $i < sizeof($val); $i++) {
1625                  $rs .= $this->serializeval($val[$i]);
1626              }
1627              $rs .= "</data>\n</array>";
1628              break;
1629  
1630          case 1:
1631              switch ($typ) {
1632              case $XML_RPC_Base64:
1633                  $rs .= "<$typ}>" . base64_encode($val) . "</$typ}>";
1634                  break;
1635              case $XML_RPC_Boolean:
1636                  $rs .= "<$typ}>" . ($val ? '1' : '0') . "</$typ}>";
1637                  break;
1638              case $XML_RPC_String:
1639                  $rs .= "<$typ}>" . htmlspecialchars($val). "</$typ}>";
1640                  break;
1641              default:
1642                  $rs .= "<$typ}>$val}</$typ}>";
1643              }
1644          }
1645          return $rs;
1646      }
1647  
1648      /**
1649       * @return string  the data in XML format
1650       */
1651      function serialize()
1652      {
1653          return $this->serializeval($this);
1654      }
1655  
1656      /**
1657       * @return string  the data in XML format
1658       */
1659      function serializeval($o)
1660      {
1661          if (!is_object($o) || empty($o->me) || !is_array($o->me)) {
1662              return '';
1663          }
1664          $ar = $o->me;
1665          reset($ar);
1666          list($typ, $val) = each($ar);
1667          return '<value>' .  $this->serializedata($typ, $val) .  "</value>\n";
1668      }
1669  
1670      /**
1671       * @return mixed  the contents of the element requested
1672       */
1673      function structmem($m)
1674      {
1675          return $this->me['struct'][$m];
1676      }
1677  
1678      /**
1679       * @return void
1680       */
1681      function structreset()
1682      {
1683          reset($this->me['struct']);
1684      }
1685  
1686      /**
1687       * @return  the key/value pair of the struct's current element
1688       */
1689      function structeach()
1690      {
1691          return each($this->me['struct']);
1692      }
1693  
1694      /**
1695       * @return mixed  the current value
1696       */
1697      function getval()
1698      {
1699          // UNSTABLE
1700          global $XML_RPC_BOOLEAN, $XML_RPC_Base64;
1701  
1702          reset($this->me);
1703          $b = current($this->me);
1704  
1705          // contributed by I Sofer, 2001-03-24
1706          // add support for nested arrays to scalarval
1707          // i've created a new method here, so as to
1708          // preserve back compatibility
1709  
1710          if (is_array($b)) {
1711              foreach ($b as $id => $cont) {
1712                  $b[$id] = $cont->scalarval();
1713              }
1714          }
1715  
1716          // add support for structures directly encoding php objects
1717          if (is_object($b)) {
1718              $t = get_object_vars($b);
1719              foreach ($t as $id => $cont) {
1720                  $t[$id] = $cont->scalarval();
1721              }
1722              foreach ($t as $id => $cont) {
1723                  $b->$id = $cont;
1724              }
1725          }
1726  
1727          // end contrib
1728          return $b;
1729      }
1730  
1731      /**
1732       * @return mixed
1733       */
1734      function scalarval()
1735      {
1736          global $XML_RPC_Boolean, $XML_RPC_Base64;
1737          reset($this->me);
1738          return current($this->me);
1739      }
1740  
1741      /**
1742       * @return string
1743       */
1744      function scalartyp()
1745      {
1746          global $XML_RPC_I4, $XML_RPC_Int;
1747          reset($this->me);
1748          $a = key($this->me);
1749          if ($a == $XML_RPC_I4) {
1750              $a = $XML_RPC_Int;
1751          }
1752          return $a;
1753      }
1754  
1755      /**
1756       * @return mixed  the struct's current element
1757       */
1758      function arraymem($m)
1759      {
1760          return $this->me['array'][$m];
1761      }
1762  
1763      /**
1764       * @return int  the number of elements in the array
1765       */
1766      function arraysize()
1767      {
1768          reset($this->me);
1769          list($a, $b) = each($this->me);
1770          return sizeof($b);
1771      }
1772  
1773      /**
1774       * Determines if the item submitted is an XML_RPC_Value object
1775       *
1776       * @param mixed $val  the variable to be evaluated
1777       *
1778       * @return bool  TRUE if the item is an XML_RPC_Value object
1779       *
1780       * @static
1781       * @since Method available since Release 1.3.0
1782       */
1783      function isValue($val)
1784      {
1785          return (strtolower(get_class($val)) == 'xml_rpc_value');
1786      }
1787  }
1788  
1789  /**
1790   * Return an ISO8601 encoded string
1791   *
1792   * While timezones ought to be supported, the XML-RPC spec says:
1793   *
1794   * "Don't assume a timezone. It should be specified by the server in its
1795   * documentation what assumptions it makes about timezones."
1796   *
1797   * This routine always assumes localtime unless $utc is set to 1, in which
1798   * case UTC is assumed and an adjustment for locale is made when encoding.
1799   *
1800   * @return string  the formatted date
1801   */
1802  function XML_RPC_iso8601_encode($timet, $utc = 0)
1803  {
1804      if (!$utc) {
1805          $t = strftime('%Y%m%dT%H:%M:%S', $timet);
1806      } else {
1807          if (function_exists('gmstrftime')) {
1808              // gmstrftime doesn't exist in some versions
1809              // of PHP
1810              $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet);
1811          } else {
1812              $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z'));
1813          }
1814      }
1815      return $t;
1816  }
1817  
1818  /**
1819   * Convert a datetime string into a Unix timestamp
1820   *
1821   * While timezones ought to be supported, the XML-RPC spec says:
1822   *
1823   * "Don't assume a timezone. It should be specified by the server in its
1824   * documentation what assumptions it makes about timezones."
1825   *
1826   * This routine always assumes localtime unless $utc is set to 1, in which
1827   * case UTC is assumed and an adjustment for locale is made when encoding.
1828   *
1829   * @return int  the unix timestamp of the date submitted
1830   */
1831  function XML_RPC_iso8601_decode($idate, $utc = 0)
1832  {
1833      $t = 0;
1834      if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) {
1835          if ($utc) {
1836              $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1837          } else {
1838              $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1839          }
1840      }
1841      return $t;
1842  }
1843  
1844  /**
1845   * Converts an XML_RPC_Value object into native PHP types
1846   *
1847   * @param object $XML_RPC_val  the XML_RPC_Value object to decode
1848   *
1849   * @return mixed  the PHP values
1850   */
1851  function XML_RPC_decode($XML_RPC_val)
1852  {
1853      $kind = $XML_RPC_val->kindOf();
1854  
1855      if ($kind == 'scalar') {
1856          return $XML_RPC_val->scalarval();
1857  
1858      } elseif ($kind == 'array') {
1859          $size = $XML_RPC_val->arraysize();
1860          $arr = array();
1861          for ($i = 0; $i < $size; $i++) {
1862              $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i));
1863          }
1864          return $arr;
1865  
1866      } elseif ($kind == 'struct') {
1867          $XML_RPC_val->structreset();
1868          $arr = array();
1869          while (list($key, $value) = $XML_RPC_val->structeach()) {
1870              $arr[$key] = XML_RPC_decode($value);
1871          }
1872          return $arr;
1873      }
1874  }
1875  
1876  /**
1877   * Converts native PHP types into an XML_RPC_Value object
1878   *
1879   * @param mixed $php_val  the PHP value or variable you want encoded
1880   *
1881   * @return object  the XML_RPC_Value object
1882   */
1883  function XML_RPC_encode($php_val)
1884  {
1885      global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String,
1886             $XML_RPC_Array, $XML_RPC_Struct;
1887  
1888      $type = gettype($php_val);
1889      $XML_RPC_val = new XML_RPC_Value;
1890  
1891      switch ($type) {
1892      case 'array':
1893          if (empty($php_val)) {
1894              $XML_RPC_val->addArray($php_val);
1895              break;
1896          }
1897          $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
1898          if (empty($tmp)) {
1899             $arr = array();
1900             foreach ($php_val as $k => $v) {
1901                 $arr[$k] = XML_RPC_encode($v);
1902             }
1903             $XML_RPC_val->addArray($arr);
1904             break;
1905          }
1906          // fall though if it's not an enumerated array
1907  
1908      case 'object':
1909          $arr = array();
1910          foreach ($php_val as $k => $v) {
1911              $arr[$k] = XML_RPC_encode($v);
1912          }
1913          $XML_RPC_val->addStruct($arr);
1914          break;
1915  
1916      case 'integer':
1917          $XML_RPC_val->addScalar($php_val, $XML_RPC_Int);
1918          break;
1919  
1920      case 'double':
1921          $XML_RPC_val->addScalar($php_val, $XML_RPC_Double);
1922          break;
1923  
1924      case 'string':
1925      case 'NULL':
1926          $XML_RPC_val->addScalar($php_val, $XML_RPC_String);
1927          break;
1928  
1929      case 'boolean':
1930          // Add support for encoding/decoding of booleans, since they
1931          // are supported in PHP
1932          // by <G_Giunta_2001-02-29>
1933          $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean);
1934          break;
1935  
1936      case 'unknown type':
1937      default:
1938          $XML_RPC_val = false;
1939      }
1940      return $XML_RPC_val;
1941  }
1942  
1943  /*
1944   * Local variables:
1945   * tab-width: 4
1946   * c-basic-offset: 4
1947   * c-hanging-comment-ender-p: nil
1948   * End:
1949   */
1950  
1951  ?>


Généré le : Sat Nov 24 09:00:37 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics