[ Index ]
 

Code source de PHP PEAR 1.4.5

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

title

Body

[fermer]

/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.101 2006/10/28 16:42:34 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.1
 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.1
 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.1
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.1
1161   * @link       http://pear.php.net/package/XML_RPC
1162   */
1163  class XML_RPC_Message extends XML_RPC_Base
1164  {
1165      /**
1166       * Should the payload's content be passed through mb_convert_encoding()?
1167       *
1168       * @see XML_RPC_Message::setConvertPayloadEncoding()
1169       * @since Property available since Release 1.5.1
1170       * @var boolean
1171       */
1172      var $convert_payload_encoding = false;
1173  
1174      /**
1175       * The current debug mode (1 = on, 0 = off)
1176       * @var integer
1177       */
1178      var $debug = 0;
1179  
1180      /**
1181       * The encoding to be used for outgoing messages
1182       *
1183       * Defaults to the value of <var>$GLOBALS['XML_RPC_defencoding']</var>
1184       *
1185       * @var string
1186       * @see XML_RPC_Message::setSendEncoding(),
1187       *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
1188       */
1189      var $send_encoding = '';
1190  
1191      /**
1192       * The method presently being evaluated
1193       * @var string
1194       */
1195      var $methodname = '';
1196  
1197      /**
1198       * @var array
1199       */
1200      var $params = array();
1201  
1202      /**
1203       * The XML message being generated
1204       * @var string
1205       */
1206      var $payload = '';
1207  
1208      /**
1209       * Should extra line breaks be removed from the payload?
1210       * @since Property available since Release 1.4.6
1211       * @var boolean
1212       */
1213      var $remove_extra_lines = true;
1214  
1215      /**
1216       * The XML response from the remote server
1217       * @since Property available since Release 1.4.6
1218       * @var string
1219       */
1220      var $response_payload = '';
1221  
1222  
1223      /**
1224       * @return void
1225       */
1226      function XML_RPC_Message($meth, $pars = 0)
1227      {
1228          $this->methodname = $meth;
1229          if (is_array($pars) && sizeof($pars) > 0) {
1230              for ($i = 0; $i < sizeof($pars); $i++) {
1231                  $this->addParam($pars[$i]);
1232              }
1233          }
1234      }
1235  
1236      /**
1237       * Produces the XML declaration including the encoding attribute
1238       *
1239       * The encoding is determined by this class' <var>$send_encoding</var>
1240       * property.  If the <var>$send_encoding</var> property is not set, use
1241       * <var>$GLOBALS['XML_RPC_defencoding']</var>.
1242       *
1243       * @return string  the XML declaration and <methodCall> element
1244       *
1245       * @see XML_RPC_Message::setSendEncoding(),
1246       *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
1247       */
1248      function xml_header()
1249      {
1250          global $XML_RPC_defencoding;
1251  
1252          if (!$this->send_encoding) {
1253              $this->send_encoding = $XML_RPC_defencoding;
1254          }
1255          return '<?xml version="1.0" encoding="' . $this->send_encoding . '"?>'
1256                 . "\n<methodCall>\n";
1257      }
1258  
1259      /**
1260       * @return string  the closing </methodCall> tag
1261       */
1262      function xml_footer()
1263      {
1264          return "</methodCall>\n";
1265      }
1266  
1267      /**
1268       * Fills the XML_RPC_Message::$payload property
1269       *
1270       * Part of the process makes sure all line endings are in DOS format
1271       * (CRLF), which is probably required by specifications.
1272       *
1273       * If XML_RPC_Message::setConvertPayloadEncoding() was set to true,
1274       * the payload gets passed through mb_convert_encoding()
1275       * to ensure the payload matches the encoding set in the
1276       * XML declaration.  The encoding type can be manually set via
1277       * XML_RPC_Message::setSendEncoding().
1278       *
1279       * @return void
1280       *
1281       * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
1282       * @see XML_RPC_Message::setSendEncoding(), $GLOBALS['XML_RPC_defencoding'],
1283       *      XML_RPC_Message::setConvertPayloadEncoding()
1284       */
1285      function createPayload()
1286      {
1287          $this->payload = $this->xml_header();
1288          $this->payload .= '<methodName>' . $this->methodname . "</methodName>\n";
1289          $this->payload .= "<params>\n";
1290          for ($i = 0; $i < sizeof($this->params); $i++) {
1291              $p = $this->params[$i];
1292              $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
1293          }
1294          $this->payload .= "</params>\n";
1295          $this->payload .= $this->xml_footer();
1296          if ($this->remove_extra_lines) {
1297              $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("[\r\n]+", "\r\n", $this->payload);
1298          } else {
1299              $this->payload = $GLOBALS['XML_RPC_func_ereg_replace']("\r\n|\n|\r|\n\r", "\r\n", $this->payload);
1300          }
1301          if ($this->convert_payload_encoding) {
1302              $this->payload = mb_convert_encoding($this->payload, $this->send_encoding);
1303          }
1304      }
1305  
1306      /**
1307       * @return string  the name of the method
1308       */
1309      function method($meth = '')
1310      {
1311          if ($meth != '') {
1312              $this->methodname = $meth;
1313          }
1314          return $this->methodname;
1315      }
1316  
1317      /**
1318       * @return string  the payload
1319       */
1320      function serialize()
1321      {
1322          $this->createPayload();
1323          return $this->payload;
1324      }
1325  
1326      /**
1327       * @return void
1328       */
1329      function addParam($par)
1330      {
1331          $this->params[] = $par;
1332      }
1333  
1334      /**
1335       * Obtains an XML_RPC_Value object for the given parameter
1336       *
1337       * @param int $i  the index number of the parameter to obtain
1338       *
1339       * @return object  the XML_RPC_Value object.
1340       *                  If the parameter doesn't exist, an XML_RPC_Response object.
1341       *
1342       * @since Returns XML_RPC_Response object on error since Release 1.3.0
1343       */
1344      function getParam($i)
1345      {
1346          global $XML_RPC_err, $XML_RPC_str;
1347  
1348          if (isset($this->params[$i])) {
1349              return $this->params[$i];
1350          } else {
1351              $this->raiseError('The submitted request did not contain this parameter',
1352                                XML_RPC_ERROR_INCORRECT_PARAMS);
1353              return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
1354                                          $XML_RPC_str['incorrect_params']);
1355          }
1356      }
1357  
1358      /**
1359       * @return int  the number of parameters
1360       */
1361      function getNumParams()
1362      {
1363          return sizeof($this->params);
1364      }
1365  
1366      /**
1367       * Sets whether the payload's content gets passed through
1368       * mb_convert_encoding()
1369       *
1370       * Returns PEAR_ERROR object if mb_convert_encoding() isn't available.
1371       *
1372       * @param int $in  where 1 = on, 0 = off
1373       *
1374       * @return void
1375       *
1376       * @see XML_RPC_Message::setSendEncoding()
1377       * @since Method available since Release 1.5.1
1378       */
1379      function setConvertPayloadEncoding($in)
1380      {
1381          if ($in && !function_exists('mb_convert_encoding')) {
1382              return $this->raiseError('mb_convert_encoding() is not available',
1383                                XML_RPC_ERROR_PROGRAMMING);
1384          }
1385          $this->convert_payload_encoding = $in;
1386      }
1387  
1388      /**
1389       * Sets the XML declaration's encoding attribute
1390       *
1391       * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
1392       *
1393       * @return void
1394       *
1395       * @see XML_RPC_Message::setConvertPayloadEncoding(), XML_RPC_Message::xml_header()
1396       * @since Method available since Release 1.2.0
1397       */
1398      function setSendEncoding($type)
1399      {
1400          $this->send_encoding = $type;
1401      }
1402  
1403      /**
1404       * Determine the XML's encoding via the encoding attribute
1405       * in the XML declaration
1406       *
1407       * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
1408       * or US-ASCII, $XML_RPC_defencoding will be returned.
1409       *
1410       * @param string $data  the XML that will be parsed
1411       *
1412       * @return string  the encoding to be used
1413       *
1414       * @link   http://php.net/xml_parser_create
1415       * @since  Method available since Release 1.2.0
1416       */
1417      function getEncoding($data)
1418      {
1419          global $XML_RPC_defencoding;
1420  
1421          if ($GLOBALS['XML_RPC_func_ereg']('<\?xml[^>]*[:space:]*encoding[:space:]*=[:space:]*[\'"]([^"\']*)[\'"]',
1422                         $data, $match))
1423          {
1424              $match[1] = trim(strtoupper($match[1]));
1425              switch ($match[1]) {
1426                  case 'ISO-8859-1':
1427                  case 'UTF-8':
1428                  case 'US-ASCII':
1429                      return $match[1];
1430                      break;
1431  
1432                  default:
1433                      return $XML_RPC_defencoding;
1434              }
1435          } else {
1436              return $XML_RPC_defencoding;
1437          }
1438      }
1439  
1440      /**
1441       * @return object  a new XML_RPC_Response object
1442       */
1443      function parseResponseFile($fp)
1444      {
1445          $ipd = '';
1446          while ($data = @fread($fp, 8192)) {
1447              $ipd .= $data;
1448          }
1449          return $this->parseResponse($ipd);
1450      }
1451  
1452      /**
1453       * @return object  a new XML_RPC_Response object
1454       */
1455      function parseResponse($data = '')
1456      {
1457          global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
1458  
1459          $encoding = $this->getEncoding($data);
1460          $parser_resource = xml_parser_create($encoding);
1461          $parser = (int) $parser_resource;
1462  
1463          $XML_RPC_xh = array();
1464          $XML_RPC_xh[$parser] = array();
1465  
1466          $XML_RPC_xh[$parser]['cm'] = 0;
1467          $XML_RPC_xh[$parser]['isf'] = 0;
1468          $XML_RPC_xh[$parser]['ac'] = '';
1469          $XML_RPC_xh[$parser]['qt'] = '';
1470          $XML_RPC_xh[$parser]['stack'] = array();
1471          $XML_RPC_xh[$parser]['valuestack'] = array();
1472  
1473          xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
1474          xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
1475          xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
1476  
1477          $hdrfnd = 0;
1478          if ($this->debug) {
1479              print "\n<pre>---GOT---\n";
1480              print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
1481              print "\n---END---</pre>\n";
1482          }
1483  
1484          // See if response is a 200 or a 100 then a 200, else raise error.
1485          // But only do this if we're using the HTTP protocol.
1486          if ($GLOBALS['XML_RPC_func_ereg']('^HTTP', $data) &&
1487              !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 200 ', $data) &&
1488              !$GLOBALS['XML_RPC_func_ereg']('^HTTP/[0-9\.]+ 10[0-9]([A-Z ]+)?[\r\n]+HTTP/[0-9\.]+ 200', $data))
1489          {
1490                  $errstr = substr($data, 0, strpos($data, "\n") - 1);
1491                  error_log('HTTP error, got response: ' . $errstr);
1492                  $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'],
1493                                            $XML_RPC_str['http_error'] . ' (' .
1494                                            $errstr . ')');
1495                  xml_parser_free($parser_resource);
1496                  return $r;
1497          }
1498  
1499          // gotta get rid of headers here
1500          if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) {
1501              $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
1502              $data = substr($data, $brpos + 4);
1503              $hdrfnd = 1;
1504          }
1505  
1506          /*
1507           * be tolerant of junk after methodResponse
1508           * (e.g. javascript automatically inserted by free hosts)
1509           * thanks to Luca Mariano <luca.mariano@email.it>
1510           */
1511          $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
1512          $this->response_payload = $data;
1513  
1514          if (!xml_parse($parser_resource, $data, sizeof($data))) {
1515              // thanks to Peter Kocks <peter.kocks@baygate.com>
1516              if (xml_get_current_line_number($parser_resource) == 1) {
1517                  $errstr = 'XML error at line 1, check URL';
1518              } else {
1519                  $errstr = sprintf('XML error: %s at line %d',
1520                                    xml_error_string(xml_get_error_code($parser_resource)),
1521                                    xml_get_current_line_number($parser_resource));
1522              }
1523              error_log($errstr);
1524              $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1525                                        $XML_RPC_str['invalid_return']);
1526              xml_parser_free($parser_resource);
1527              return $r;
1528          }
1529  
1530          xml_parser_free($parser_resource);
1531  
1532          if ($this->debug) {
1533              print "\n<pre>---PARSED---\n";
1534              var_dump($XML_RPC_xh[$parser]['value']);
1535              print "---END---</pre>\n";
1536          }
1537  
1538          if ($XML_RPC_xh[$parser]['isf'] > 1) {
1539              $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1540                                        $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']);
1541          } elseif (!is_object($XML_RPC_xh[$parser]['value'])) {
1542              // then something odd has happened
1543              // and it's time to generate a client side error
1544              // indicating something odd went on
1545              $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'],
1546                                        $XML_RPC_str['invalid_return']);
1547          } else {
1548              $v = $XML_RPC_xh[$parser]['value'];
1549              if ($XML_RPC_xh[$parser]['isf']) {
1550                  $f = $v->structmem('faultCode');
1551                  $fs = $v->structmem('faultString');
1552                  $r = new XML_RPC_Response($v, $f->scalarval(),
1553                                            $fs->scalarval());
1554              } else {
1555                  $r = new XML_RPC_Response($v);
1556              }
1557          }
1558          $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
1559          return $r;
1560      }
1561  }
1562  
1563  /**
1564   * The methods and properties that represent data in XML RPC format
1565   *
1566   * @category   Web Services
1567   * @package    XML_RPC
1568   * @author     Edd Dumbill <edd@usefulinc.com>
1569   * @author     Stig Bakken <stig@php.net>
1570   * @author     Martin Jansen <mj@php.net>
1571   * @author     Daniel Convissor <danielc@php.net>
1572   * @copyright  1999-2001 Edd Dumbill, 2001-2006 The PHP Group
1573   * @version    Release: 1.5.1
1574   * @link       http://pear.php.net/package/XML_RPC
1575   */
1576  class XML_RPC_Value extends XML_RPC_Base
1577  {
1578      var $me = array();
1579      var $mytype = 0;
1580  
1581      /**
1582       * @return void
1583       */
1584      function XML_RPC_Value($val = -1, $type = '')
1585      {
1586          $this->me = array();
1587          $this->mytype = 0;
1588          if ($val != -1 || $type != '') {
1589              if ($type == '') {
1590                  $type = 'string';
1591              }
1592              if (!array_key_exists($type, $GLOBALS['XML_RPC_Types'])) {
1593                  // XXX
1594                  // need some way to report this error
1595              } elseif ($GLOBALS['XML_RPC_Types'][$type] == 1) {
1596                  $this->addScalar($val, $type);
1597              } elseif ($GLOBALS['XML_RPC_Types'][$type] == 2) {
1598                  $this->addArray($val);
1599              } elseif ($GLOBALS['XML_RPC_Types'][$type] == 3) {
1600                  $this->addStruct($val);
1601              }
1602          }
1603      }
1604  
1605      /**
1606       * @return int  returns 1 if successful or 0 if there are problems
1607       */
1608      function addScalar($val, $type = 'string')
1609      {
1610          if ($this->mytype == 1) {
1611              $this->raiseError('Scalar can have only one value',
1612                                XML_RPC_ERROR_INVALID_TYPE);
1613              return 0;
1614          }
1615          $typeof = $GLOBALS['XML_RPC_Types'][$type];
1616          if ($typeof != 1) {
1617              $this->raiseError("Not a scalar type ($typeof})",
1618                                XML_RPC_ERROR_INVALID_TYPE);
1619              return 0;
1620          }
1621  
1622          if ($type == $GLOBALS['XML_RPC_Boolean']) {
1623              if (strcasecmp($val, 'true') == 0
1624                  || $val == 1
1625                  || ($val == true && strcasecmp($val, 'false')))
1626              {
1627                  $val = 1;
1628              } else {
1629                  $val = 0;
1630              }
1631          }
1632  
1633          if ($this->mytype == 2) {
1634              // we're adding to an array here
1635              $ar = $this->me['array'];
1636              $ar[] = new XML_RPC_Value($val, $type);
1637              $this->me['array'] = $ar;
1638          } else {
1639              // a scalar, so set the value and remember we're scalar
1640              $this->me[$type] = $val;
1641              $this->mytype = $typeof;
1642          }
1643          return 1;
1644      }
1645  
1646      /**
1647       * @return int  returns 1 if successful or 0 if there are problems
1648       */
1649      function addArray($vals)
1650      {
1651          if ($this->mytype != 0) {
1652              $this->raiseError(
1653                      'Already initialized as a [' . $this->kindOf() . ']',
1654                      XML_RPC_ERROR_ALREADY_INITIALIZED);
1655              return 0;
1656          }
1657          $this->mytype = $GLOBALS['XML_RPC_Types']['array'];
1658          $this->me['array'] = $vals;
1659          return 1;
1660      }
1661  
1662      /**
1663       * @return int  returns 1 if successful or 0 if there are problems
1664       */
1665      function addStruct($vals)
1666      {
1667          if ($this->mytype != 0) {
1668              $this->raiseError(
1669                      'Already initialized as a [' . $this->kindOf() . ']',
1670                      XML_RPC_ERROR_ALREADY_INITIALIZED);
1671              return 0;
1672          }
1673          $this->mytype = $GLOBALS['XML_RPC_Types']['struct'];
1674          $this->me['struct'] = $vals;
1675          return 1;
1676      }
1677  
1678      /**
1679       * @return void
1680       */
1681      function dump($ar)
1682      {
1683          reset($ar);
1684          foreach ($ar as $key => $val) {
1685              echo "$key => $val<br />";
1686              if ($key == 'array') {
1687                  foreach ($val as $key2 => $val2) {
1688                      echo "-- $key2 => $val2<br />";
1689                  }
1690              }
1691          }
1692      }
1693  
1694      /**
1695       * @return string  the data type of the current value
1696       */
1697      function kindOf()
1698      {
1699          switch ($this->mytype) {
1700          case 3:
1701              return 'struct';
1702  
1703          case 2:
1704              return 'array';
1705  
1706          case 1:
1707              return 'scalar';
1708  
1709          default:
1710              return 'undef';
1711          }
1712      }
1713  
1714      /**
1715       * @return string  the data in XML format
1716       */
1717      function serializedata($typ, $val)
1718      {
1719          $rs = '';
1720          if (!array_key_exists($typ, $GLOBALS['XML_RPC_Types'])) {
1721              // XXX
1722              // need some way to report this error
1723              return;
1724          }
1725          switch ($GLOBALS['XML_RPC_Types'][$typ]) {
1726          case 3:
1727              // struct
1728              $rs .= "<struct>\n";
1729              reset($val);
1730              foreach ($val as $key2 => $val2) {
1731                  $rs .= "<member><name>$key2}</name>\n";
1732                  $rs .= $this->serializeval($val2);
1733                  $rs .= "</member>\n";
1734              }
1735              $rs .= '</struct>';
1736              break;
1737  
1738          case 2:
1739              // array
1740              $rs .= "<array>\n<data>\n";
1741              for ($i = 0; $i < sizeof($val); $i++) {
1742                  $rs .= $this->serializeval($val[$i]);
1743              }
1744              $rs .= "</data>\n</array>";
1745              break;
1746  
1747          case 1:
1748              switch ($typ) {
1749              case $GLOBALS['XML_RPC_Base64']:
1750                  $rs .= "<$typ}>" . base64_encode($val) . "</$typ}>";
1751                  break;
1752              case $GLOBALS['XML_RPC_Boolean']:
1753                  $rs .= "<$typ}>" . ($val ? '1' : '0') . "</$typ}>";
1754                  break;
1755              case $GLOBALS['XML_RPC_String']:
1756                  $rs .= "<$typ}>" . htmlspecialchars($val). "</$typ}>";
1757                  break;
1758              default:
1759                  $rs .= "<$typ}>$val}</$typ}>";
1760              }
1761          }
1762          return $rs;
1763      }
1764  
1765      /**
1766       * @return string  the data in XML format
1767       */
1768      function serialize()
1769      {
1770          return $this->serializeval($this);
1771      }
1772  
1773      /**
1774       * @return string  the data in XML format
1775       */
1776      function serializeval($o)
1777      {
1778          if (!is_object($o) || empty($o->me) || !is_array($o->me)) {
1779              return '';
1780          }
1781          $ar = $o->me;
1782          reset($ar);
1783          list($typ, $val) = each($ar);
1784          return '<value>' .  $this->serializedata($typ, $val) .  "</value>\n";
1785      }
1786  
1787      /**
1788       * @return mixed  the contents of the element requested
1789       */
1790      function structmem($m)
1791      {
1792          return $this->me['struct'][$m];
1793      }
1794  
1795      /**
1796       * @return void
1797       */
1798      function structreset()
1799      {
1800          reset($this->me['struct']);
1801      }
1802  
1803      /**
1804       * @return  the key/value pair of the struct's current element
1805       */
1806      function structeach()
1807      {
1808          return each($this->me['struct']);
1809      }
1810  
1811      /**
1812       * @return mixed  the current value
1813       */
1814      function getval()
1815      {
1816          // UNSTABLE
1817  
1818          reset($this->me);
1819          $b = current($this->me);
1820  
1821          // contributed by I Sofer, 2001-03-24
1822          // add support for nested arrays to scalarval
1823          // i've created a new method here, so as to
1824          // preserve back compatibility
1825  
1826          if (is_array($b)) {
1827              foreach ($b as $id => $cont) {
1828                  $b[$id] = $cont->scalarval();
1829              }
1830          }
1831  
1832          // add support for structures directly encoding php objects
1833          if (is_object($b)) {
1834              $t = get_object_vars($b);
1835              foreach ($t as $id => $cont) {
1836                  $t[$id] = $cont->scalarval();
1837              }
1838              foreach ($t as $id => $cont) {
1839                  $b->$id = $cont;
1840              }
1841          }
1842  
1843          // end contrib
1844          return $b;
1845      }
1846  
1847      /**
1848       * @return mixed  the current element's scalar value.  If the value is
1849       *                 not scalar, FALSE is returned.
1850       */
1851      function scalarval()
1852      {
1853          reset($this->me);
1854          $v = current($this->me);
1855          if (!is_scalar($v)) {
1856              $v = false;
1857          }
1858          return $v;
1859      }
1860  
1861      /**
1862       * @return string
1863       */
1864      function scalartyp()
1865      {
1866          reset($this->me);
1867          $a = key($this->me);
1868          if ($a == $GLOBALS['XML_RPC_I4']) {
1869              $a = $GLOBALS['XML_RPC_Int'];
1870          }
1871          return $a;
1872      }
1873  
1874      /**
1875       * @return mixed  the struct's current element
1876       */
1877      function arraymem($m)
1878      {
1879          return $this->me['array'][$m];
1880      }
1881  
1882      /**
1883       * @return int  the number of elements in the array
1884       */
1885      function arraysize()
1886      {
1887          reset($this->me);
1888          list($a, $b) = each($this->me);
1889          return sizeof($b);
1890      }
1891  
1892      /**
1893       * Determines if the item submitted is an XML_RPC_Value object
1894       *
1895       * @param mixed $val  the variable to be evaluated
1896       *
1897       * @return bool  TRUE if the item is an XML_RPC_Value object
1898       *
1899       * @static
1900       * @since Method available since Release 1.3.0
1901       */
1902      function isValue($val)
1903      {
1904          return (strtolower(get_class($val)) == 'xml_rpc_value');
1905      }
1906  }
1907  
1908  /**
1909   * Return an ISO8601 encoded string
1910   *
1911   * While timezones ought to be supported, the XML-RPC spec says:
1912   *
1913   * "Don't assume a timezone. It should be specified by the server in its
1914   * documentation what assumptions it makes about timezones."
1915   *
1916   * This routine always assumes localtime unless $utc is set to 1, in which
1917   * case UTC is assumed and an adjustment for locale is made when encoding.
1918   *
1919   * @return string  the formatted date
1920   */
1921  function XML_RPC_iso8601_encode($timet, $utc = 0)
1922  {
1923      if (!$utc) {
1924          $t = strftime('%Y%m%dT%H:%M:%S', $timet);
1925      } else {
1926          if (function_exists('gmstrftime')) {
1927              // gmstrftime doesn't exist in some versions
1928              // of PHP
1929              $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet);
1930          } else {
1931              $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z'));
1932          }
1933      }
1934      return $t;
1935  }
1936  
1937  /**
1938   * Convert a datetime string into a Unix timestamp
1939   *
1940   * While timezones ought to be supported, the XML-RPC spec says:
1941   *
1942   * "Don't assume a timezone. It should be specified by the server in its
1943   * documentation what assumptions it makes about timezones."
1944   *
1945   * This routine always assumes localtime unless $utc is set to 1, in which
1946   * case UTC is assumed and an adjustment for locale is made when encoding.
1947   *
1948   * @return int  the unix timestamp of the date submitted
1949   */
1950  function XML_RPC_iso8601_decode($idate, $utc = 0)
1951  {
1952      $t = 0;
1953      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)) {
1954          if ($utc) {
1955              $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1956          } else {
1957              $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1958          }
1959      }
1960      return $t;
1961  }
1962  
1963  /**
1964   * Converts an XML_RPC_Value object into native PHP types
1965   *
1966   * @param object $XML_RPC_val  the XML_RPC_Value object to decode
1967   *
1968   * @return mixed  the PHP values
1969   */
1970  function XML_RPC_decode($XML_RPC_val)
1971  {
1972      $kind = $XML_RPC_val->kindOf();
1973  
1974      if ($kind == 'scalar') {
1975          return $XML_RPC_val->scalarval();
1976  
1977      } elseif ($kind == 'array') {
1978          $size = $XML_RPC_val->arraysize();
1979          $arr = array();
1980          for ($i = 0; $i < $size; $i++) {
1981              $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i));
1982          }
1983          return $arr;
1984  
1985      } elseif ($kind == 'struct') {
1986          $XML_RPC_val->structreset();
1987          $arr = array();
1988          while (list($key, $value) = $XML_RPC_val->structeach()) {
1989              $arr[$key] = XML_RPC_decode($value);
1990          }
1991          return $arr;
1992      }
1993  }
1994  
1995  /**
1996   * Converts native PHP types into an XML_RPC_Value object
1997   *
1998   * @param mixed $php_val  the PHP value or variable you want encoded
1999   *
2000   * @return object  the XML_RPC_Value object
2001   */
2002  function XML_RPC_encode($php_val)
2003  {
2004      $type = gettype($php_val);
2005      $XML_RPC_val = new XML_RPC_Value;
2006  
2007      switch ($type) {
2008      case 'array':
2009          if (empty($php_val)) {
2010              $XML_RPC_val->addArray($php_val);
2011              break;
2012          }
2013          $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
2014          if (empty($tmp)) {
2015             $arr = array();
2016             foreach ($php_val as $k => $v) {
2017                 $arr[$k] = XML_RPC_encode($v);
2018             }
2019             $XML_RPC_val->addArray($arr);
2020             break;
2021          }
2022          // fall though if it's not an enumerated array
2023  
2024      case 'object':
2025          $arr = array();
2026          foreach ($php_val as $k => $v) {
2027              $arr[$k] = XML_RPC_encode($v);
2028          }
2029          $XML_RPC_val->addStruct($arr);
2030          break;
2031  
2032      case 'integer':
2033          $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Int']);
2034          break;
2035  
2036      case 'double':
2037          $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Double']);
2038          break;
2039  
2040      case 'string':
2041      case 'NULL':
2042          if ($GLOBALS['XML_RPC_func_ereg']('^[0-9]{8}\T{1}[0-9]{2}\:[0-9]{2}\:[0-9]{2}$', $php_val)) {
2043              $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_DateTime']);
2044          } elseif ($GLOBALS['XML_RPC_auto_base64']
2045                    && $GLOBALS['XML_RPC_func_ereg']("[^ -~\t\r\n]", $php_val))
2046          {
2047              // Characters other than alpha-numeric, punctuation, SP, TAB,
2048              // LF and CR break the XML parser, encode value via Base 64.
2049              $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Base64']);
2050          } else {
2051              $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_String']);
2052          }
2053          break;
2054  
2055      case 'boolean':
2056          // Add support for encoding/decoding of booleans, since they
2057          // are supported in PHP
2058          // by <G_Giunta_2001-02-29>
2059          $XML_RPC_val->addScalar($php_val, $GLOBALS['XML_RPC_Boolean']);
2060          break;
2061  
2062      case 'unknown type':
2063      default:
2064          $XML_RPC_val = false;
2065      }
2066      return $XML_RPC_val;
2067  }
2068  
2069  /*
2070   * Local variables:
2071   * tab-width: 4
2072   * c-basic-offset: 4
2073   * c-hanging-comment-ender-p: nil
2074   * End:
2075   */
2076  
2077  ?>


Généré le : Sun Feb 25 14:08:00 2007 par Balluche grâce à PHPXref 0.7