minor bug fix
[openemr.git] / library / freeb / xmlrpc.inc
blobbd1a0a71df5e1da302863e7eb83b162c1415e6e2
1 <?php                                   // -*-c++-*-
2 // by Edd Dumbill (C) 1999-2002
3 // <edd@usefulinc.com>
4 // $Id$
7 // Copyright (c) 1999,2000,2002 Edd Dumbill.
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
12 // are met:
14 //    * Redistributions of source code must retain the above copyright
15 //      notice, this list of conditions and the following disclaimer.
17 //    * Redistributions in binary form must reproduce the above
18 //      copyright notice, this list of conditions and the following
19 //      disclaimer in the documentation and/or other materials provided
20 //      with the distribution.
22 //    * Neither the name of the "XML-RPC for PHP" nor the names of its
23 //      contributors may be used to endorse or promote products derived
24 //      from this software without specific prior written permission.
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37 // OF THE POSSIBILITY OF SUCH DAMAGE.
39         if (!function_exists('xml_parser_create'))
40         {
41                 // Win 32 fix. From: 'Leo West' <lwest@imaginet.fr>
42                 if($WINDIR)
43                 {
44                         dl('php3_xml.dll');
45                 }
46                 else
47                 {
48                         dl('xml.so');
49                 }
50         }
53         define("XMLRPCI4", "i4");
54         $xmlrpcI4=XMLRPCI4;
55         define("XMLRPCINT", "int");
56         $xmlrpcInt=XMLRPCINT;
57         define("XMLRPCBOOLEAN", "boolean");
58         $xmlrpcBoolean=XMLRPCBOOLEAN;
59         define("XMLRPCDOUBLE", "double");
60         $xmlrpcDouble=XMLRPCDOUBLE;
61         define("XMLRPCSTRING", "string");
62         $xmlrpcString=XMLRPCSTRING;
63         define("XMLRPCDATETIME", "dateTime.iso8601");
64         $xmlrpcDateTime=XMLRPCDATETIME;
65         define("XMLRPCBASE64", "base64");
66         $xmlrpcBase64=XMLRPCBASE64;
67         define("XMLRPCARRAY", "array");
68         $xmlrpcArray=XMLRPCARRAY;
69         define("XMLRPCSTRUCT", "struct");
70         $xmlrpcStruct=XMLRPCSTRUCT;
71         
72         $xmlrpcTypes=array(
73                 $xmlrpcI4       => 1,
74                 $xmlrpcInt      => 1,
75                 $xmlrpcBoolean  => 1,
76                 $xmlrpcString   => 1,
77                 $xmlrpcDouble   => 1,
78                 $xmlrpcDateTime => 1,
79                 $xmlrpcBase64   => 1,
80                 $xmlrpcArray    => 2,
81                 $xmlrpcStruct   => 3
82         );
84         $xmlEntities=array(
85                 'amp'  => '&',
86                 'quot' => '"',
87                 'lt'   => '<',
88                 'gt'   => '>',
89                 'apos' => "'"
90         );
92         $xmlrpcerr['unknown_method']=1;
93         $xmlrpcstr['unknown_method']='Unknown method';
94         $xmlrpcerr['invalid_return']=2;
95         $xmlrpcstr['invalid_return']='Invalid return payload: enabling debugging to examine incoming payload';
96         $xmlrpcerr['incorrect_params']=3;
97         $xmlrpcstr['incorrect_params']='Incorrect parameters passed to method';
98         $xmlrpcerr['introspect_unknown']=4;
99         $xmlrpcstr['introspect_unknown']="Can't introspect: method unknown";
100         $xmlrpcerr['http_error']=5;
101         $xmlrpcstr['http_error']="Didn't receive 200 OK from remote server.";
102         $xmlrpcerr['no_data']=6;
103         $xmlrpcstr['no_data']='No data received from server.';
104         $xmlrpcerr['no_ssl']=7;
105         $xmlrpcstr['no_ssl']='No SSL support compiled in.';
106         $xmlrpcerr['curl_fail']=8;
107         $xmlrpcstr['curl_fail']='CURL error';
110         $xmlrpcerr['multicall_notstruct'] = 9;
111         $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';
112         $xmlrpcerr['multicall_nomethod']  = 10;
113         $xmlrpcstr['multicall_nomethod']  = 'missing methodName';
114         $xmlrpcerr['multicall_notstring'] = 11;
115         $xmlrpcstr['multicall_notstring'] = 'methodName is not a string';
116         $xmlrpcerr['multicall_recursion'] = 12;
117         $xmlrpcstr['multicall_recursion'] = 'recursive system.multicall forbidden';
118         $xmlrpcerr['multicall_noparams']  = 13;
119         $xmlrpcstr['multicall_noparams']  = 'missing params';
120         $xmlrpcerr['multicall_notarray']  = 14;
121         $xmlrpcstr['multicall_notarray']  = 'params is not an array';
123         $xmlrpc_defencoding='UTF-8';
125         $xmlrpcName='XML-RPC for PHP';
126         $xmlrpcVersion='1.0.99';
128         // let user errors start at 800
129         $xmlrpcerruser=800;
130         // let XML parse errors start at 100
131         $xmlrpcerrxml=100;
133         // formulate backslashes for escaping regexp
134         $xmlrpc_backslash=chr(92).chr(92);
136         // used to store state during parsing
137         // quick explanation of components:
138         //   st - used to build up a string for evaluation
139         //   ac - used to accumulate values
140         //   qt - used to decide if quotes are needed for evaluation
141         //   cm - used to denote struct or array (comma needed)
142         //   isf - used to indicate a fault
143         //   lv - used to indicate "looking for a value": implements
144         //        the logic to allow values with no types to be strings
145         //   params - used to store parameters in method calls
146         //   method - used to store method name
148         $_xh=array();
150         function xmlrpc_entity_decode($string)
151         {
152                 $top=split('&', $string);
153                 $op='';
154                 $i=0; 
155                 while($i<sizeof($top))
156                 {
157                         if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs))
158                         {
159                                 $op.=ereg_replace("^[#a-zA-Z0-9]+;",
160                                 xmlrpc_lookup_entity($regs[1]),
161                                 $top[$i]);
162                         }
163                         else
164                         {
165                                 if ($i==0)
166                                 {
167                                         $op=$top[$i];
168                                 }
169                                 else
170                                 {
171                                         $op.='&' . $top[$i];
172                                 }
173                         }
174                         $i++;
175                 }
176                 return $op;
177         }
179         function xmlrpc_lookup_entity($ent)
180         {
181                 global $xmlEntities;
183                 if (isset($xmlEntities[strtolower($ent)]))
184                 {
185                         return $xmlEntities[strtolower($ent)];
186                 }
187                 if (ereg("^#([0-9]+)$", $ent, $regs))
188                 {
189                         return chr($regs[1]);
190                 }
191                 return '?';
192         }
194         function xmlrpc_se($parser, $name, $attrs)
195         {
196                 global $_xh, $xmlrpcDateTime, $xmlrpcString;
198                 switch($name)
199                 {
200                         case 'STRUCT':
201                         case 'ARRAY':
202                                 $_xh[$parser]['st'].='array(';
203                                 $_xh[$parser]['cm']++;
204                                 // this last line turns quoting off
205                                 // this means if we get an empty array we'll 
206                                 // simply get a bit of whitespace in the eval
207                                 $_xh[$parser]['qt']=0;
208                                 break;
209                         case 'NAME':
210                                 $_xh[$parser]['st'].="'"; $_xh[$parser]['ac']='';
211                                 break;
212                         case 'FAULT':
213                                 $_xh[$parser]['isf']=1;
214                                 break;
215                         case 'PARAM':
216                                 $_xh[$parser]['st']='';
217                                 break;
218                         case 'VALUE':
219                                 $_xh[$parser]['st'].='new xmlrpcval(';
220                                 $_xh[$parser]['vt']=$xmlrpcString;
221                                 $_xh[$parser]['ac']='';
222                                 $_xh[$parser]['qt']=0;
223                                 $_xh[$parser]['lv']=1;
224                                 // look for a value: if this is still 1 by the
225                                 // time we reach the first data segment then the type is string
226                                 // by implication and we need to add in a quote
227                                 break;
228                         case 'I4':
229                         case 'INT':
230                         case 'STRING':
231                         case 'BOOLEAN':
232                         case 'DOUBLE':
233                         case 'DATETIME.ISO8601':
234                         case 'BASE64':
235                                 $_xh[$parser]['ac']=''; // reset the accumulator
237                                 if ($name=='DATETIME.ISO8601' || $name=='STRING')
238                                 {
239                                         $_xh[$parser]['qt']=1;
240                                         if ($name=='DATETIME.ISO8601')
241                                         {
242                                                 $_xh[$parser]['vt']=$xmlrpcDateTime;
243                                         }
244                                 }
245                                 elseif ($name=='BASE64')
246                                 {
247                                         $_xh[$parser]['qt']=2;
248                                 }
249                                 else
250                                 {
251                                         // No quoting is required here -- but
252                                         // at the end of the element we must check
253                                         // for data format errors.
254                                         $_xh[$parser]['qt']=0;
255                                 }
256                                 break;
257                         case 'MEMBER':
258                                 $_xh[$parser]['ac']='';
259                                 break;
260                         default:
261                                 break;
262                 }
264                 if ($name!='VALUE')
265                 {
266                         $_xh[$parser]['lv']=0;
267                 }
268         }
270         function xmlrpc_ee($parser, $name)
271         {
272                 global $_xh,$xmlrpcTypes,$xmlrpcString;
274                 switch($name)
275                 {
276                         case 'STRUCT':
277                         case 'ARRAY':
278                                 if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')
279                                 {
280                                         $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
281                                 }
282                                 $_xh[$parser]['st'].=')';
283                                 $_xh[$parser]['vt']=strtolower($name);
284                                 $_xh[$parser]['cm']--;
285                                 break;
286                         case 'NAME':
287                                 $_xh[$parser]['st'].= $_xh[$parser]['ac'] . "' => ";
288                                 break;
289                         case 'BOOLEAN':
290                                 // special case here: we translate boolean 1 or 0 into PHP
291                                 // constants true or false
292                                 if ($_xh[$parser]['ac']=='1')
293                                 {
294                                         $_xh[$parser]['ac']='true';
295                                 }
296                                 else
297                                 {
298                                         $_xh[$parser]['ac']='false';
299                                         $_xh[$parser]['vt']=strtolower($name);
300                                         // Drop through intentionally.
301                                 }
302                         case 'I4':
303                         case 'INT':
304                         case 'STRING':
305                         case 'DOUBLE':
306                         case 'DATETIME.ISO8601':
307                         case 'BASE64':
308                                 if ($_xh[$parser]['qt']==1)
309                                 {
310                                         // we use double quotes rather than single so backslashification works OK
311                                         $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
312                                 }
313                                 elseif ($_xh[$parser]['qt']==2)
314                                 {
315                                         $_xh[$parser]['st'].="base64_decode('". $_xh[$parser]['ac'] . "')"; 
316                                 }
317                                 elseif ($name=='BOOLEAN')
318                                 {
319                                         $_xh[$parser]['st'].=$_xh[$parser]['ac'];
320                                 }
321                                 else
322                                 {
323                                         // we have an I4, INT or a DOUBLE
324                                         // we must check that only 0123456789-.<space> are characters here
325                                         if (!ereg("^\-?[0123456789 \t\.]+$", $_xh[$parser]['ac']))
326                                         {
327                                                 // TODO: find a better way of throwing an error
328                                                 // than this!
329                                                 error_log('XML-RPC: non numeric value received in INT or DOUBLE');
330                                                 $_xh[$parser]['st'].='ERROR_NON_NUMERIC_FOUND';
331                                         }
332                                         else
333                                         {
334                                                 // it's ok, add it on
335                                                 $_xh[$parser]['st'].=$_xh[$parser]['ac'];
336                                         }
337                                 }
338                                 $_xh[$parser]['ac']=''; $_xh[$parser]['qt']=0;
339                                 $_xh[$parser]['lv']=3; // indicate we've found a value
340                                 break;
341                         case 'VALUE':
342                                 // deal with a string value
343                                 if (strlen($_xh[$parser]['ac'])>0 &&
344                                         $_xh[$parser]['vt']==$xmlrpcString)
345                                 {
346                                         $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"'; 
347                                 }
348                                 // This if() detects if no scalar was inside <VALUE></VALUE>
349                                 // and pads an empty ''.
350                                 if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(')
351                                 {
352                                         $_xh[$parser]['st'].= '""';
353                                 }
354                                 $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
355                                 if ($_xh[$parser]['cm'])
356                                 {
357                                         $_xh[$parser]['st'].=',';
358                                 }
359                                 break;
360                         case 'MEMBER':
361                                 $_xh[$parser]['ac']=''; $_xh[$parser]['qt']=0;
362                                 break;
363                         case 'DATA':
364                                 $_xh[$parser]['ac']=''; $_xh[$parser]['qt']=0;
365                                 break;
366                         case 'PARAM':
367                                 $_xh[$parser]['params'][]=$_xh[$parser]['st'];
368                                 break;
369                         case 'METHODNAME':
370                                 $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);
371                                 break;
372                         case 'BOOLEAN':
373                                 // special case here: we translate boolean 1 or 0 into PHP
374                                 // constants true or false
375                                 if ($_xh[$parser]['ac']=='1')
376                                 {
377                                         $_xh[$parser]['ac']='true';
378                                 }
379                                 else
380                                 {
381                                         $_xh[$parser]['ac']='false';
382                                         $_xh[$parser]['vt']=strtolower($name);
383                                 }
384                                 break;
385                         default:
386                                 break;
387                 }
388                 // if it's a valid type name, set the type
389                 if (isset($xmlrpcTypes[strtolower($name)]))
390                 {
391                         $_xh[$parser]['vt']=strtolower($name);
392                 }
393         }
395         function xmlrpc_cd($parser, $data)
396         {
397                 global $_xh, $xmlrpc_backslash;
399                 //if (ereg("^[\n\r \t]+$", $data)) return;
400                 // print "adding [${data}]\n";
402                 if ($_xh[$parser]['lv']!=3)
403                 {
404                         // "lookforvalue==3" means that we've found an entire value
405                         // and should discard any further character data
406                         if ($_xh[$parser]['lv']==1)
407                         {
408                                 // if we've found text and we're just in a <value> then
409                                 // turn quoting on, as this will be a string
410                                 $_xh[$parser]['qt']=1; 
411                                 // and say we've found a value
412                                 $_xh[$parser]['lv']=2; 
413                         }
414                         if(!@isset($_xh[$parser]['ac']))
415                         {
416                                 $_xh[$parser]['ac'] = '';
417                         }
418                         $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
419                 }
420         }
422         function xmlrpc_dh($parser, $data)
423         {
424                 global $_xh;
425                 if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
426                 {
427                         if ($_xh[$parser]['lv']==1)
428                         {
429                                 $_xh[$parser]['qt']=1; 
430                                 $_xh[$parser]['lv']=2; 
431                         }
432                         $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
433                 }
434         }
436         class xmlrpc_client
437         {
438                 var $path;
439                 var $server;
440                 var $port;
441                 var $errno;
442                 var $errstring;
443                 var $debug=0;
444                 var $username='';
445                 var $password='';
446                 var $cert='';
447                 var $certpass='';
448                 var $verifypeer=1;
449                 var $verifyhost=1;
450                 var $no_multicall=false;
452                 function xmlrpc_client($path, $server, $port=0)
453                 {
454                         $this->port=$port; $this->server=$server; $this->path=$path;
455                 }
457                 function setDebug($in)
458                 {
459                         if ($in)
460                         {
461                                 $this->debug=1;
462                         }
463                         else
464                         {
465                                 $this->debug=0;
466                         }
467                 }
469                 function setCredentials($u, $p)
470                 {
471                         $this->username=$u;
472                         $this->password=$p;
473                 }
475                 function setCertificate($cert, $certpass)
476                 {
477                         $this->cert = $cert;
478                         $this->certpass = $certpass;
479                 }
481                 function setSSLVerifyPeer($i)
482                 {
483                         $this->verifypeer = $i;
484                 }
486                 function setSSLVerifyHost($i)
487                 {
488                         $this->verifyhost = $i;
489                 }
491                 function send($msg, $timeout=0, $method='http')
492                 {
493                         if (is_array($msg))
494                         {
495                                 // $msg is an array of xmlrpcmsg's
496                                 return $this->multicall($msg, $timeout, $method);
497                         }
499                         // where msg is an xmlrpcmsg
500                         $msg->debug=$this->debug;
502                         if ($method == 'https')
503                         {
504                                 return $this->sendPayloadHTTPS($msg,
505                                 $this->server,
506                                 $this->port, $timeout,
507                                 $this->username, $this->password,
508                                 $this->cert,
509                                 $this->certpass);
510                         }
511                         else
512                         {
513                                 return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
514                                 $timeout, $this->username, 
515                                 $this->password);
516                         }
517                 }
519                 function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
520                 {
521                         global $xmlrpcerr, $xmlrpcstr;
522                         if ($port==0)
523                         {
524                                 $port=80;
525                         }
526                         if($timeout>0)
527                         {
528                                 $fp=fsockopen($server, $port,$this->errno, $this->errstr, $timeout);
529                                 stream_set_timeout($fp,360);
530                                 
531                         }
532                         else
533                         {
534                                 $fp=fsockopen($server, $port,$this->errno, $this->errstr);
535                                 stream_set_timeout($fp,360);
536                         }
537                         if (!$fp)
538                         {
539                                 $this->errstr='Connect error';
540                                 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']);
541                                 return $r;
542                         }
543                         // Only create the payload if it was not created previously
544                         if(empty($msg->payload))
545                         {
546                                 $msg->createPayload();
547                         }
549                         // thanks to Grant Rauscher <grant7@firstworld.net>
550                         // for this
551                         $credentials='';
552                         if ($username!='')
553                         {
554                                 $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
555                         }
557                         $op= "POST " . $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" .
558                                 "Host: ". $this->server  . "\r\n" .
559                                 $credentials . 
560                                 "Content-Type: text/xml\r\nContent-Length: " .
561                                 strlen($msg->payload) . "\r\n\r\n" .
562                                 $msg->payload;
564                         if (!fputs($fp, $op, strlen($op)))
565                         {
566                                 $this->errstr='Write error';
567                                 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']);
568                                 return $r;
569                         }
570                         $resp=$msg->parseResponseFile($fp);
571                         fclose($fp);
572                         return $resp;
573                 }
575                 // contributed by Justin Miller <justin@voxel.net>
576                 // requires curl to be built into PHP
577                 function sendPayloadHTTPS($msg, $server, $port, $timeout=240,$username='', $password='', $cert='',$certpass='')
578                 {
579                         global $xmlrpcerr, $xmlrpcstr;
580                         if ($port == 0)
581                         {
582                                 $port = 443;
583                         }
585                         // Only create the payload if it was not created previously
586                         if(empty($msg->payload))
587                         {
588                                 $msg->createPayload();
589                         }
591                         if (!function_exists('curl_init'))
592                         {
593                                 $this->errstr='SSL unavailable on this install';
594                                 $r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']);
595                                 return $r;
596                         }
598                         $curl = curl_init('https://' . $server . ':' . $port . $this->path);
600                         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
601                         // results into variable
602                         if ($this->debug)
603                         {
604                                 curl_setopt($curl, CURLOPT_VERBOSE, 1);
605                         }
606                         curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC 1.0');
607                         // required for XMLRPC
608                         curl_setopt($curl, CURLOPT_POST, 1);
609                         // post the data
610                         curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
611                         // the data
612                         curl_setopt($curl, CURLOPT_HEADER, 1);
613                         // return the header too
614                         curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
615                         // whether to verify remote host's cert
616                         curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
617                         // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
618                         curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
619                         // required for XMLRPC
620                         if ($timeout)
621                         {
622                                 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
623                         }
624                         // timeout is borked
625                         if ($username && $password)
626                         {
627                                 curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
628                         }
629                         // set auth stuff
630                         if ($cert)
631                         {
632                                 curl_setopt($curl, CURLOPT_SSLCERT, $cert);
633                         }
634                         // set cert file
635                         if ($certpass)
636                         {
637                                 curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass);
638                         }
639                         // set cert password
641                         $result = curl_exec($curl);
643                         if (!$result)
644                         {
645                                 $this->errstr='no response';
646                                 $resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl));
647                         }
648                         else
649                         {
650                                 $resp = $msg->parseResponse($result);
651                         }
652                         curl_close($curl);
653                         return $resp;
654                 }
656                 function multicall($msgs, $timeout=240, $method='http')
657                 {
658                         $results = false;
660                         if (! $this->no_multicall)
661                         {
662                                 $results = $this->_try_multicall($msgs, $timeout, $method);
663                                 /* TODO - this is not php3-friendly */
664                                 // if($results !== false)
665                                 if($results != false)
666                                 {
667                                         // Either the system.multicall succeeded, or the send
668                                         // failed (e.g. due to HTTP timeout).  In either case,
669                                         // we're done for now.
670                                         return $results;
671                                 }
672                                 else
673                                 {
674                                         // system.multicall unsupported by server,
675                                         // don't try it next time...
676                                         $this->no_multicall = true;
677                                 }
678                         }
680                         // system.multicall is unupported by server:
681                         //   Emulate multicall via multiple requests
682                         $results = array();
683                         //foreach($msgs as $msg)
684                         @reset($msgs);
685                         while(list(,$msg) = @each($msgs))
686                         {
687                                 $results[] = $this->send($msg, $timeout, $method);
688                         }
689                         return $results;
690                 }
692                 // Attempt to boxcar $msgs via system.multicall.
693                 function _try_multicall($msgs, $timeout, $method)
694                 {
695                         // Construct multicall message
696                         $calls = array();
697                         //foreach($msgs as $msg)
698                         @reset($msgs);
699                         while(list(,$msg) = @each($msgs))
700                         {
701                                 $call['methodName'] = new xmlrpcval($msg->method(),'string');
702                                 $numParams = $msg->getNumParams();
703                                 $params = array();
704                                 for ($i = 0; $i < $numParams; $i++)
705                                 {
706                                         $params[$i] = $msg->getParam($i);
707                                 }
708                                 $call['params'] = new xmlrpcval($params, 'array');
709                                 $calls[] = new xmlrpcval($call, 'struct');
710                         }
711                         $multicall = new xmlrpcmsg('system.multicall');
712                         $multicall->addParam(new xmlrpcval($calls, 'array'));
714                         // Attempt RPC call
715                         $result = $this->send($multicall, $timeout, $method);
716                         if (!is_object($result))
717                                 return ($result || 0); // transport failed
719                         if ($result->faultCode() != 0)
720                                 return false;           // system.multicall failed
722                         // Unpack responses.
723                         $rets = $result->value();
724                         if ($rets->kindOf() != 'array')
725                                 return false;           // bad return type from system.multicall
726                         $numRets = $rets->arraysize();
727                         if ($numRets != count($msgs))
728                                 return false;           // wrong number of return values.
730                         $response = array();
731                         for ($i = 0; $i < $numRets; $i++)
732                         {
733                                 $val = $rets->arraymem($i);
734                                 switch ($val->kindOf())
735                                 {
736                                 case 'array':
737                                         if ($val->arraysize() != 1)
738                                                 return false;           // Bad value
739                                         // Normal return value
740                                         $response[$i] = new xmlrpcresp($val->arraymem(0));
741                                         break;
742                                 case 'struct':
743                                         $code = $val->structmem('faultCode');
744                                         if ($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
745                                                 return false;
746                                         $str = $val->structmem('faultString');
747                                         if ($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
748                                                 return false;
749                                         $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
750                                         break;
751                                 default:
752                                         return false;
753                                 }
754                         }
755                         return $response;
756                 }
757         } // end class xmlrpc_client
759         class xmlrpcresp
760         {
761                 var $val = 0;
762                 var $errno = 0;
763                 var $errstr = '';
764                 var $hdrs = array();
766                 function xmlrpcresp($val, $fcode = 0, $fstr = '')
767                 {
768                         if ($fcode != 0)
769                         {
770                                 // error
771                                 $this->errno = $fcode;
772                                 $this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
773                         }
774                         else if (!is_object($val))
775                         {
776                                 // programmer error
777                                 error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp.  Defaulting to empty value.");
778                                 $this->val = new xmlrpcval();
779                         }
780                         else
781                         {
782                                 // success
783                                 $this->val = $val;
784                         }
785                 }
787                 function faultCode()
788                 {
789                         return $this->errno;
790                 }
792                 function faultString()
793                 {
794                         return $this->errstr;
795                 }
797                 function value()
798                 {
799                         return $this->val;
800                 }
802                 function serialize()
803                 {
804                         $result = "<methodResponse>\n";
805                         if ($this->errno)
806                         {
807                                 $result .= '<fault>
808 <value>
809 <struct>
810 <member>
811 <name>faultCode</name>
812 <value><int>' . $this->errno . '</int></value>
813 </member>
814 <member>
815 <name>faultString</name>
816 <value><string>' . $this->errstr . '</string></value>
817 </member>
818 </struct>
819 </value>
820 </fault>';
821                         }
822                         else
823                         {
824                                 $result .= "<params>\n<param>\n" .
825                                                 $this->val->serialize() . 
826                                                 "</param>\n</params>";
827                         }
828                         $result .= "\n</methodResponse>";
829                         return $result;
830                 }
831         }
833         class xmlrpcmsg
834         {
835                 var $payload;
836                 var $methodname;
837                 var $params=array();
838                 var $debug=0;
840                 function xmlrpcmsg($meth, $pars=0)
841                 {
842                         $this->methodname=$meth;
843                         if (is_array($pars) && sizeof($pars)>0)
844                         {
845                                 for($i=0; $i<sizeof($pars); $i++)
846                                 {
847                                         $this->addParam($pars[$i]);
848                                 }
849                         }
850                 }
852                 function xml_header()
853                 {
854                         return "<?xml version=\"1.0\"?>\n<methodCall>\n";
855                 }
857                 function xml_footer()
858                 {
859                         return "</methodCall>\n";
860                 }
862                 function createPayload()
863                 {
864                         $this->payload=$this->xml_header();
865                         $this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
866                         //      if (sizeof($this->params)) {
867                         $this->payload.="<params>\n";
868                         for($i=0; $i<sizeof($this->params); $i++)
869                         {
870                                 $p=$this->params[$i];
871                                 $this->payload.="<param>\n" . $p->serialize() .
872                                 "</param>\n";
873                         }
874                         $this->payload.="</params>\n";
875                         // }
876                         $this->payload.=$this->xml_footer();
877                         $this->payload=str_replace("\n", "\r\n", $this->payload);
878                 }
880                 function method($meth='')
881                 {
882                         if ($meth!='')
883                         {
884                                 $this->methodname=$meth;
885                         }
886                         return $this->methodname;
887                 }
889                 function serialize()
890                 {
891                         $this->createPayload();
892                         return $this->payload;
893                 }
895                 function addParam($par) { $this->params[]=$par; }
896                 function getParam($i) { return $this->params[$i]; }
897                 function getNumParams() { return sizeof($this->params); }
899                 function parseResponseFile($fp)
900                 {
901                         $ipd='';
902                         while($data=fread($fp, 32768))
903                         {
904                                 $ipd.=$data;
905                         }
906                         return $this->parseResponse($ipd);
907                 }
909                 function parseResponse($data='')
910                 {
911                         global $_xh,$xmlrpcerr,$xmlrpcstr;
912                         global $xmlrpc_defencoding;
914                         $parser = xml_parser_create($xmlrpc_defencoding);
916                         $_xh[$parser]=array();
918                         $_xh[$parser]['st']='';
919                         $_xh[$parser]['cm']=0;
920                         $_xh[$parser]['isf']=0;
921                         $_xh[$parser]['ac']='';
922                         $_xh[$parser]['qt']='';
923                         $_xh[$parser]['headers'] = array();
925                         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
926                         xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
927                         xml_set_character_data_handler($parser, 'xmlrpc_cd');
928                         xml_set_default_handler($parser, 'xmlrpc_dh');
929                         $xmlrpc_value=new xmlrpcval;
931                         $hdrfnd = 0;
932                         if($this->debug)
933                         {
934                                 //by maHo, replaced htmlspecialchars with htmlentities
935                                 print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
936                         }
938                         if($data == '')
939                         {
940                                 error_log('No response received from server.');
941                                 $r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']);
942                                 xml_parser_free($parser);
943                                 return $r;
944                         }
945                         // see if we got an HTTP 200 OK, else bomb
946                         // but only do this if we're using the HTTP protocol.
947                         if(ereg("^HTTP",$data) && !ereg("^HTTP/[0-9\.]+ 200 ", $data))
948                         {
949                                 $errstr= substr($data, 0, strpos($data, "\n")-1);
950                                 error_log('HTTP error, got response: ' .$errstr);
951                                 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')');
952                                 xml_parser_free($parser);
953                                 return $r;
954                         }
956                         // separate HTTP headers from data
957                         if (ereg("^HTTP", $data))
958                         {
959                                 $ar = split("\r\n", $data);
960                                 while (($line = array_shift($ar)))
961                                 {
962                                         if (strlen($line) < 1)
963                                         {
964                                                 break;
965                                         }
966                                         $_xh[$parser]['headers'][] = $line;
967                                 }
968                                 $data = join("\r\n", $ar);
969                         }
970                                 
971                         if ($this->debug && count($_xh[$parser]['headers']))
972                         {
973                                 print "<PRE>";
974                                 foreach ($_xh[$parser]['headers'] as $header)
975                                 {
976                                         print "HEADER: $header\n";
977                                 }
978                                 print "</PRE>\n";
979                         }
981                         if (!xml_parse($parser, $data, sizeof($data)))
982                         {
983                                 // thanks to Peter Kocks <peter.kocks@baygate.com>
984                                 if((xml_get_current_line_number($parser)) == 1)
985                                 {
986                                         $errstr = 'XML error at line 1, check URL';
987                                 }
988                                 else
989                                 {
990                                         $errstr = sprintf('XML error: %s at line %d',
991                                                 xml_error_string(xml_get_error_code($parser)),
992                                                 xml_get_current_line_number($parser));
993                                                 error_log($errstr);
994                                                 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);
995                                         xml_parser_free($parser);
996                                         echo $errstr;
997                                         return $r;
998                                 }
999                         }
1000                         xml_parser_free($parser);
1001                         if ($this->debug)
1002                         {
1003                                 print "<PRE>---EVALING---[" . 
1004                                 strlen($_xh[$parser]['st']) . " chars]---\n" . 
1005                                 htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";
1006                         }
1007                         if (strlen($_xh[$parser]['st'])==0)
1008                         {
1009                                 // then something odd has happened
1010                                 // and it's time to generate a client side error
1011                                 // indicating something odd went on
1012                                 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
1013                                 $xmlrpcstr['invalid_return']);
1014                         }
1015                         else
1016                         {
1017                                 eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');
1018                                 if ($_xh[$parser]['isf'])
1019                                 {
1020                                         $errno_v = $v->structmem('faultCode');
1021                                         $errstr_v = $v->structmem('faultString');
1022                                         $errno = $errno_v->scalarval();
1024                                         if ($errno == 0)
1025                                         {
1026                                                 // FAULT returned, errno needs to reflect that
1027                                                 $errno = -1;
1028                                         }
1030                                         $r = new xmlrpcresp($v, $errno, $errstr_v->scalarval());
1031                                 }
1032                                 else
1033                                 {
1034                                         $r=new xmlrpcresp($v);
1035                                 }
1036                         }
1038                         $r->hdrs = $_xh[$parser]['headers'];
1039                         return $r;
1040                 }
1041         }
1043         class xmlrpcval
1044         {
1045                 var $me=array();
1046                 var $mytype=0;
1048                 function xmlrpcval($val=-1, $type='')
1049                 {
1050                         $xmlrpcTypes=array(
1051                                 XMLRPCI4       => 1,
1052                                 XMLRPCINT      => 1,
1053                                 XMLRPCBOOLEAN  => 1,
1054                                 XMLRPCDOUBLE   => 1,
1055                                 XMLRPCSTRING   => 1,
1056                                 XMLRPCDATETIME => 1,
1057                                 XMLRPCBASE64   => 1,
1058                                 XMLRPCARRAY    => 2,
1059                                 XMLRPCSTRUCT   => 3
1060                         );
1061         
1062                         $this->me=array();
1063                         $this->mytype=0;
1064                 
1065                         #print_r($val);
1066                         if ($type == '')        {
1067                                         if (gettype($val) == "string") {
1068                                                 $type='string';
1069                                                 $this->addScalar($val,$type);
1070                                         }
1071                                         elseif (gettype($val) == "int") {
1072                                                 $type="int";
1073                                                 $this->addScalar($val,$type);
1074                                         }
1075                                         elseif (gettype($val) == "boolean") {
1076                                                 $type="boolean";
1077                                                 $this->addScalar($val,$type);
1078                                         }
1079                                         elseif (is_array($val)) {
1080                                                 $type="array";
1081                                                 $this->addArray($val);
1082                                         }
1083                                         else {
1084                                                 $type='string';
1085                                                 $this->addScalar($val,$type);
1086                                         }
1087                         }
1088                         else if ($type == "i4") {
1089                                 $val = intval($val);
1090                                 $this->addScalar($val,$type);
1091                         }
1092                         else if ($val!=-1 || $type!='')
1093                         {
1094                                 
1095                                 if ($xmlrpcTypes[$type]==1)
1096                                 {
1097                                         $this->addScalar($val,$type);
1098                                 }
1099                                 elseif ($xmlrpcTypes[$type]==2)
1100                                 {
1101                                         
1102                                         $this->addArray($val);
1103                                 }
1104                                 elseif ($xmlrpcTypes[$type]==3)
1105                                 {
1106                                         $this->addStruct($val);
1107                                 }
1108                         }
1109                 }
1111                 function addScalar($val, $type='string')
1112                 {
1113                         global $xmlrpcTypes, $xmlrpcBoolean;
1115                         if ($this->mytype==1)
1116                         {
1117                                 echo '<B>xmlrpcval</B>: scalar can have only one value<BR>';
1118                                 return 0;
1119                         }
1120                         $typeof=$xmlrpcTypes[$type];
1121                         if ($typeof!=1)
1122                         {
1123                                 echo '<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>';
1124                                 return 0;
1125                         }
1127                         if ($type==$xmlrpcBoolean)
1128                         {
1129                                 if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
1130                                 {
1131                                         $val=1;
1132                                 }
1133                                 else
1134                                 {
1135                                         $val=0;
1136                                 }
1137                         }
1139                         if ($this->mytype==2)
1140                         {
1141                                 // we're adding to an array here
1142                                 $ar=$this->me['array'];
1143                                 $ar[]=new xmlrpcval($val, $type);
1144                                 $this->me['array']=$ar;
1145                         }
1146                         else
1147                         {
1148                                 // a scalar, so set the value and remember we're scalar
1149                                 $this->me[$type]=$val;
1150                                 $this->mytype=$typeof;
1151                         }
1152                         return 1;
1153                 }
1155                 function addArray($vals)
1156                 {
1157                         global $xmlrpcTypes;
1158                         if ($this->mytype!=0)
1159                         {
1160                                 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
1161                                 return 0;
1162                         }
1164                         $this->mytype=$xmlrpcTypes['array'];
1165                         $this->me['array']=$vals;
1166                         return 1;
1167                 }
1169                 function addStruct($vals)
1170                 {
1171                         
1172                         global $xmlrpcTypes;
1173                                 
1174                                 $xmlrpcTypes=array(
1175                                 XMLRPCI4       => 1,
1176                                 XMLRPCINT      => 1,
1177                                 XMLRPCBOOLEAN  => 1,
1178                                 XMLRPCDOUBLE   => 1,
1179                                 XMLRPCSTRING   => 1,
1180                                 XMLRPCDATETIME => 1,
1181                                 XMLRPCBASE64   => 1,
1182                                 XMLRPCARRAY    => 2,
1183                                 XMLRPCSTRUCT   => 3
1184                         );
1185                         if ($this->mytype!=0)
1186                         {
1187                                 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
1188                                 return 0;
1189                         }
1190                         $this->mytype=$xmlrpcTypes['struct'];
1191                         $this->me['struct']=$vals;
1192                         return 1;
1193                 }
1195                 function dump($ar)
1196                 {
1197                         reset($ar);
1198                         while ( list( $key, $val ) = each( $ar ) )
1199                         {
1200                                 echo "$key => $val<br>";
1201                                 if ($key == 'array')
1202                                 {
1203                                         while ( list( $key2, $val2 ) = each( $val ) )
1204                                         {
1205                                                 echo "-- $key2 => $val2<br>";
1206                                         }
1207                                 }
1208                         }
1209                 }
1211                 function kindOf()
1212                 {
1213                         switch($this->mytype)
1214                         {
1215                                 case 3:
1216                                         return 'struct';
1217                                         break;
1218                                 case 2:
1219                                         return 'array';
1220                                         break;
1221                                 case 1:
1222                                         return 'scalar';
1223                                         break;
1224                                 default:
1225                                         return 'undef';
1226                         }
1227                 }
1229                 function serializedata($typ, $val)
1230                 {
1231                         $rs='';
1232                         global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,
1233                         $xmlrpcBoolean;
1234                         switch($xmlrpcTypes[$typ])
1235                         {
1236                                 case 3:
1237                                         // struct
1238                                         $rs.="<struct>\n";
1239                                         reset($val);
1240                                         while(list($key2, $val2)=each($val))
1241                                         {
1242                                                 $rs.="<member><name>${key2}</name>\n";
1243                                                 $rs.=$this->serializeval($val2);
1244                                                 $rs.="</member>\n";
1245                                         }
1246                                         $rs.='</struct>';
1247                                         break;
1248                                 case 2:
1249                                         // array
1250                                         $rs.="<array>\n<data>\n";
1251                                         for($i=0; $i<sizeof($val); $i++) {
1252                                                 $keys = array_keys($val);
1253                                                 $rs.=$this->serializeval($val[$keys[$i]]);
1254                                         }
1255                                         $rs.="</data>\n</array>";
1256                                         break;
1257                                 case 1:
1258                                         switch ($typ)
1259                                         {
1260                                                 case $xmlrpcBase64:
1261                                                         $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
1262                                                         break;
1263                                                 case $xmlrpcBoolean:
1264                                                         $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
1265                                                         break;
1266                                                 case $xmlrpcString:
1267                                                         $rs.="<${typ}>" . @htmlspecialchars($val). "</${typ}>";
1268                                                         break;
1269                                                 default:
1270                                                         $rs.="<${typ}>${val}</${typ}>";
1271                                         }
1272                                         break;
1273                                 default:
1274                                         break;
1275                         }
1276                         return $rs;
1277                 }
1279                 function serialize()
1280                 {
1281                         return $this->serializeval($this);
1282                 }
1284                 function serializeval($o)
1285                 {
1286                         global $xmlrpcTypes;
1287                         $rs='';
1288                         if (is_object($o)) {
1289                           $ar=$o->me;
1290                           list($typ,$val) = each($ar);
1291                         }
1292                         else {
1293                           $ar = $o;     
1294                           if (is_array($ar)) {
1295                             @reset($ar);
1296                             $ak = array_keys($ar);
1297                             if (gettype($ak[0]) == "string" ) {
1298                               $typ = "struct";
1299                               $val = $ar;
1300                             }
1301                             else {
1302                               $typ = "array";
1303                               $val = $ar;
1304                             }
1305                           }
1306                           else {
1307                             $typ = "string";
1308                             $val = $ar; 
1309                           }
1310                         }
1311                         $rs.='<value>';
1312                         $rs.=$this->serializedata($typ, $val);
1313                         $rs.="</value>\n";
1314                         return $rs;
1315                 }
1317                 function structmem($m)
1318                 {
1319                         $nv=$this->me['struct'][$m];
1320                         return $nv;
1321                 }
1323                 function structreset()
1324                 {
1325                         reset($this->me['struct']);
1326                 }
1328                 function structeach()
1329                 {
1330                         return each($this->me['struct']);
1331                 }
1333                 function getval()
1334                 {
1335                         // UNSTABLE
1336                         global $xmlrpcBoolean, $xmlrpcBase64;
1337                         reset($this->me);
1338                         list($a,$b)=each($this->me);
1339                         // contributed by I Sofer, 2001-03-24
1340                         // add support for nested arrays to scalarval
1341                         // i've created a new method here, so as to
1342                         // preserve back compatibility
1344                         if (is_array($b))
1345                         {
1346                                 @reset($b);
1347                                 while(list($id,$cont) = @each($b))
1348                                 {
1349                                         if (is_object($cont) && get_class($cont) == "xmlrpcval") {
1350                                                 $b[$id] = $cont->getval();      
1351                                         }
1352                                         else {
1353                                                 $b[$id] = $cont->scalarval();
1354                                         }
1355                                 }
1356                         }
1358                         // add support for structures directly encoding php objects
1359                         if (is_object($b))
1360                         {
1361                                 $t = get_object_vars($b);
1362                                 @reset($t);
1363                                 while(list($id,$cont) = @each($t))
1364                                 {
1365                                         if (get_class($b) == "xmlrpcval") {
1366                                                 $t[$id] = $cont->getval();      
1367                                         }
1368                                         else {
1369                                                 $t[$id] = $cont->scalarval();
1370                                         }
1371                                 }
1372                                 @reset($t);
1373                                 while(list($id,$cont) = @each($t))
1374                                 {
1375                                         eval('$b->'.$id.' = $cont;');
1376                                 }
1377                         }
1378                         // end contrib
1379                         return $b;
1380                 }
1382                 function scalarval()
1383                 {
1384                         global $xmlrpcBoolean, $xmlrpcBase64;
1385                         reset($this->me);
1386                         list($a,$b)=each($this->me);
1387                         return $b;
1388                 }
1390                 function scalartyp()
1391                 {
1392                         global $xmlrpcI4, $xmlrpcInt;
1393                         reset($this->me);
1394                         list($a,$b)=each($this->me);
1395                         if ($a==$xmlrpcI4)
1396                         {
1397                                 $a=$xmlrpcInt;
1398                         }
1399                         return $a;
1400                 }
1402                 function arraymem($m)
1403                 {
1404                         $nv=$this->me['array'][$m];
1405                         return $nv;
1406                 }
1408                 function arraysize()
1409                 {
1410                         reset($this->me);
1411                         list($a,$b)=each($this->me);
1412                         return sizeof($b);
1413                 }
1414         }
1416         // date helpers
1417         function iso8601_encode($timet, $utc=0)
1418         {
1419                 // return an ISO8601 encoded string
1420                 // really, timezones ought to be supported
1421                 // but the XML-RPC spec says:
1422                 //
1423                 // "Don't assume a timezone. It should be specified by the server in its
1424                 // documentation what assumptions it makes about timezones."
1425                 // 
1426                 // these routines always assume localtime unless 
1427                 // $utc is set to 1, in which case UTC is assumed
1428                 // and an adjustment for locale is made when encoding
1429                 if (!$utc)
1430                 {
1431                         $t=strftime("%Y%m%dT%H:%M:%S", $timet);
1432                 }
1433                 else
1434                 {
1435                         if (function_exists('gmstrftime'))
1436                         {
1437                                 // gmstrftime doesn't exist in some versions
1438                                 // of PHP
1439                                 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
1440                         }
1441                         else
1442                         {
1443                                 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z'));
1444                         }
1445                 }
1446                 return $t;
1447         }
1449         function iso8601_decode($idate, $utc=0)
1450         {
1451                 // return a timet in the localtime, or UTC
1452                 $t=0;
1453                 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs))
1454                 {
1455                         if ($utc)
1456                         {
1457                                 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1458                         }
1459                         else
1460                         {
1461                                 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1462                         }
1463                 } 
1464                 return $t;
1465         }
1467         /****************************************************************
1468         * xmlrpc_decode takes a message in PHP xmlrpc object format and *
1469         * tranlates it into native PHP types.                           *
1470         *                                                               *
1471         * author: Dan Libby (dan@libby.com)                             *
1472         ****************************************************************/
1473         function xmlrpc_decode_php($xmlrpc_val)
1474         {
1475                 $kind = $xmlrpc_val->kindOf();
1477                 if($kind == 'scalar')
1478                 {
1479                         return $xmlrpc_val->scalarval();
1480                 }
1481                 elseif($kind == 'array')
1482                 {
1483                         $size = $xmlrpc_val->arraysize();
1484                         $arr = array();
1486                         for($i = 0; $i < $size; $i++)
1487                         {
1488                                 $arr[]=xmlrpc_decode_php($xmlrpc_val->arraymem($i));
1489                         }
1490                         return $arr; 
1491                 }
1492                 elseif($kind == 'struct')
1493                 {
1494                         $xmlrpc_val->structreset();
1495                         $arr = array();
1497                         while(list($key,$value)=$xmlrpc_val->structeach())
1498                         {
1499                                 $arr[$key] = xmlrpc_decode_php($value);
1500                         }
1501                         return $arr;
1502                 }
1503         }
1505         /****************************************************************
1506         * xmlrpc_encode takes native php types and encodes them into    *
1507         * xmlrpc PHP object format.                                     *
1508         * BUG: All sequential arrays are turned into structs.  I don't  *
1509         * know of a good way to determine if an array is sequential     *
1510         * only.                                                         *
1511         *                                                               *
1512         * feature creep -- could support more types via optional type   *
1513         * argument.                                                     *
1514         *                                                               *
1515         * author: Dan Libby (dan@libby.com)                             *
1516         ****************************************************************/
1517         function xmlrpc_encode_php($php_val)
1518         {
1519                 global $xmlrpcInt;
1520                 global $xmlrpcDouble;
1521                 global $xmlrpcString;
1522                 global $xmlrpcArray;
1523                 global $xmlrpcStruct;
1524                 global $xmlrpcBoolean;
1526                 $type = gettype($php_val);
1527                 $xmlrpc_val = new xmlrpcval;
1529                 switch($type)
1530                 {
1531                         case 'array':
1532                         case 'object':
1533                                 $arr = array();
1534                                 while (list($k,$v) = each($php_val))
1535                                 {
1536                                         $arr[$k] = xmlrpc_encode_php($v);
1537                                 }
1538                                 print_r($php_val);
1539                                 $xmlrpc_val->addStruct($arr);
1540                                 break;
1541                         case 'integer':
1542                                 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
1543                                 break;
1544                         case 'double':
1545                                 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
1546                                 break;
1547                         case 'string':
1548                                 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
1549                                 break;
1550                                 // <G_Giunta_2001-02-29>
1551                                 // Add support for encoding/decoding of booleans, since they are supported in PHP
1552                         case 'boolean':
1553                                 $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
1554                                 break;
1555                                 // </G_Giunta_2001-02-29>
1556                         case 'unknown type':
1557                         default:
1558                                 // giancarlo pinerolo <ping@alt.it>
1559                                 // it has to return 
1560                                 // an empty object in case (which is already
1561                                 // at this point), not a boolean. 
1562                                 break;
1563                 }
1564                 return $xmlrpc_val;
1565         }