home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / XML / RPC.php < prev    next >
Encoding:
PHP Script  |  2006-04-07  |  55.5 KB  |  1,959 lines

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