[ Index ]
 

Code source de phpMyVisites 2.3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

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


Généré le : Mon Nov 26 14:10:01 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics