XML_RPC
[ class tree: XML_RPC ] [ index: XML_RPC ] [ all elements ]

Source for file RPC.php

Documentation is available at RPC.php

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

Documentation generated on Tue, 18 Aug 2009 17:30:04 +0000 by phpDocumentor 1.4.2. PEAR Logo Copyright © PHP Group 2004.