home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / XML / RPC.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  59.7 KB  |  2,078 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-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. ?>
  2078.