home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / phptriad / phptriadsetup2-11.exe / php / pear / XML / RPC.php < prev   
PHP Script  |  2000-09-26  |  22KB  |  828 lines

  1. <?php
  2.   require_once "XML/Parser.php";
  3.  
  4. //
  5. // This file contains PEAR-ifications of XML-RPC code written by Edd
  6. // Dumbill.
  7. //
  8. // by Edd Dumbill (C) 1999-2000
  9. // <edd@usefulinc.com>
  10. // $Id: RPC.php,v 1.2 2000/09/26 07:33:19 sbergmann Exp $
  11.  
  12. // License is granted to use or modify this software ("XML-RPC for PHP")
  13. // for commercial or non-commercial use provided the copyright of the author
  14. // is preserved in any distributed or derivative work.
  15.  
  16. // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  17. // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
  22. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  
  27. if (!function_exists('xml_parser_create')) {
  28. // Win 32 fix. From: "Leo West" <lwest@imaginet.fr>
  29.     if($WINDIR) {
  30.         dl("php3_xml.dll");
  31.     } else {
  32.         dl("xml.so");
  33.     }
  34. }
  35.  
  36. $XML_RPC_I4="i4";
  37. $XML_RPC_Int="int";
  38. $XML_RPC_Boolean="boolean";
  39. $XML_RPC_Double="double";
  40. $XML_RPC_String="string";
  41. $XML_RPC_DateTime="dateTime.iso8601";
  42. $XML_RPC_Base64="base64";
  43. $XML_RPC_Array="array";
  44. $XML_RPC_Struct="struct";
  45.  
  46. $XML_RPC_Types=array($XML_RPC_I4 => 1,
  47.                    $XML_RPC_Int => 1,
  48.                    $XML_RPC_Boolean => 1,
  49.                    $XML_RPC_String => 1,
  50.                    $XML_RPC_Double => 1,
  51.                    $XML_RPC_DateTime => 1,
  52.                    $XML_RPC_Base64 => 1,
  53.                    $XML_RPC_Array => 2,
  54.                    $XML_RPC_Struct => 3);
  55.  
  56. $XML_RPC_Entities=array("quot" => '"',
  57.                    "amp" => "&",
  58.                    "lt" => "<",
  59.                    "gt" => ">",
  60.                    "apos" => "'");
  61.  
  62. $XML_RPC_err["unknown_method"]=1;
  63. $XML_RPC_str["unknown_method"]="Unknown method";
  64. $XML_RPC_err["invalid_return"]=2;
  65. $XML_RPC_str["invalid_return"]="Invalid return payload: enabling debugging to examine incoming payload";
  66. $XML_RPC_err["incorrect_params"]=3;
  67. $XML_RPC_str["incorrect_params"]="Incorrect parameters passed to method";
  68. $XML_RPC_err["introspect_unknown"]=4;
  69. $XML_RPC_str["introspect_unknown"]="Can't introspect: method unknown";
  70. $XML_RPC_err["http_error"]=5;
  71. $XML_RPC_str["http_error"]="Didn't receive 200 OK from remote server.";
  72.  
  73. $XML_RPC_defencoding="UTF-8";
  74.  
  75. // let user errors start at 800
  76. $XML_RPC_erruser=800; 
  77. // let XML parse errors start at 100
  78. $XML_RPC_errxml=100;
  79.  
  80. // formulate backslashes for escaping regexp
  81. $XML_RPC_backslash=chr(92).chr(92);
  82.  
  83. $XML_RPC_twoslash=$XML_RPC_backslash . $XML_RPC_backslash;
  84. $XML_RPC_twoslash="2SLS";
  85. // used to store state during parsing
  86. // quick explanation of components:
  87. //   st - used to build up a string for evaluation
  88. //   ac - used to accumulate values
  89. //   qt - used to decide if quotes are needed for evaluation
  90. //   cm - used to denote struct or array (comma needed)
  91. //   isf - used to indicate a fault
  92. //   lv - used to indicate "looking for a value": implements
  93. //        the logic to allow values with no types to be strings
  94. //   params - used to store parameters in method calls
  95. //   method - used to store method name
  96.  
  97. $_xh=array();
  98.  
  99.  
  100. class XML_RPC_Parser extends XML_Parser {
  101.     var $st;  /* used to build up a string for evaluation */
  102.     var $ac;  /* used to accumulate values */
  103.     var $qt;  /* used to decide if quotes are needed for evaluation */
  104.     var $cm;  /* used to denote struct or array (comma needed) */
  105.     var $isf; /* used to indicate a fault */
  106.     var $lv;  /* used to indicate "looking for a vlaue": implements
  107.          the logic to allow values with no types to be strings */
  108.     var $params; /* used to store parameters in method calls */
  109.     var $method; /* used to store method name */
  110.  
  111.     function XML_RPC_Parser() {
  112.     $this->XML_Parser();
  113.     }
  114.  
  115.     function xmlrpc_se($parser, $name, $attrs) {
  116.     global $_xh, $XML_RPC_DateTime;
  117.     
  118.     switch($name) {
  119.         case "STRUCT":
  120.         case "ARRAY":
  121.         $_xh[$parser]['st'].="array(";
  122.         $_xh[$parser]['cm']++;
  123.         // this last line turns quoting off
  124.         // this means if we get an empty array we'll 
  125.         // simply get a bit of whitespace in the eval
  126.         $_xh[$parser]['qt']=0;
  127.         break;
  128.         case "NAME":
  129.         $_xh[$parser]['st'].="'"; $_xh[$parser]['ac']="";
  130.         break;
  131.         case "FAULT":
  132.         $_xh[$parser]['isf']=1;
  133.         break;
  134.         case "PARAM":
  135.         $_xh[$parser]['st']="";
  136.         break;
  137.         case "VALUE":
  138.         $_xh[$parser]['st'].="new xmlrpcval("; 
  139.         $_xh[$parser]['lv']=1; $_xh[$parser]['vt']="string";
  140.         // look for a value: if this is still 1 by the
  141.         // time we reach the first data segment then the type is string
  142.         // by implication and we need to add in a quote
  143.         $_xh[$parser]['ac']=""; // reset the accumulator
  144.         break;
  145.         case "MEMBER":
  146.         $_xh[$parser]['ac']="";
  147.         break;
  148.         default:
  149.         if ($name=="DATETIME.ISO8601" || $name=="STRING") {
  150.             $_xh[$parser]['qt']=1; 
  151.             if ($name=="DATETIME.ISO8601")
  152.             $_xh[$parser]['vt']=$XML_RPC_DateTime;
  153.         } else if ($name=="BASE64") {
  154.             $_xh[$parser]['qt']=2;
  155.         } else {
  156.             $_xh[$parser]['qt']=0;
  157.         }
  158.     }
  159.     if ($name!="VALUE") $_xh[$parser]['lv']=0;
  160.     }
  161.  
  162.     function xmlrpc_ee($parser, $name) {
  163.     global $_xh,$XML_RPC_Types;
  164.     
  165.     switch($name) {
  166.         case "STRUCT":
  167.         case "ARRAY":
  168.         if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',') {
  169.             $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
  170.         }
  171.         $_xh[$parser]['st'].=")";    
  172.         $_xh[$parser]['vt']=strtolower($name);
  173.         $_xh[$parser]['cm']--;
  174.         break;
  175.         case "NAME":
  176.         $_xh[$parser]['st'].= $_xh[$parser]['ac'] . "' => ";
  177.         break;
  178.         case "VALUE":
  179.         if ($_xh[$parser]['qt']==1) {
  180.             // we use double quotes rather than single so backslashification works OK
  181.             $_xh[$parser]['st'].="\"". $_xh[$parser]['ac'] . "\""; 
  182.         } else if ($_xh[$parser]['qt']==2) {
  183.             $_xh[$parser]['st'].="base64_decode('". $_xh[$parser]['ac'] . "')"; 
  184.         } else 
  185.             $_xh[$parser]['st'].=$_xh[$parser]['ac'];
  186.         $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
  187.         if ($_xh[$parser]['cm']) $_xh[$parser]['st'].=",";
  188.         break;
  189.         case "MEMBER":
  190.         $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
  191.         break;
  192.         case "DATA":
  193.         $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
  194.         break;
  195.         case "PARAM":
  196.         $_xh[$parser]['params'][]=$_xh[$parser]['st'];
  197.         break;
  198.         case "METHODNAME":
  199.         $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", "", $_xh[$parser]['ac']);
  200.         break;
  201.         case "BOOLEAN":
  202.         // special case here: we translate boolean 1 or 0 into PHP
  203.         // constants true or false
  204.         if ($_xh[$parser]['ac']=='1') 
  205.             $_xh[$parser]['ac']="true";
  206.         else 
  207.             $_xh[$parser]['ac']="false";
  208.         $_xh[$parser]['vt']=strtolower($name);
  209.         break;
  210.         default:
  211.         // if it's a valid type name, set the type
  212.         if ($XML_RPC_Types[strtolower($name)]) {
  213.             $_xh[$parser]['vt']=strtolower($name);
  214.         }
  215.         break;
  216.     }
  217.     }
  218.     
  219.     function xmlrpc_cd($parser, $data) {    
  220.     global $_xh, $XML_RPC_backslash, $XML_RPC_twoslash;
  221.     
  222.     //if (ereg("^[\n\r \t]+$", $data)) return;
  223.     // print "adding [${data}]\n";
  224.     if ($_xh[$parser]['lv']==1) {  
  225.         $_xh[$parser]['qt']=1; 
  226.         $_xh[$parser]['lv']=2; 
  227.     }
  228.     if ($_xh[$parser]['qt']) { // quoted string
  229.         $_xh[$parser]['ac'].=ereg_replace('\$', '\\$',
  230.                           ereg_replace('"', '\"', 
  231.                                ereg_replace($XML_RPC_backslash, 
  232.                                     $XML_RPC_backslash, $data)));
  233.     }
  234.     else 
  235.         $_xh[$parser]['ac'].=$data;
  236.     }
  237.  
  238.     function xmlrpc_dh($parser, $data) {
  239.     global $_xh;
  240.     if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
  241.         if ($_xh[$parser]['lv']==1) {  
  242.         $_xh[$parser]['qt']=1; 
  243.         $_xh[$parser]['lv']=2; 
  244.         }
  245.         $_xh[$parser]['ac'].=$data;
  246.     }
  247.     }
  248. }
  249.  
  250. function xmlrpc_entity_decode($string) {
  251.   $top=split("&", $string);
  252.   $op="";
  253.   $i=0; 
  254.   while($i<sizeof($top)) {
  255.     if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs)) {
  256.       $op.=ereg_replace("^[#a-zA-Z0-9]+;",
  257.                         xmlrpc_lookup_entity($regs[1]),
  258.                                             $top[$i]);
  259.     } else {
  260.       if ($i==0) 
  261.         $op=$top[$i]; 
  262.       else
  263.         $op.="&" . $top[$i];
  264.     }
  265.     $i++;
  266.   }
  267.   return $op;
  268. }
  269.  
  270. function xmlrpc_lookup_entity($ent) {
  271.   global $XML_RPC_Entities;
  272.   
  273.   if ($XML_RPC_Entities[strtolower($ent)]) 
  274.     return $XML_RPC_Entities[strtolower($ent)];
  275.   if (ereg("^#([0-9]+)$", $ent, $regs))
  276.     return chr($regs[1]);
  277.   return "?";
  278. }
  279.  
  280. class xmlrpc_client {
  281.   var $path;
  282.   var $server;
  283.   var $port;
  284.   var $errno;
  285.   var $errstring;
  286.   var $debug=0;
  287.     var $username="";
  288.     var $password="";
  289.  
  290.   function xmlrpc_client($path, $server, $port=80) {
  291.         $this->port=$port; $this->server=$server; $this->path=$path;
  292.   }
  293.  
  294.   function setDebug($in) {
  295.         if ($in) { 
  296.             $this->debug=1;
  297.         } else {
  298.             $this->debug=0;
  299.         }
  300.   }
  301.  
  302.     function setCredentials($u, $p) {
  303.         $this->username=$u;
  304.         $this->password=$p;
  305.     }
  306.  
  307.   function send($msg, $timeout=0) {
  308.         // where msg is an xmlrpcmsg
  309.         $msg->debug=$this->debug;
  310.         return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
  311.                                                                         $timeout, $this->username, 
  312.                                                                         $this->password);
  313.   }
  314.  
  315.     function sendPayloadHTTP10($msg, $server, $port, $timeout=0,
  316.                                                          $username="", $password="") {
  317.         if($timeout>0)
  318.             $fp=fsockopen($server, $port,
  319.                                         $this->errno, $this->errstr, $timeout);
  320.         else
  321.             $fp=fsockopen($server, $port,
  322.                                         $this->errno, $this->errstr);
  323.         if (!$fp) {   
  324.             return 0;
  325.         }
  326.         // Only create the payload if it was not created previously
  327.         if(empty($msg->payload)) $msg->createPayload();
  328.         
  329.         // thanks to Grant Rauscher <grant7@firstworld.net>
  330.         // for this
  331.         $credentials="";
  332.         if ($username!="") {
  333.             $credentials="Authorization: Basic " .
  334.                 base64_encode($username . ":" . $password) . "\r\n";
  335.         }
  336.  
  337.         $op= "POST " . $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" .
  338.             "Host: ". $this->server  . "\r\n" .
  339.             $credentials . 
  340.             "Content-Type: text/xml\r\nContent-Length: " .
  341.             strlen($msg->payload) . "\r\n\r\n" .
  342.             $msg->payload;
  343.         
  344.         if (!fputs($fp, $op, strlen($op))) {
  345.             $this->errstr="Write error";
  346.             return 0;
  347.         }
  348.         $resp=$msg->parseResponseFile($fp);
  349.         fclose($fp);
  350.         return $resp;
  351.     }
  352.  
  353. } // end class xmlrpc_client
  354.  
  355. class xmlrpcresp {
  356.   var $xv;
  357.   var $fn;
  358.   var $fs;
  359.   var $hdrs;
  360.  
  361.   function xmlrpcresp($val, $fcode=0, $fstr="") {
  362.     if ($fcode!=0) {
  363.       $this->fn=$fcode;
  364.       $this->fs=htmlspecialchars($fstr);
  365.     } else {
  366.       $this->xv=$val;
  367.     }
  368.   }
  369.  
  370.   function faultCode() { return $this->fn; }
  371.   function faultString() { return $this->fs; }
  372.   function value() { return $this->xv; }
  373.  
  374.   function serialize() { 
  375.     $rs="<methodResponse>\n";
  376.     if ($this->fn) {
  377.       $rs.="<fault>
  378.   <value>
  379.     <struct>
  380.       <member>
  381.         <name>faultCode</name>
  382.         <value><int>" . $this->fn . "</int></value>
  383.       </member>
  384.       <member>
  385.         <name>faultString</name>
  386.         <value><string>" . $this->fs . "</string></value>
  387.       </member>
  388.     </struct>
  389.   </value>
  390. </fault>";
  391.     } else {
  392.       $rs.="<params>\n<param>\n" . $this->xv->serialize() . 
  393.         "</param>\n</params>";
  394.     }
  395.     $rs.="\n</methodResponse>";
  396.     return $rs;
  397.   }
  398. }
  399.  
  400. class xmlrpcmsg {
  401.   var $payload;
  402.   var $methodname;
  403.   var $params=array();
  404.   var $debug=0;
  405.  
  406.   function xmlrpcmsg($meth, $pars=0) {
  407.         $this->methodname=$meth;
  408.         if (is_array($pars) && sizeof($pars)>0) {
  409.             for($i=0; $i<sizeof($pars); $i++) 
  410.                 $this->addParam($pars[$i]);
  411.         }
  412.   }
  413.  
  414.   function xml_header() {
  415.     return "<?xml version=\"1.0\"?>\n<methodCall>\n";
  416.   }
  417.  
  418.   function xml_footer() {
  419.     return "</methodCall>\n";
  420.   }
  421.  
  422.   function createPayload() {
  423.     $this->payload=$this->xml_header();
  424.     $this->payload.="<methodName>" . $this->methodname . "</methodName>\n";
  425.     //    if (sizeof($this->params)) {
  426.       $this->payload.="<params>\n";
  427.       for($i=0; $i<sizeof($this->params); $i++) {
  428.         $p=$this->params[$i];
  429.         $this->payload.="<param>\n" . $p->serialize() .
  430.           "</param>\n";
  431.       }
  432.       $this->payload.="</params>\n";
  433.     // }
  434.     $this->payload.=$this->xml_footer();
  435.     $this->payload=ereg_replace("\n", "\r\n", $this->payload);
  436.   }
  437.  
  438.   function method($meth="") {
  439.     if ($meth!="") {
  440.       $this->methodname=$meth;
  441.     }
  442.     return $this->methodname;
  443.   }
  444.  
  445.   function serialize() {
  446.         $this->createPayload();
  447.         return $this->payload;
  448.   }
  449.  
  450.   function addParam($par) { $this->params[]=$par; }
  451.   function getParam($i) { return $this->params[$i]; }
  452.   function getNumParams() { return sizeof($this->params); }
  453.  
  454.   function parseResponseFile($fp) {
  455.     $ipd="";
  456.  
  457.     while($data=fread($fp, 32768)) {
  458.       $ipd.=$data;
  459.     }
  460.     return $this->parseResponse($ipd);
  461.   }
  462.  
  463.   function parseResponse($data="") {
  464.     global $_xh,$XML_RPC_err,$XML_RPC_str;
  465.     global $XML_RPC_defencoding;
  466.  
  467.     
  468.     $parser = xml_parser_create($XML_RPC_defencoding);
  469.  
  470.     $_xh[$parser]=array();
  471.  
  472.     $_xh[$parser]['st']=""; 
  473.     $_xh[$parser]['cm']=0; 
  474.     $_xh[$parser]['isf']=0; 
  475.     $_xh[$parser]['ac']="";
  476.  
  477.     xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
  478.     xml_set_element_handler($parser, "xmlrpc_se", "xmlrpc_ee");
  479.     xml_set_character_data_handler($parser, "xmlrpc_cd");
  480.     xml_set_default_handler($parser, "xmlrpc_dh");
  481.     $XML_RPC_value=new xmlrpcval;
  482.  
  483.     $hdrfnd=0;
  484.     if ($this->debug)
  485.       print "<PRE>---GOT---\n" . htmlspecialchars($data) . 
  486.         "\n---END---\n</PRE>";
  487.     // see if we got an HTTP 200 OK, else bomb
  488.     // but only do this if we're using the HTTP protocol.
  489.     if (ereg("^HTTP",$data) && 
  490.             !ereg("^HTTP/[0-9\.]+ 200 ", $data)) {
  491.         $errstr= substr($data, 0, strpos($data, "\n")-1);
  492.         error_log("HTTP error, got response: " .$errstr);
  493.         $r=new xmlrpcresp(0, $XML_RPC_err["http_error"],
  494.                                             $XML_RPC_str["http_error"]. " (" . $errstr . ")");
  495.         xml_parser_free($parser);
  496.         return $r;
  497.     }
  498.     // gotta get rid of headers here
  499.     if ((!$hdrfnd) && ereg("^(.*)\r\n\r\n",$data,$_xh[$parser]['ha'])) {
  500.       $data=ereg_replace("^.*\r\n\r\n", "", $data);
  501.       $hdrfnd=1;
  502.     }
  503.     
  504.     if (!xml_parse($parser, $data, sizeof($data))) {
  505.         // thanks to Peter Kocks <peter.kocks@baygate.com>
  506.         if((xml_get_current_line_number($parser)) == 1)   
  507.             $errstr = "XML error at line 1, check URL";
  508.         else
  509.             $errstr = sprintf("XML error: %s at line %d",
  510.                                                 xml_error_string(xml_get_error_code($parser)),
  511.                                                 xml_get_current_line_number($parser));
  512.         error_log($errstr);
  513.         $r=new xmlrpcresp(0, $XML_RPC_err["invalid_return"],
  514.                                             $XML_RPC_str["invalid_return"]);
  515.         xml_parser_free($parser);
  516.         return $r;
  517.     }
  518.     xml_parser_free($parser);
  519.     if ($this->debug) {
  520.       print "<PRE>---EVALING---[" . 
  521.         strlen($_xh[$parser]['st']) . " chars]---\n" . 
  522.         htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";
  523.     }
  524.     if (strlen($_xh[$parser]['st'])==0) {
  525.       // then something odd has happened
  526.       // and it's time to generate a client side error
  527.       // indicating something odd went on
  528.       $r=new xmlrpcresp(0, $XML_RPC_err["invalid_return"],
  529.                         $XML_RPC_str["invalid_return"]);
  530.     } else {
  531.       eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');
  532.       if ($_xh[$parser]['isf']) {
  533.         $f=$v->structmem("faultCode");
  534.         $fs=$v->structmem("faultString");
  535.         $r=new xmlrpcresp($v, $f->scalarval(), 
  536.                           $fs->scalarval());
  537.       } else {
  538.         $r=new xmlrpcresp($v);
  539.       }
  540.     }
  541.     $r->hdrs=split('\r?\n', $_xh[$parser]['ha'][1]);
  542.     return $r;
  543.   }
  544.  
  545. }
  546.  
  547. class xmlrpcval {
  548.   var $me=array();
  549.   var $mytype=0;
  550.  
  551.   function xmlrpcval($val=-1, $type="") {
  552.         global $XML_RPC_Types;
  553.         $this->me=array();
  554.         $this->mytype=0;
  555.         if ($val!=-1 || $type!="") {
  556.             if ($type=="") $type="string";
  557.             if ($XML_RPC_Types[$type]==1) {
  558.                 $this->addScalar($val,$type);
  559.             }
  560.       else if ($XML_RPC_Types[$type]==2)
  561.             $this->addArray($val);
  562.             else if ($XML_RPC_Types[$type]==3)
  563.                 $this->addStruct($val);
  564.         }
  565.   }
  566.  
  567.   function addScalar($val, $type="string") {
  568.         global $XML_RPC_Types, $XML_RPC_Boolean;
  569.  
  570.         if ($this->mytype==1) {
  571.             echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";
  572.             return 0;
  573.         }
  574.         $typeof=$XML_RPC_Types[$type];
  575.         if ($typeof!=1) {
  576.             echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";
  577.             return 0;
  578.         }
  579.         
  580.         if ($type==$XML_RPC_Boolean) {
  581.             if (strcasecmp($val,"true")==0 || $val==1 || $val==true) {
  582.                 $val=1;
  583.             } else {
  584.                 $val=0;
  585.             }
  586.         }
  587.         
  588.         if ($this->mytype==2) {
  589.             // we're adding to an array here
  590.             $ar=$this->me["array"];
  591.             $ar[]=new xmlrpcval($val, $type);
  592.             $this->me["array"]=$ar;
  593.         } else {
  594.             // a scalar, so set the value and remember we're scalar
  595.             $this->me[$type]=$val;
  596.             $this->mytype=$typeof;
  597.         }
  598.         return 1;
  599.   }
  600.  
  601.   function addArray($vals) {
  602.         global $XML_RPC_Types;
  603.         if ($this->mytype!=0) {
  604.             echo "<B>xmlrpcval</B>: already initialized as a [" . 
  605.                 $this->kindOf() . "]<BR>";
  606.             return 0;
  607.         }
  608.         $this->mytype=$XML_RPC_Types["array"];
  609.         $this->me["array"]=$vals;
  610.         return 1;
  611.   }
  612.  
  613.   function addStruct($vals) {
  614.     global $XML_RPC_Types;
  615.     if ($this->mytype!=0) {
  616.       echo "<B>xmlrpcval</B>: already initialized as a [" . 
  617.         $this->kindOf() . "]<BR>";
  618.       return 0;
  619.     }
  620.     $this->mytype=$XML_RPC_Types["struct"];
  621.     $this->me["struct"]=$vals;
  622.     return 1;
  623.   }
  624.  
  625.   function dump($ar) {
  626.     reset($ar);
  627.     while ( list( $key, $val ) = each( $ar ) ) {
  628.       echo "$key => $val<br>";
  629.       if ($key == 'array')
  630.         while ( list( $key2, $val2 ) = each( $val ) ) {
  631.           echo "-- $key2 => $val2<br>";
  632.         }
  633.     }
  634.   }
  635.  
  636.   function kindOf() {
  637.     switch($this->mytype) {
  638.     case 3:
  639.       return "struct";
  640.       break;
  641.     case 2:
  642.       return "array";
  643.       break;
  644.     case 1:
  645.       return "scalar";
  646.       break;
  647.     default:
  648.       return "undef";
  649.     }
  650.   }
  651.  
  652.   function serializedata($typ, $val) {
  653.         $rs="";
  654.         global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String;
  655.         switch($XML_RPC_Types[$typ]) {
  656.         case 3:
  657.             // struct
  658.             $rs.="<struct>\n";
  659.             reset($val);
  660.             while(list($key2, $val2)=each($val)) {
  661.                 $rs.="<member><name>${key2}</name>\n";
  662.                 $rs.=$this->serializeval($val2);
  663.                 $rs.="</member>\n";
  664.             }
  665.             $rs.="</struct>";
  666.             break;
  667.         case 2:
  668.             // array
  669.             $rs.="<array>\n<data>\n";
  670.             for($i=0; $i<sizeof($val); $i++) {
  671.                 $rs.=$this->serializeval($val[$i]);
  672.             }
  673.             $rs.="</data>\n</array>";
  674.             break;
  675.         case 1:
  676.             switch ($typ) {
  677.             case $XML_RPC_Base64:
  678.                 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
  679.                 break;
  680.             case $XML_RPC_Boolean:
  681.                 $rs.="<${typ}>" . ($val ? "1" : "0") . "</${typ}>";
  682.                     break;
  683.             case $XML_RPC_String:
  684.                 $rs.="<${typ}>" . htmlspecialchars($val). "</${typ}>";
  685.                 break;
  686.             default:
  687.                 $rs.="<${typ}>${val}</${typ}>";
  688.             }
  689.             break;
  690.         default:
  691.             break;
  692.         }
  693.         return $rs;
  694.   }
  695.  
  696.   function serialize() {
  697.     return $this->serializeval($this);
  698.   }
  699.  
  700.   function serializeval($o) {
  701.         global $XML_RPC_Types;
  702.         $rs="";
  703.         $ar=$o->me;
  704.         reset($ar);
  705.         list($typ, $val) = each($ar);
  706.         $rs.="<value>";
  707.         $rs.=$this->serializedata($typ, $val);
  708.         $rs.="</value>\n";
  709.         return $rs;
  710.   }
  711.  
  712.   function structmem($m) {
  713.         $nv=$this->me["struct"][$m];
  714.         return $nv;
  715.   }
  716.  
  717.     function structreset() {
  718.         reset($this->me["struct"]);
  719.     }
  720.     
  721.     function structeach() {
  722.         return each($this->me["struct"]);
  723.     }
  724.  
  725.   function scalarval() {
  726.         global $XML_RPC_Boolean, $XML_RPC_Base64;
  727.         reset($this->me);
  728.         list($a,$b)=each($this->me);
  729.         return $b;
  730.   }
  731.  
  732.   function scalartyp() {
  733.         global $XML_RPC_I4, $XML_RPC_Int;
  734.         reset($this->me);
  735.         list($a,$b)=each($this->me);
  736.         if ($a==$XML_RPC_I4) 
  737.             $a=$XML_RPC_Int;
  738.         return $a;
  739.   }
  740.  
  741.   function arraymem($m) {
  742.         $nv=$this->me["array"][$m];
  743.         return $nv;
  744.   }
  745.  
  746.   function arraysize() {
  747.         reset($this->me);
  748.         list($a,$b)=each($this->me);
  749.         return sizeof($b);
  750.   }
  751. }
  752.  
  753. // date helpers
  754. function iso8601_encode($timet, $utc=0) {
  755.     // return an ISO8601 encoded string
  756.     // really, timezones ought to be supported
  757.     // but the XML-RPC spec says:
  758.     //
  759.     // "Don't assume a timezone. It should be specified by the server in its
  760.   // documentation what assumptions it makes about timezones."
  761.     // 
  762.     // these routines always assume localtime unless 
  763.     // $utc is set to 1, in which case UTC is assumed
  764.     // and an adjustment for locale is made when encoding
  765.     if (!$utc) {
  766.         $t=strftime("%Y%m%dT%H:%M:%S", $timet);
  767.     } else {
  768.         if (function_exists("gmstrftime")) 
  769.             // gmstrftime doesn't exist in some versions
  770.             // of PHP
  771.             $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
  772.         else {
  773.             $t=strftime("%Y%m%dT%H:%M:%S", $timet-date("Z"));
  774.         }
  775.     }
  776.     return $t;
  777. }
  778.  
  779. function iso8601_decode($idate, $utc=0) {
  780.     // return a timet in the localtime, or UTC
  781.     $t=0;
  782.     if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",
  783.                      $idate, $regs)) {
  784.         if ($utc) {
  785.             $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
  786.         } else {
  787.             $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
  788.         }
  789.     } 
  790.     return $t;
  791. }
  792.  
  793. // general helper functions --- they DON'T WORK YET
  794.  
  795. function hash_to_rpcv($hash)
  796.     // contributed by Ben Margolin <ben@wendy.auctionwatch.com>  
  797. {
  798.   reset($hash);
  799.   while (list($k,$v) = each($hash)) {
  800.     if (is_integer($v)) {
  801.       $oa[$k] = new xmlrpcval($v, 'int');
  802.     } else if (is_array($v)) {
  803.             $oa[$k] = new xmlrpcval( hash_to_rpcv($v), 'struct' );
  804.     } else { // if binary, do base64...?
  805.       $oa[$k] = new xmlrpcval($v);
  806.     }
  807.     }
  808.     return new xmlrpcval( $oa, 'struct' );
  809. } // hash_to_rpc
  810.  
  811.  
  812. function rpcv_to_hash($rv)
  813. {
  814.   $rv->structreset();
  815.   while (list($k,$v) = $rv->structeach()) {
  816.     $ko = $v->kindOf();
  817.     if ('scalar' == $ko) {
  818.       $oa[$k] = $v->scalarval();
  819.     } else {
  820.             $oa[$k] = rpcv_to_hash( $v );
  821.         }
  822.   }
  823.     return $oa;
  824. } // rpcv_to_hash 
  825.  
  826.  
  827. ?>
  828.