OSDN Git Service

Avoid fatal error in parse_bloglist() when the blog is not defined.
[nucleus-jp/nucleus-jp-ancient.git] / utf8 / nucleus / libs / xmlrpc.inc.php
1 <?php                                   // -*-c++-*-
2 // by Edd Dumbill (C) 1999-2002
3 // <edd@usefulinc.com>
4 // $Id: xmlrpc.inc.php,v 1.6 2006-07-12 07:11:47 kimitake Exp $
5 // $NucleusJP: xmlrpc.inc.php,v 1.5 2005/08/13 07:24:44 kimitake Exp $
6
7
8 // Copyright (c) 1999,2000,2002 Edd Dumbill.
9 // All rights reserved.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions
13 // are met:
14 //
15 //    * Redistributions of source code must retain the above copyright
16 //      notice, this list of conditions and the following disclaimer.
17 //
18 //    * Redistributions in binary form must reproduce the above
19 //      copyright notice, this list of conditions and the following
20 //      disclaimer in the documentation and/or other materials provided
21 //      with the distribution.
22 //
23 //    * Neither the name of the "XML-RPC for PHP" nor the names of its
24 //      contributors may be used to endorse or promote products derived
25 //      from this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38 // OF THE POSSIBILITY OF SUCH DAMAGE.
39
40         if (!function_exists('xml_parser_create'))
41         {
42                 // Win 32 fix. From: 'Leo West' <lwest@imaginet.fr>
43                 if($WINDIR)
44                 {
45                         dl('php3_xml.dll');
46                 }
47                 else
48                 {
49                         dl('xml.so');
50                 }
51         }
52
53         // G. Giunta 2005/01/29: declare global these variables,
54         // so that xmlrpc.inc will work even if included from within a function
55         // NB: it will give warnings in PHP3, so we comment it out
56         // Milosch: Next round, maybe we should explicitly request these via $GLOBALS where used.
57         if (phpversion() >= '4')
58         {
59                 global $xmlrpcI4;
60                 global $xmlrpcInt;
61                 global $xmlrpcDouble;
62                 global $xmlrpcBoolean;
63                 global $xmlrpcString;
64                 global $xmlrpcDateTime;
65                 global $xmlrpcBase64;
66                 global $xmlrpcArray;
67                 global $xmlrpcStruct;
68
69                 global $xmlrpcTypes;
70                 global $xmlEntities;
71                 global $xmlrpcerr;
72                 global $xmlrpcstr;
73                 global $xmlrpc_defencoding;
74                 global $xmlrpc_internalencoding;
75                 global $xmlrpcName;
76                 global $xmlrpcVersion;
77                 global $xmlrpcerruser;
78                 global $xmlrpcerrxml;
79                 global $xmlrpc_backslash;
80                 global $_xh;
81         }
82         $xmlrpcI4='i4';
83         $xmlrpcInt='int';
84         $xmlrpcBoolean='boolean';
85         $xmlrpcDouble='double';
86         $xmlrpcString='string';
87         $xmlrpcDateTime='dateTime.iso8601';
88         $xmlrpcBase64='base64';
89         $xmlrpcArray='array';
90         $xmlrpcStruct='struct';
91
92         $xmlrpcTypes=array(
93                 $xmlrpcI4       => 1,
94                 $xmlrpcInt      => 1,
95                 $xmlrpcBoolean  => 1,
96                 $xmlrpcString   => 1,
97                 $xmlrpcDouble   => 1,
98                 $xmlrpcDateTime => 1,
99                 $xmlrpcBase64   => 1,
100                 $xmlrpcArray    => 2,
101                 $xmlrpcStruct   => 3
102         );
103
104         $xmlrpc_valid_parents = array(
105                 'BOOLEAN' => array('VALUE' => 'VALUE'),
106                 'I4' => array('VALUE' => 'VALUE'),
107                 'INT' => array('VALUE' => 'VALUE'),
108                 'STRING' => array('VALUE' => 'VALUE'),
109                 'DOUBLE' => array('VALUE' => 'VALUE'),
110                 'DATETIME.ISO8601' => array('VALUE' => 'VALUE'),
111                 'BASE64' => array('VALUE' => 'VALUE'),
112                 'ARRAY' => array('VALUE' => 'VALUE'),
113                 'STRUCT' => array('VALUE' => 'VALUE'),
114                 'PARAM' => array('PARAMS' => 'PARAMS'),
115                 'METHODNAME' => array('METHODCALL' => 'METHODCALL'),
116                 'PARAMS' => array('METHODCALL' => 'METHODCALL', 'METHODRESPONSE' => 'METHODRESPONSE'),
117                 'MEMBER' => array('STRUCT' => 'STRUCT'),
118                 'NAME' => array('MEMBER' => 'MEMBER'),
119                 'DATA' => array('ARRAY' => 'ARRAY'),
120                 'FAULT' => array('METHODRESPONSE' => 'METHODRESPONSE'),
121                 'VALUE' => array('MEMBER' => 'MEMBER', 'DATA' => 'DATA', 'PARAM' => 'PARAM', 'FAULT' => 'FAULT')
122         );
123
124         $xmlEntities=array(
125                 'amp'  => '&',
126                 'quot' => '"',
127                 'lt'   => '<',
128                 'gt'   => '>',
129                 'apos' => "'"
130         );
131
132         $xmlrpcerr['unknown_method']=1;
133         $xmlrpcstr['unknown_method']='Unknown method';
134         $xmlrpcerr['invalid_return']=2;
135         $xmlrpcstr['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';
136         $xmlrpcerr['incorrect_params']=3;
137         $xmlrpcstr['incorrect_params']='Incorrect parameters passed to method';
138         $xmlrpcerr['introspect_unknown']=4;
139         $xmlrpcstr['introspect_unknown']="Can't introspect: method unknown";
140         $xmlrpcerr['http_error']=5;
141         $xmlrpcstr['http_error']="Didn't receive 200 OK from remote server.";
142         $xmlrpcerr['no_data']=6;
143         $xmlrpcstr['no_data']='No data received from server.';
144         $xmlrpcerr['no_ssl']=7;
145         $xmlrpcstr['no_ssl']='No SSL support compiled in.';
146         $xmlrpcerr['curl_fail']=8;
147         $xmlrpcstr['curl_fail']='CURL error';
148         $xmlrpcerr['invalid_request']=15;
149         $xmlrpcstr['invalid_request']='Invalid request payload';
150
151         $xmlrpcerr['multicall_notstruct'] = 9;
152         $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';
153         $xmlrpcerr['multicall_nomethod']  = 10;
154         $xmlrpcstr['multicall_nomethod']  = 'missing methodName';
155         $xmlrpcerr['multicall_notstring'] = 11;
156         $xmlrpcstr['multicall_notstring'] = 'methodName is not a string';
157         $xmlrpcerr['multicall_recursion'] = 12;
158         $xmlrpcstr['multicall_recursion'] = 'recursive system.multicall forbidden';
159         $xmlrpcerr['multicall_noparams']  = 13;
160         $xmlrpcstr['multicall_noparams']  = 'missing params';
161         $xmlrpcerr['multicall_notarray']  = 14;
162         $xmlrpcstr['multicall_notarray']  = 'params is not an array';
163
164         // The charset encoding expected by the server for received messages and
165         // by the client for received responses
166         $xmlrpc_defencoding='UTF-8';
167         // The encoding used by PHP.
168         // String values received will be converted to this.
169         $xmlrpc_internalencoding='ISO-8859-1';
170
171         $xmlrpcName='XML-RPC for PHP';
172         $xmlrpcVersion='1.2.1';
173
174         // let user errors start at 800
175         $xmlrpcerruser=800;
176         // let XML parse errors start at 100
177         $xmlrpcerrxml=100;
178
179         // formulate backslashes for escaping regexp
180         $xmlrpc_backslash=chr(92).chr(92);
181
182         // used to store state during parsing
183         // quick explanation of components:
184         //   ac - used to accumulate values
185         //   isf - used to indicate a fault
186         //   lv - used to indicate "looking for a value": implements
187         //        the logic to allow values with no types to be strings
188         //   params - used to store parameters in method calls
189         //   method - used to store method name
190         //   stack - array with genealogy of xml elements names:
191         //           used to validate nesting of xmlrpc elements
192
193         $_xh=array();
194
195         /**
196         * To help correct communication of non-ascii chars inside strings, regardless
197         * of the charset used when sending requests, parsing them, sending responses
198         * and parsing responses, convert all non-ascii chars present in the message
199         * into their equivalent 'charset entity'. Charset entities enumerated this way
200         * are independent of the charset encoding used to transmit them, and all XML
201         * parsers are bound to understand them.
202         */
203         function xmlrpc_entity_decode($string)
204         {
205                 $top=split('&', $string);
206                 $op='';
207                 $i=0;
208                 while($i<sizeof($top))
209                 {
210                         if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs))
211                         {
212                                 $op.=ereg_replace("^[#a-zA-Z0-9]+;",
213                                 xmlrpc_lookup_entity($regs[1]),
214                                 $top[$i]);
215                         }
216                         else
217                         {
218                                 if ($i==0)
219                                 {
220                                         $op=$top[$i];
221                                 }
222                                 else
223                                 {
224                                         $op.='&' . $top[$i];
225                                 }
226                         }
227                         $i++;
228                 }
229                 return $op;
230         }
231
232         function xmlrpc_lookup_entity($ent)
233         {
234                 global $xmlEntities;
235
236                 if (isset($xmlEntities[strtolower($ent)]))
237                 {
238                         return $xmlEntities[strtolower($ent)];
239                 }
240                 if (ereg("^#([0-9]+)$", $ent, $regs))
241                 {
242                         return chr($regs[1]);
243                 }
244                 return '?';
245         }
246
247         /**
248          * These entities originate from HTML specs (1.1, proposed 2.0, etc),
249          * and are taken directly from php-4.3.1/ext/mbstring/html_entities.c.
250          * Until php provides functionality to translate these entities in its
251          * core library, use this function.
252          */
253         function xmlrpc_html_entity_xlate($data = '')
254         {
255                 $entities = array(
256                         "&nbsp;" => "&#160;",
257                         "&iexcl;" => "&#161;",
258                         "&cent;" => "&#162;",
259                         "&pound;" => "&#163;",
260                         "&curren;" => "&#164;",
261                         "&yen;" => "&#165;",
262                         "&brvbar;" => "&#166;",
263                         "&sect;" => "&#167;",
264                         "&uml;" => "&#168;",
265                         "&copy;" => "&#169;",
266                         "&ordf;" => "&#170;",
267                         "&laquo;" => "&#171;",
268                         "&not;" => "&#172;",
269                         "&shy;" => "&#173;",
270                         "&reg;" => "&#174;",
271                         "&macr;" => "&#175;",
272                         "&deg;" => "&#176;",
273                         "&plusmn;" => "&#177;",
274                         "&sup2;" => "&#178;",
275                         "&sup3;" => "&#179;",
276                         "&acute;" => "&#180;",
277                         "&micro;" => "&#181;",
278                         "&para;" => "&#182;",
279                         "&middot;" => "&#183;",
280                         "&cedil;" => "&#184;",
281                         "&sup1;" => "&#185;",
282                         "&ordm;" => "&#186;",
283                         "&raquo;" => "&#187;",
284                         "&frac14;" => "&#188;",
285                         "&frac12;" => "&#189;",
286                         "&frac34;" => "&#190;",
287                         "&iquest;" => "&#191;",
288                         "&Agrave;" => "&#192;",
289                         "&Aacute;" => "&#193;",
290                         "&Acirc;" => "&#194;",
291                         "&Atilde;" => "&#195;",
292                         "&Auml;" => "&#196;",
293                         "&Aring;" => "&#197;",
294                         "&AElig;" => "&#198;",
295                         "&Ccedil;" => "&#199;",
296                         "&Egrave;" => "&#200;",
297                         "&Eacute;" => "&#201;",
298                         "&Ecirc;" => "&#202;",
299                         "&Euml;" => "&#203;",
300                         "&Igrave;" => "&#204;",
301                         "&Iacute;" => "&#205;",
302                         "&Icirc;" => "&#206;",
303                         "&Iuml;" => "&#207;",
304                         "&ETH;" => "&#208;",
305                         "&Ntilde;" => "&#209;",
306                         "&Ograve;" => "&#210;",
307                         "&Oacute;" => "&#211;",
308                         "&Ocirc;" => "&#212;",
309                         "&Otilde;" => "&#213;",
310                         "&Ouml;" => "&#214;",
311                         "&times;" => "&#215;",
312                         "&Oslash;" => "&#216;",
313                         "&Ugrave;" => "&#217;",
314                         "&Uacute;" => "&#218;",
315                         "&Ucirc;" => "&#219;",
316                         "&Uuml;" => "&#220;",
317                         "&Yacute;" => "&#221;",
318                         "&THORN;" => "&#222;",
319                         "&szlig;" => "&#223;",
320                         "&agrave;" => "&#224;",
321                         "&aacute;" => "&#225;",
322                         "&acirc;" => "&#226;",
323                         "&atilde;" => "&#227;",
324                         "&auml;" => "&#228;",
325                         "&aring;" => "&#229;",
326                         "&aelig;" => "&#230;",
327                         "&ccedil;" => "&#231;",
328                         "&egrave;" => "&#232;",
329                         "&eacute;" => "&#233;",
330                         "&ecirc;" => "&#234;",
331                         "&euml;" => "&#235;",
332                         "&igrave;" => "&#236;",
333                         "&iacute;" => "&#237;",
334                         "&icirc;" => "&#238;",
335                         "&iuml;" => "&#239;",
336                         "&eth;" => "&#240;",
337                         "&ntilde;" => "&#241;",
338                         "&ograve;" => "&#242;",
339                         "&oacute;" => "&#243;",
340                         "&ocirc;" => "&#244;",
341                         "&otilde;" => "&#245;",
342                         "&ouml;" => "&#246;",
343                         "&divide;" => "&#247;",
344                         "&oslash;" => "&#248;",
345                         "&ugrave;" => "&#249;",
346                         "&uacute;" => "&#250;",
347                         "&ucirc;" => "&#251;",
348                         "&uuml;" => "&#252;",
349                         "&yacute;" => "&#253;",
350                         "&thorn;" => "&#254;",
351                         "&yuml;" => "&#255;",
352                         "&OElig;" => "&#338;",
353                         "&oelig;" => "&#339;",
354                         "&Scaron;" => "&#352;",
355                         "&scaron;" => "&#353;",
356                         "&Yuml;" => "&#376;",
357                         "&fnof;" => "&#402;",
358                         "&circ;" => "&#710;",
359                         "&tilde;" => "&#732;",
360                         "&Alpha;" => "&#913;",
361                         "&Beta;" => "&#914;",
362                         "&Gamma;" => "&#915;",
363                         "&Delta;" => "&#916;",
364                         "&Epsilon;" => "&#917;",
365                         "&Zeta;" => "&#918;",
366                         "&Eta;" => "&#919;",
367                         "&Theta;" => "&#920;",
368                         "&Iota;" => "&#921;",
369                         "&Kappa;" => "&#922;",
370                         "&Lambda;" => "&#923;",
371                         "&Mu;" => "&#924;",
372                         "&Nu;" => "&#925;",
373                         "&Xi;" => "&#926;",
374                         "&Omicron;" => "&#927;",
375                         "&Pi;" => "&#928;",
376                         "&Rho;" => "&#929;",
377                         "&Sigma;" => "&#931;",
378                         "&Tau;" => "&#932;",
379                         "&Upsilon;" => "&#933;",
380                         "&Phi;" => "&#934;",
381                         "&Chi;" => "&#935;",
382                         "&Psi;" => "&#936;",
383                         "&Omega;" => "&#937;",
384                         "&beta;" => "&#946;",
385                         "&gamma;" => "&#947;",
386                         "&delta;" => "&#948;",
387                         "&epsilon;" => "&#949;",
388                         "&zeta;" => "&#950;",
389                         "&eta;" => "&#951;",
390                         "&theta;" => "&#952;",
391                         "&iota;" => "&#953;",
392                         "&kappa;" => "&#954;",
393                         "&lambda;" => "&#955;",
394                         "&mu;" => "&#956;",
395                         "&nu;" => "&#957;",
396                         "&xi;" => "&#958;",
397                         "&omicron;" => "&#959;",
398                         "&pi;" => "&#960;",
399                         "&rho;" => "&#961;",
400                         "&sigmaf;" => "&#962;",
401                         "&sigma;" => "&#963;",
402                         "&tau;" => "&#964;",
403                         "&upsilon;" => "&#965;",
404                         "&phi;" => "&#966;",
405                         "&chi;" => "&#967;",
406                         "&psi;" => "&#968;",
407                         "&omega;" => "&#969;",
408                         "&thetasym;" => "&#977;",
409                         "&upsih;" => "&#978;",
410                         "&piv;" => "&#982;",
411                         "&ensp;" => "&#8194;",
412                         "&emsp;" => "&#8195;",
413                         "&thinsp;" => "&#8201;",
414                         "&zwnj;" => "&#8204;",
415                         "&zwj;" => "&#8205;",
416                         "&lrm;" => "&#8206;",
417                         "&rlm;" => "&#8207;",
418                         "&ndash;" => "&#8211;",
419                         "&mdash;" => "&#8212;",
420                         "&lsquo;" => "&#8216;",
421                         "&rsquo;" => "&#8217;",
422                         "&sbquo;" => "&#8218;",
423                         "&ldquo;" => "&#8220;",
424                         "&rdquo;" => "&#8221;",
425                         "&bdquo;" => "&#8222;",
426                         "&dagger;" => "&#8224;",
427                         "&Dagger;" => "&#8225;",
428                         "&bull;" => "&#8226;",
429                         "&hellip;" => "&#8230;",
430                         "&permil;" => "&#8240;",
431                         "&prime;" => "&#8242;",
432                         "&Prime;" => "&#8243;",
433                         "&lsaquo;" => "&#8249;",
434                         "&rsaquo;" => "&#8250;",
435                         "&oline;" => "&#8254;",
436                         "&frasl;" => "&#8260;",
437                         "&euro;" => "&#8364;",
438                         "&weierp;" => "&#8472;",
439                         "&image;" => "&#8465;",
440                         "&real;" => "&#8476;",
441                         "&trade;" => "&#8482;",
442                         "&alefsym;" => "&#8501;",
443                         "&larr;" => "&#8592;",
444                         "&uarr;" => "&#8593;",
445                         "&rarr;" => "&#8594;",
446                         "&darr;" => "&#8595;",
447                         "&harr;" => "&#8596;",
448                         "&crarr;" => "&#8629;",
449                         "&lArr;" => "&#8656;",
450                         "&uArr;" => "&#8657;",
451                         "&rArr;" => "&#8658;",
452                         "&dArr;" => "&#8659;",
453                         "&hArr;" => "&#8660;",
454                         "&forall;" => "&#8704;",
455                         "&part;" => "&#8706;",
456                         "&exist;" => "&#8707;",
457                         "&empty;" => "&#8709;",
458                         "&nabla;" => "&#8711;",
459                         "&isin;" => "&#8712;",
460                         "&notin;" => "&#8713;",
461                         "&ni;" => "&#8715;",
462                         "&prod;" => "&#8719;",
463                         "&sum;" => "&#8721;",
464                         "&minus;" => "&#8722;",
465                         "&lowast;" => "&#8727;",
466                         "&radic;" => "&#8730;",
467                         "&prop;" => "&#8733;",
468                         "&infin;" => "&#8734;",
469                         "&ang;" => "&#8736;",
470                         "&and;" => "&#8743;",
471                         "&or;" => "&#8744;",
472                         "&cap;" => "&#8745;",
473                         "&cup;" => "&#8746;",
474                         "&int;" => "&#8747;",
475                         "&there4;" => "&#8756;",
476                         "&sim;" => "&#8764;",
477                         "&cong;" => "&#8773;",
478                         "&asymp;" => "&#8776;",
479                         "&ne;" => "&#8800;",
480                         "&equiv;" => "&#8801;",
481                         "&le;" => "&#8804;",
482                         "&ge;" => "&#8805;",
483                         "&sub;" => "&#8834;",
484                         "&sup;" => "&#8835;",
485                         "&nsub;" => "&#8836;",
486                         "&sube;" => "&#8838;",
487                         "&supe;" => "&#8839;",
488                         "&oplus;" => "&#8853;",
489                         "&otimes;" => "&#8855;",
490                         "&perp;" => "&#8869;",
491                         "&sdot;" => "&#8901;",
492                         "&lceil;" => "&#8968;",
493                         "&rceil;" => "&#8969;",
494                         "&lfloor;" => "&#8970;",
495                         "&rfloor;" => "&#8971;",
496                         "&lang;" => "&#9001;",
497                         "&rang;" => "&#9002;",
498                         "&loz;" => "&#9674;",
499                         "&spades;" => "&#9824;",
500                         "&clubs;" => "&#9827;",
501                         "&hearts;" => "&#9829;",
502                         "&diams;" => "&#9830;");
503                 return strtr($data, $entities);
504         }
505
506         function xmlrpc_encode_entitites($data) 
507         {
508                 $length = strlen($data);
509                 $escapeddata = "";
510                 for($position = 0; $position < $length; $position++)
511                 {
512                         $character = substr($data, $position, 1);
513                         $code = Ord($character);
514                         switch($code) {
515                                 case 34:
516                                 $character = "&quot;";
517                                 break;
518                                 case 38:
519                                 $character = "&amp;";
520                                 break;
521                                 case 39:
522                                 $character = "&apos;";
523                                 break;
524                                 case 60:
525                                 $character = "&lt;";
526                                 break;
527                                 case 62:
528                                 $character = "&gt;";
529                                 break;
530                                 default:
531                                 if ($code < 32 || $code > 159)
532                                         $character = ("&#".strval($code).";");
533                                 break;
534                         }
535                         $escapeddata .= $character;
536                 }
537                 return $escapeddata;
538         }
539
540         function xmlrpc_se($parser, $name, $attrs)
541         {
542                 global $_xh, $xmlrpcDateTime, $xmlrpcString, $xmlrpc_valid_parents;
543
544                 // if invalid xmlrpc already detected, skip all processing
545                 if ($_xh[$parser]['isf'] < 2)
546                 {
547
548                 // check for correct element nesting
549                 // top level element can only be of 2 types
550                 if ($_xh[$parser]['sp'] == 0)
551                 {
552                         if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
553                         {
554                                 $_xh[$parser]['isf'] = 2;
555                                 $_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
556                                 return;
557                         }
558                 }
559                 else
560                 {
561                         // not top level element: see if parent is OK
562                         $parent = $_xh[$parser]['stack'][$_xh[$parser]['sp']-1];
563                         if (!isset($xmlrpc_valid_parents[$name][$parent]))
564                         {
565                                 $_xh[$parser]['isf'] = 2;
566                                 $_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of $parent";
567                                 return;
568                         }
569                 }
570
571                 switch($name)
572                 {
573                         case 'STRUCT':
574                         case 'ARRAY':
575                                 //$_xh[$parser]['st'].='array(';
576                                 //$_xh[$parser]['cm']++;
577                                 // this last line turns quoting off
578                                 // this means if we get an empty array we'll
579                                 // simply get a bit of whitespace in the eval
580                                 //$_xh[$parser]['qt']=0;
581
582                                 // create an empty array to hold child values, and push it onto appropriate stack
583                                 $cur_val = array();
584                                 $cur_val['values'] = array();
585                                 $cur_val['type'] = $name;
586                                 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']] = $cur_val;
587                                 $_xh[$parser]['vsp']++;
588                                 break;
589                         case 'METHODNAME':
590                         case 'NAME':
591                                 //$_xh[$parser]['st'].='"';
592                                 $_xh[$parser]['ac']='';
593                                 break;
594                         case 'FAULT':
595                                 $_xh[$parser]['isf']=1;
596                                 break;
597                         case 'PARAM':
598                                 //$_xh[$parser]['st']='';
599                                 // clear value, so we can check later if no value will passed for this param/member
600                                 $_xh[$parser]['value']='';
601                                 break;
602                         case 'VALUE':
603                                 //$_xh[$parser]['st'].='new xmlrpcval(';
604                                 // look for a value: if this is still true by the
605                                 // time we reach the end tag for value then the type is string
606                                 // by implication
607                                 $_xh[$parser]['vt']='value';
608                                 $_xh[$parser]['ac']='';
609                                 //$_xh[$parser]['qt']=0;
610                                 $_xh[$parser]['lv']=1;
611                                 break;
612                         case 'I4':
613                         case 'INT':
614                         case 'STRING':
615                         case 'BOOLEAN':
616                         case 'DOUBLE':
617                         case 'DATETIME.ISO8601':
618                         case 'BASE64':
619                                 if ($_xh[$parser]['vt']!='value')
620                                 {
621                                         //two data elements inside a value: an error occurred!
622                                         $_xh[$parser]['isf'] = 2;
623                                         $_xh[$parser]['isf_reason'] = "$name element following a {$_xh[$parser]['vt']} element inside a single value";
624                                         return;
625                                 }
626
627                                 // reset the accumulator
628                                 $_xh[$parser]['ac']='';
629
630                                 /*if ($name=='DATETIME.ISO8601' || $name=='STRING')
631                                 {
632                                         $_xh[$parser]['qt']=1;
633                                         if ($name=='DATETIME.ISO8601')
634                                         {
635                                                 $_xh[$parser]['vt']=$xmlrpcDateTime;
636                                         }
637                                 }
638                                 elseif ($name=='BASE64')
639                                 {
640                                         $_xh[$parser]['qt']=2;
641                                 }
642                                 else
643                                 {
644                                         // No quoting is required here -- but
645                                         // at the end of the element we must check
646                                         // for data format errors.
647                                         $_xh[$parser]['qt']=0;
648                                 }*/
649                                 break;
650                         case 'MEMBER':
651                                 //$_xh[$parser]['ac']='';
652                                 // avoid warnings later on if no NAME is found before VALUE inside
653                                 // a struct member predefining member name as NULL
654                                 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['name'] = '';
655                                 // clear value, so we can check later if no value will passed for this param/member
656                                 $_xh[$parser]['value']='';
657                                 break;
658                         case 'DATA':
659                         case 'METHODCALL':
660                         case 'METHODRESPONSE':
661                         case 'PARAMS':
662                                 // valid elements that add little to processing
663                                 break;
664                         default:
665                                 /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
666                                 $_xh[$parser]['isf'] = 2;
667                                 $_xh[$parser]['isf_reason'] = "found not-xmlrpc xml element $name";
668                                 break;
669                 }
670
671                 // Save current element name to stack, to validate nesting
672                 $_xh[$parser]['stack'][$_xh[$parser]['sp']] = $name;
673                 $_xh[$parser]['sp']++;
674
675                 if ($name!='VALUE')
676                 {
677                         $_xh[$parser]['lv']=0;
678                 }
679         }
680         }
681
682         function xmlrpc_ee($parser, $name)
683         {
684                 global $_xh,$xmlrpcTypes,$xmlrpcString,$xmlrpcDateTime;
685
686                 if ($_xh[$parser]['isf'] < 2)
687                 {
688
689                 // push this element name from stack
690                 // NB: if XML validates, correct opening/closing is guaranteed and
691                 // we do not have to check for $name == $curr_elem.
692                 // we also checked for proper nesting at start of elements...
693                 $_xh[$parser]['sp']--;
694                 $curr_elem = $_xh[$parser]['stack'][$_xh[$parser]['sp']];
695                 unset($_xh[$parser]['stack'][$_xh[$parser]['sp']]); 
696                 switch($name)
697                 {
698                         case 'STRUCT':
699                         case 'ARRAY':
700                                 //if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')
701                                 //{
702                                 //      $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
703                                 //}
704                                 //$_xh[$parser]['st'].=')';
705
706                                 // fetch out of stack array of values, and promote it to current value
707                                 $_xh[$parser]['vsp']--;
708                                 $cur_val = $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']];
709                                 unset($_xh[$parser]['valuestack'][$_xh[$parser]['vsp']]);
710                                 $_xh[$parser]['value'] = $cur_val['values'];
711
712                                 $_xh[$parser]['vt']=strtolower($name);
713                                 //$_xh[$parser]['cm']--;
714                                 break;
715                         case 'NAME':
716                                 //$_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';
717                                 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['name'] = $_xh[$parser]['ac'];
718                                 break;
719                         case 'BOOLEAN':
720                         case 'I4':
721                         case 'INT':
722                         case 'STRING':
723                         case 'DOUBLE':
724                         case 'DATETIME.ISO8601':
725                         case 'BASE64':
726                                 $_xh[$parser]['vt']=strtolower($name);
727                                 //if ($_xh[$parser]['qt']==1)                   
728                                 if ($name=='STRING')
729                                 {
730                                         // we use double quotes rather than single so backslashification works OK
731                                         //$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
732                                         $_xh[$parser]['value']=$_xh[$parser]['ac'];
733                                 }
734                                 elseif ($name=='DATETIME.ISO8601')
735                                 {
736                                         $_xh[$parser]['vt']=$xmlrpcDateTime;
737                                         $_xh[$parser]['value']=$_xh[$parser]['ac'];
738                                 }
739                                 elseif ($name=='BASE64')
740                                 {
741                                         //$_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';
742
743                                         ///@todo check for failure of base64 decoding / catch warnings
744                                         $_xh[$parser]['value']=base64_decode($_xh[$parser]['ac']);
745                                 }
746                                 elseif ($name=='BOOLEAN')
747                                 {
748                                         // special case here: we translate boolean 1 or 0 into PHP
749                                         // constants true or false
750                                         // NB: this simple checks helps a lot sanitizing input, ie no
751                                         // security problems around here
752
753                                         // [MOD] S. Verberkt (Legolas) (13/02/2006 21:16): Also accept 'true' and 'false'
754                                         if ($_xh[$parser]['ac']=='1' || strcasecmp($_xh[$parser]['ac'], 'true') == 0)
755                                         {
756                                                 //$_xh[$parser]['ac']='true';   
757                                                 $_xh[$parser]['value']=true;
758                                         }
759                                         else
760                                         {
761                                                 //$_xh[$parser]['ac']='false';
762                                                 // log if receiveing something strange, even though we set the value to false anyway
763                                                 if ($_xh[$parser]['ac']!='0' && strcasecmp($_xh[$parser]['ac'], 'false') != 0)
764                                                         error_log('XML-RPC: invalid value received in BOOLEAN: '.$_xh[$parser]['ac']);
765                                                 $_xh[$parser]['value']=false;
766                                         }
767                                         // [/MOD]
768
769                                         //$_xh[$parser]['st'].=$_xh[$parser]['ac'];
770                                 }
771                                 elseif ($name=='DOUBLE')
772                                 {
773                                         // we have a DOUBLE
774                                         // we must check that only 0123456789-.<space> are characters here
775                                         if (!ereg("^[+-]?[eE0123456789 \\t\\.]+$", $_xh[$parser]['ac']))
776                                         {
777                                                 // TODO: find a better way of throwing an error
778                                                 // than this!
779                                                 error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']);
780                                                 //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
781                                                 $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';
782                                         }
783                                         else
784                                         {
785                                                 // it's ok, add it on
786                                                 //$_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];
787                                                 $_xh[$parser]['value']=(double)$_xh[$parser]['ac'];
788                                         }
789                                 }
790                                 else
791                                 {
792                                         // we have an I4/INT
793                                         // we must check that only 0123456789-<space> are characters here
794                                         if (!ereg("^[+-]?[0123456789 \\t]+$", $_xh[$parser]['ac']))
795                                         {
796                                                 // TODO: find a better way of throwing an error
797                                                 // than this!
798                                                 error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']);
799                                                 //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
800                                                 $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';
801                                         }
802                                         else
803                                         {
804                                                 // it's ok, add it on
805                                                 //$_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];
806                                                 $_xh[$parser]['value']=(int)$_xh[$parser]['ac'];
807                                         }
808                                 }
809                                 $_xh[$parser]['ac']='';
810                                 //$_xh[$parser]['qt']=0;
811                                 $_xh[$parser]['lv']=3; // indicate we've found a value
812                                 break;
813                         case 'VALUE':
814                                 // This if() detects if no scalar was inside <VALUE></VALUE>
815                                 if ($_xh[$parser]['vt']=='value')
816                                 {
817                                         $_xh[$parser]['value']=$_xh[$parser]['ac'];
818                                         $_xh[$parser]['vt']=$xmlrpcString;
819                                 }
820                                 /*if (strlen($_xh[$parser]['ac'])>0 &&
821                                         $_xh[$parser]['vt']==$xmlrpcString)
822                                 {
823                                         $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
824                                 }
825                                 // This if() detects if no scalar was inside <VALUE></VALUE>
826                                 // and pads an empty ''.
827                                 if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(')
828                                 {
829                                         $_xh[$parser]['st'].= '""';
830                                 }
831                                 // G. Giunta 2005/03/12 save some chars in the reconstruction of string vals...
832                                 if ($_xh[$parser]['vt'] != $xmlrpcString)
833                                         $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
834                                 else
835                                         $_xh[$parser]['st'].=")";
836                                 if ($_xh[$parser]['cm'])
837                                 {
838                                         $_xh[$parser]['st'].=',';
839                                 }*/
840
841                                 // build the xmlrpc val out of the data received, and substitute it
842                                 $temp = new xmlrpcval($_xh[$parser]['value'], $_xh[$parser]['vt']);
843                                 // check if we are inside an array or struct:
844                                 // if value just built is inside an array, let's move it into array on the stack
845                                 if ($_xh[$parser]['vsp'] && $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['type']=='ARRAY')
846                                 {
847                                         $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['values'][] = $temp;
848                                 }
849                                 else
850                                 {
851                                 $_xh[$parser]['value'] = $temp;
852                                 }
853                                 break;
854                         case 'MEMBER':
855                                 $_xh[$parser]['ac']='';
856                                 //$_xh[$parser]['qt']=0;
857                                 // add to array in the stack the last element built
858                                 // unless no VALUE was found
859                                 if ($_xh[$parser]['value'])
860                                 {
861                                         $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['values'][$_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['name']] = $_xh[$parser]['value'];
862                                 }
863                                 else
864                                         error_log('XML-RPC: missing VALUE inside STRUCT in received xml');
865                                 break;
866                         case 'DATA':
867                                 $_xh[$parser]['ac']='';
868                                 //$_xh[$parser]['qt']=0;
869                                 break;
870                         case 'PARAM':
871                                 //$_xh[$parser]['params'][]=$_xh[$parser]['st'];
872                                 if ($_xh[$parser]['value'])
873                                         $_xh[$parser]['params'][]=$_xh[$parser]['value'];
874                                 else
875                                         error_log('XML-RPC: missing VALUE inside PARAM in received xml');
876                                 break;
877                         case 'METHODNAME':
878                                 $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);
879                                 break;
880                         case 'PARAMS':
881                         case 'FAULT':
882                         case 'METHODCALL':
883                         case 'METHORESPONSE':
884                                 break;
885                         default:
886                                 // End of INVALID ELEMENT!
887                                 // shall we add an assert here for unreachable code???
888                                 break;
889                 }
890                 // if it's a valid type name, set the type
891                 /*if (isset($xmlrpcTypes[strtolower($name)]))
892                 {
893                         $_xh[$parser]['vt']=strtolower($name);
894                 }*/
895
896                 }
897         }
898
899         function xmlrpc_cd($parser, $data)
900         {
901                 global $_xh, $xmlrpc_backslash;
902
903                 //if (ereg("^[\n\r \t]+$", $data)) return;
904                 // print "adding [${data}]\n";
905
906                 // skip processing if xml fault already detected
907                 if ($_xh[$parser]['isf'] < 2)
908                 {
909                 if ($_xh[$parser]['lv']!=3)
910                 {
911                         // "lookforvalue==3" means that we've found an entire value
912                         // and should discard any further character data
913                         if ($_xh[$parser]['lv']==1)
914                         {
915                                 // if we've found text and we're just in a <value> then
916                                 // turn quoting on, as this will be a string
917                                         //$_xh[$parser]['qt']=1;
918                                 // and say we've found a value
919                                 $_xh[$parser]['lv']=2;
920                         }
921                         if(!@isset($_xh[$parser]['ac']))
922                         {
923                                 $_xh[$parser]['ac'] = '';
924                         }
925                                 //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
926                                 $_xh[$parser]['ac'].=$data;
927                         }
928                 }
929         }
930
931         function xmlrpc_dh($parser, $data)
932         {
933                 global $_xh, $xmlrpc_backslash;
934
935                 // skip processing if xml fault already detected
936                 if ($_xh[$parser]['isf'] < 2)
937                 {
938                 if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
939                 {
940                         if ($_xh[$parser]['lv']==1)
941                         {
942                                         //$_xh[$parser]['qt']=1;
943                                 $_xh[$parser]['lv']=2;
944                         }
945                                 //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
946                                 $_xh[$parser]['ac'].=$data;
947                         }
948                 }
949         }
950
951         class xmlrpc_client
952         {
953                 var $path;
954                 var $server;
955                 var $port;
956                 var $errno;
957                 var $errstr;
958                 var $debug=0;
959                 var $username='';
960                 var $password='';
961                 var $cert='';
962                 var $certpass='';
963                 var $verifypeer=1;
964                 var $verifyhost=1;
965                 var $no_multicall=false;
966
967                 function xmlrpc_client($path, $server, $port=0)
968                 {
969                         $this->port=$port; $this->server=$server; $this->path=$path;
970                 }
971
972                 function setDebug($in)
973                 {
974                         if ($in)
975                         {
976                                 $this->debug=1;
977                         }
978                         else
979                         {
980                                 $this->debug=0;
981                         }
982                 }
983
984                 function setCredentials($u, $p)
985                 {
986                         $this->username=$u;
987                         $this->password=$p;
988                 }
989
990                 function setCertificate($cert, $certpass)
991                 {
992                         $this->cert = $cert;
993                         $this->certpass = $certpass;
994                 }
995
996                 function setSSLVerifyPeer($i)
997                 {
998                         $this->verifypeer = $i;
999                 }
1000
1001                 function setSSLVerifyHost($i)
1002                 {
1003                         $this->verifyhost = $i;
1004                 }
1005
1006                 function send($msg, $timeout=0, $method='http')
1007                 {
1008                         if (is_array($msg))
1009                         {
1010                                 // $msg is an array of xmlrpcmsg's
1011                                 return $this->multicall($msg, $timeout, $method);
1012                         }
1013
1014                         // where msg is an xmlrpcmsg
1015                         $msg->debug=$this->debug;
1016
1017                         if ($method == 'https')
1018                         {
1019                                 return $this->sendPayloadHTTPS($msg,
1020                                 $this->server,
1021                                 $this->port, $timeout,
1022                                 $this->username, $this->password,
1023                                 $this->cert,
1024                                 $this->certpass);
1025                         }
1026                         else
1027                         {
1028                                 return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
1029                                 $timeout, $this->username, 
1030                                 $this->password);
1031                         }
1032                 }
1033
1034                 function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
1035                 {
1036                         global $xmlrpcerr, $xmlrpcstr, $xmlrpcName, $xmlrpcVersion, $xmlrpc_defencoding;
1037                         if ($port==0)
1038                         {
1039                                 $port=80;
1040                         }
1041                         if($timeout>0)
1042                         {
1043                                 $fp=@fsockopen($server, $port,$this->errno, $this->errstr, $timeout);
1044                         }
1045                         else
1046                         {
1047                                 $fp=@fsockopen($server, $port,$this->errno, $this->errstr);
1048                         }
1049                         if ($fp)
1050                         {
1051                                 if ($timeout>0 && function_exists('stream_set_timeout'))
1052                                         stream_set_timeout($fp, $timeout);
1053                         }
1054                         else
1055                         {
1056                                 $this->errstr='Connect error';
1057                                 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']);
1058                                 return $r;
1059                         }
1060                         // Only create the payload if it was not created previously
1061                         if(empty($msg->payload))
1062                         {
1063                                 $msg->createPayload();
1064                         }
1065
1066                         // thanks to Grant Rauscher <grant7@firstworld.net>
1067                         // for this
1068                         $credentials='';
1069                         if ($username!='')
1070                         {
1071                                 $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
1072                         }
1073
1074                         $op= "POST " . $this->path. " HTTP/1.0\r\n" .
1075                                 "User-Agent: " . $xmlrpcName . " " . $xmlrpcVersion . "\r\n" .
1076                                 "Host: ". $server . "\r\n" .
1077                                 $credentials . 
1078                                 "Accept-Charset: " . $xmlrpc_defencoding . "\r\n" .
1079                                 "Content-Type: text/xml\r\nContent-Length: " .
1080                                 strlen($msg->payload) . "\r\n\r\n" .
1081                                 $msg->payload;
1082
1083                         if (!fputs($fp, $op, strlen($op)))
1084                         {
1085                                 $this->errstr='Write error';
1086                                 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']);
1087                                 return $r;
1088                         }
1089                         $resp=$msg->parseResponseFile($fp);
1090                         fclose($fp);
1091                         return $resp;
1092                 }
1093
1094                 // contributed by Justin Miller <justin@voxel.net>
1095                 // requires curl to be built into PHP
1096                 function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='')
1097                 {
1098                         global $xmlrpcerr, $xmlrpcstr, $xmlrpcVersion, $xmlrpc_internalencoding;
1099                         if ($port == 0)
1100                         {
1101                                 $port = 443;
1102                         }
1103
1104                         // Only create the payload if it was not created previously
1105                         if(empty($msg->payload))
1106                         {
1107                                 $msg->createPayload();
1108                         }
1109
1110                         if (!function_exists('curl_init'))
1111                         {
1112                                 $this->errstr='SSL unavailable on this install';
1113                                 $r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']);
1114                                 return $r;
1115                         }
1116
1117                         $curl = curl_init('https://' . $server . ':' . $port . $this->path);
1118
1119                         curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
1120                         // results into variable
1121                         if ($this->debug)
1122                         {
1123                                 curl_setopt($curl, CURLOPT_VERBOSE, 1);
1124                         }
1125                         curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC '.$xmlrpcVersion);
1126                         // required for XMLRPC
1127                         curl_setopt($curl, CURLOPT_POST, 1);
1128                         // post the data
1129                         curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
1130                         // the data
1131                         curl_setopt($curl, CURLOPT_HEADER, 1);
1132                         // return the header too
1133                         curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml', 'Accept-Charset: '.$xmlrpc_internalencoding));
1134                         // whether to verify remote host's cert
1135                         curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
1136                         // 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
1137                         curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
1138                         // required for XMLRPC
1139                         if ($timeout)
1140                         {
1141                                 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
1142                         }
1143                         // timeout is borked
1144                         if ($username && $password)
1145                         {
1146                                 curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
1147                         }
1148                         // set auth stuff
1149                         if ($cert)
1150                         {
1151                                 curl_setopt($curl, CURLOPT_SSLCERT, $cert);
1152                         }
1153                         // set cert file
1154                         if ($certpass)
1155                         {
1156                                 curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass);
1157                         }
1158                         // set cert password
1159
1160                         $result = curl_exec($curl);
1161
1162                         if (!$result)
1163                         {
1164                                 $this->errstr='no response';
1165                                 $resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl));
1166                                 curl_close($curl);
1167                         }
1168                         else
1169                         {
1170                                 curl_close($curl);
1171                                 $resp = $msg->parseResponse($result);
1172                         }
1173                         return $resp;
1174                 }
1175
1176                 function multicall($msgs, $timeout=0, $method='http')
1177                 {
1178                         $results = false;
1179
1180                         if (! $this->no_multicall)
1181                         {
1182                                 $results = $this->_try_multicall($msgs, $timeout, $method);
1183                                 /* TODO - this is not php3-friendly */
1184                                 // if($results !== false)
1185                                 if(is_array($results))
1186                                 {
1187                                         // Either the system.multicall succeeded, or the send
1188                                         // failed (e.g. due to HTTP timeout). In either case,
1189                                         // we're done for now.
1190                                         return $results;
1191                                 }
1192                                 else
1193                                 {
1194                                         // system.multicall unsupported by server,
1195                                         // don't try it next time...
1196                                         $this->no_multicall = true;
1197                                 }
1198                         }
1199
1200                         // system.multicall is unupported by server:
1201                         //   Emulate multicall via multiple requests
1202                         $results = array();
1203                         //foreach($msgs as $msg)
1204                         @reset($msgs);
1205                         while(list(,$msg) = @each($msgs))
1206                         {
1207                                 $results[] = $this->send($msg, $timeout, $method);
1208                         }
1209                         return $results;
1210                 }
1211
1212                 // Attempt to boxcar $msgs via system.multicall.
1213                 function _try_multicall($msgs, $timeout, $method)
1214                 {
1215                         // Construct multicall message
1216                         $calls = array();
1217                         //foreach($msgs as $msg)
1218                         @reset($msgs);
1219                         while(list(,$msg) = @each($msgs))
1220                         {
1221                                 $call['methodName'] = new xmlrpcval($msg->method(),'string');
1222                                 $numParams = $msg->getNumParams();
1223                                 $params = array();
1224                                 for ($i = 0; $i < $numParams; $i++)
1225                                 {
1226                                         $params[$i] = $msg->getParam($i);
1227                                 }
1228                                 $call['params'] = new xmlrpcval($params, 'array');
1229                                 $calls[] = new xmlrpcval($call, 'struct');
1230                         }
1231                         $multicall = new xmlrpcmsg('system.multicall');
1232                         $multicall->addParam(new xmlrpcval($calls, 'array'));
1233
1234                         // Attempt RPC call
1235                         $result = $this->send($multicall, $timeout, $method);
1236                         if(!is_object($result))
1237                         {
1238                                 return ($result || 0); // transport failed
1239                         }
1240
1241                         if($result->faultCode() != 0)
1242                         {
1243                                 return false;           // system.multicall failed
1244                         }
1245
1246                         // Unpack responses.
1247                         $rets = $result->value();
1248                         if($rets->kindOf() != 'array')
1249                         {
1250                                 return false;           // bad return type from system.multicall
1251                         }
1252                         $numRets = $rets->arraysize();
1253                         if($numRets != count($msgs))
1254                         {
1255                                 return false;           // wrong number of return values.
1256                         }
1257
1258                         $response = array();
1259                         for ($i = 0; $i < $numRets; $i++)
1260                         {
1261                                 $val = $rets->arraymem($i);
1262                                 switch ($val->kindOf())
1263                                 {
1264                                 case 'array':
1265                                         if($val->arraysize() != 1)
1266                                         {
1267                                                 return false;           // Bad value
1268                                         }
1269                                         // Normal return value
1270                                         $response[$i] = new xmlrpcresp($val->arraymem(0));
1271                                         break;
1272                                 case 'struct':
1273                                         $code = $val->structmem('faultCode');
1274                                         if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
1275                                         {
1276                                                 return false;
1277                                         }
1278                                         $str = $val->structmem('faultString');
1279                                         if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
1280                                         {
1281                                                 return false;
1282                                         }
1283                                         $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
1284                                         break;
1285                                 default:
1286                                         return false;
1287                                 }
1288                         }
1289                         return $response;
1290                 }
1291         } // end class xmlrpc_client
1292
1293         class xmlrpcresp
1294         {
1295                 var $val = 0;
1296                 var $errno = 0;
1297                 var $errstr = '';
1298                 var $hdrs = array();
1299
1300                 function xmlrpcresp($val, $fcode = 0, $fstr = '')
1301                 {
1302                         if ($fcode != 0)
1303                         {
1304                                 // error
1305                                 $this->errno = $fcode;
1306                                 $this->errstr = $fstr;
1307                                 //$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
1308                         }
1309                         elseif (!is_object($val))
1310                         {
1311                                 // programmer error
1312                                 error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value.");
1313                                 $this->val = new xmlrpcval();
1314                         }
1315                         else
1316                         {
1317                                 // success
1318                                 $this->val = $val;
1319                         }
1320                 }
1321
1322                 function faultCode()
1323                 {
1324                         return $this->errno;
1325                 }
1326
1327                 function faultString()
1328                 {
1329                         return $this->errstr;
1330                 }
1331
1332                 function value()
1333                 {
1334                         return $this->val;
1335                 }
1336
1337                 function serialize()
1338                 {
1339                         $result = "<methodResponse>\n";
1340                         if ($this->errno)
1341                         {
1342                                 // G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients
1343                                 $result .= '<fault>
1344 <value>
1345 <struct>
1346 <member>
1347 <name>faultCode</name>
1348 <value><int>' . $this->errno . '</int></value>
1349 </member>
1350 <member>
1351 <name>faultString</name>
1352 <value><string>' . xmlrpc_encode_entitites($this->errstr) . '</string></value>
1353 </member>
1354 </struct>
1355 </value>
1356 </fault>';
1357                         }
1358                         else
1359                         {
1360                                 $result .= "<params>\n<param>\n" .
1361                                         $this->val->serialize() . 
1362                                         "</param>\n</params>";
1363                         }
1364                         $result .= "\n</methodResponse>";
1365                         return $result;
1366                 }
1367         }
1368
1369         class xmlrpcmsg
1370         {
1371                 var $payload;
1372                 var $methodname;
1373                 var $params=array();
1374                 var $debug=0;
1375
1376                 function xmlrpcmsg($meth, $pars=0)
1377                 {
1378                         $this->methodname=$meth;
1379                         if (is_array($pars) && sizeof($pars)>0)
1380                         {
1381                                 for($i=0; $i<sizeof($pars); $i++)
1382                                 {
1383                                         $this->addParam($pars[$i]);
1384                                 }
1385                         }
1386                 }
1387
1388                 function xml_header()
1389                 {
1390                         return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
1391                 }
1392
1393                 function xml_footer()
1394                 {
1395                         return "</methodCall>\n";
1396                 }
1397
1398                 function createPayload()
1399                 {
1400                         $this->payload=$this->xml_header();
1401                         $this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
1402                         //      if (sizeof($this->params)) {
1403                         $this->payload.="<params>\n";
1404                         for($i=0; $i<sizeof($this->params); $i++)
1405                         {
1406                                 $p=$this->params[$i];
1407                                 $this->payload.="<param>\n" . $p->serialize() .
1408                                 "</param>\n";
1409                         }
1410                         $this->payload.="</params>\n";
1411                         // }
1412                         $this->payload.=$this->xml_footer();
1413                         //$this->payload=str_replace("\n", "\r\n", $this->payload);
1414                 }
1415
1416                 function method($meth='')
1417                 {
1418                         if ($meth!='')
1419                         {
1420                                 $this->methodname=$meth;
1421                         }
1422                         return $this->methodname;
1423                 }
1424
1425                 function serialize()
1426                 {
1427                         $this->createPayload();
1428                         return $this->payload;
1429                 }
1430
1431                 function addParam($par) { $this->params[]=$par; }
1432                 function getParam($i) { return $this->params[$i]; }
1433                 function getNumParams() { return sizeof($this->params); }
1434
1435                 function parseResponseFile($fp)
1436                 {
1437                         $ipd='';
1438                         while($data=fread($fp, 32768))
1439                         {
1440                                 $ipd.=$data;
1441                         }
1442                         return $this->parseResponse($ipd);
1443                 }
1444
1445                 function parseResponse($data='')
1446                 {
1447                         global $_xh,$xmlrpcerr,$xmlrpcstr;
1448                         global $xmlrpc_defencoding, $xmlrpc_internalencoding;
1449
1450                         $hdrfnd = 0;
1451                         if($this->debug)
1452                         {
1453                                 //by maHo, replaced htmlspecialchars with htmlentities
1454                                 print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
1455                         }
1456
1457                         if($data == '')
1458                         {
1459                                 error_log('No response received from server.');
1460                                 $r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']);
1461                                 return $r;
1462                         }
1463                         // see if we got an HTTP 200 OK, else bomb
1464                         // but only do this if we're using the HTTP protocol.
1465                         if(ereg("^HTTP",$data))
1466                         {
1467                                 // Strip HTTP 1.1 100 Continue header if present
1468                                 while (ereg('^HTTP/1.1 1[0-9]{2}', $data))
1469                                 {
1470                                         $pos = strpos($data, 'HTTP', 12);
1471                                         // server sent a Continue header without any (valid) content following...
1472                                         // give the client a chance to know it
1473                                         if (!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
1474                                                 break;
1475                                         $data = substr($data, $pos);
1476                                 }
1477                                 if (!ereg("^HTTP/[0-9\\.]+ 200 ", $data))
1478                                 {
1479                                         $errstr= substr($data, 0, strpos($data, "\n")-1);
1480                                         error_log('HTTP error, got response: ' .$errstr);
1481                                         $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')');
1482                                         return $r;
1483                                 }
1484                         }
1485                         $parser = xml_parser_create($xmlrpc_defencoding);
1486
1487                         // G. Giunta 2004/04/06
1488                         // Clean up the accumulator, or it will grow indefinitely long
1489                         // if making xmlrpc calls for a while
1490                         $_xh=array();
1491                         $_xh[$parser]=array();
1492                         $_xh[$parser]['headers'] = array();
1493                         $_xh[$parser]['stack'] = array();
1494                         $_xh[$parser]['sp'] = 0;
1495                         $_xh[$parser]['valuestack'] = array();
1496                         $_xh[$parser]['vsp'] = 0;
1497
1498                         // separate HTTP headers from data
1499                         if (ereg("^HTTP", $data))
1500                         {
1501                                 // be tolerant to usage of \n instead of \r\n to separate headers and data
1502                                 // (even though it is not valid http)
1503                                 $pos = strpos($data,"\r\n\r\n");
1504                                 if($pos || is_int($pos))
1505                                         $bd = $pos+4;
1506                                 else
1507                                 {
1508                                         $pos = strpos($data,"\n\n");
1509                                         if($pos || is_int($pos))
1510                                                 $bd = $pos+2;
1511                                         else
1512                                         {
1513                                                 // No separation between response headers and body: fault?
1514                                                 $bd = 0;
1515                                         }
1516                                 }
1517                                 // be tolerant to line endings, and extra empty lines
1518                                 $ar = split("\r?\n", trim(substr($data, 0, $pos)));
1519                                 while (list(,$line) = @each($ar))
1520                                 {
1521                                         // take care of multi-line headers
1522                                         $arr = explode(':',$line);
1523                                         if(count($arr) > 1)
1524                                         {
1525                                                 $header_name = trim($arr[0]);
1526                                                 // TO DO: some headers (the ones that allow a CSV list of values)
1527                                                 // do allow many values to be passed using multiple header lines.
1528                                                 // We should add content to $_xh[$parser]['headers'][$header_name]
1529                                                 // instead of replacing it for those...
1530                                                 $_xh[$parser]['headers'][$header_name] = $arr[1];
1531                                                 for ($i = 2; $i < count($arr); $i++)
1532                                                 {
1533                                                         $_xh[$parser]['headers'][$header_name] .= ':'.$arr[$i];
1534                                                 } // while
1535                                                 $_xh[$parser]['headers'][$header_name] = trim($_xh[$parser]['headers'][$header_name]);
1536                                         } else if (isset($header_name))
1537                                         {
1538                                                 $_xh[$parser]['headers'][$header_name] .= ' ' . trim($line);
1539                                         }
1540                                 }
1541                                 $data = substr($data, $bd);
1542
1543                                 if ($this->debug && count($_xh[$parser]['headers']))
1544                                 {
1545                                         print '<PRE>';
1546                                         //foreach ($_xh[$parser]['headers'] as $header)
1547                                         @reset($_xh[$parser]['headers']);
1548                                         while(list($header, $value) = @each($_xh[$parser]['headers']))
1549                                         {
1550                                                 print "HEADER: $header: $value\n";
1551                                         }
1552                                         print "</PRE>\n";
1553                                 }
1554                         }
1555
1556                         // be tolerant of extra whitespace in response body
1557                         $data = trim($data);
1558
1559                         // be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
1560                         // idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
1561                         $bd = false;
1562                         $pos = strpos($data, "</methodResponse>");
1563                         while ($pos || is_int($pos))
1564                         {
1565                                 $bd = $pos+17;
1566                                 $pos = strpos($data, "</methodResponse>", $bd);
1567                         }
1568                         if ($bd)
1569                                 $data = substr($data, 0, $bd);
1570
1571                         //$_xh[$parser]['st']='';
1572                         //$_xh[$parser]['cm']=0;
1573                         $_xh[$parser]['isf']=0;
1574                         $_xh[$parser]['isf_reason']=0;
1575                         $_xh[$parser]['ac']='';
1576                         //$_xh[$parser]['qt']='';
1577
1578                         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
1579                         // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
1580                         // the xml parser to give us back data in the expected charset
1581                         xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding);
1582
1583                         xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
1584                         xml_set_character_data_handler($parser, 'xmlrpc_cd');
1585                         xml_set_default_handler($parser, 'xmlrpc_dh');
1586                         //$xmlrpc_value=new xmlrpcval;
1587
1588                         if (!xml_parse($parser, $data, sizeof($data)))
1589                         {
1590                                 // thanks to Peter Kocks <peter.kocks@baygate.com>
1591                                 if((xml_get_current_line_number($parser)) == 1)
1592                                 {
1593                                         $errstr = 'XML error at line 1, check URL';
1594                                 }
1595                                 else
1596                                 {
1597                                         $errstr = sprintf('XML error: %s at line %d',
1598                                                 xml_error_string(xml_get_error_code($parser)),
1599                                                 xml_get_current_line_number($parser));
1600                                 }
1601                                 error_log($errstr);
1602                                 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return'].' ('.$errstr.')');
1603                                 xml_parser_free($parser);
1604                                 if ($this->debug)
1605                                         echo $errstr;
1606                                 $r->hdrs = $_xh[$parser]['headers'];
1607                                 return $r;
1608                         }
1609                         xml_parser_free($parser);
1610
1611                         if ($_xh[$parser]['isf'] > 1)
1612                         {
1613                         if ($this->debug)
1614                         {
1615                                         ///@todo echo something for user?
1616                                 }
1617
1618                                 $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
1619                                 $xmlrpcstr['invalid_return'] . ' ' . $_xh[$parser]['isf_reason']);
1620                         }
1621                         //else if (strlen($_xh[$parser]['st'])==0)
1622                         else if (!is_object($_xh[$parser]['value']))
1623                         {
1624                                 // then something odd has happened
1625                                 // and it's time to generate a client side error
1626                                 // indicating something odd went on
1627                                 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
1628                                 $xmlrpcstr['invalid_return']);
1629                         }
1630                         else
1631                         {
1632
1633                                 if ($this->debug)
1634                                 {
1635                                         //print "<PRE>---EVALING---[" .
1636                                         //strlen($_xh[$parser]['st']) . " chars]---\n" .
1637                                         //htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";
1638                                         print "<PRE>---PARSED---\n" ;
1639                                         var_dump($_xh[$parser]['value']);
1640                                         print "\n---END---</PRE>";
1641                                 }
1642
1643                                 //$allOK=0;
1644                                 //@eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');
1645                                 //if (!$allOK)
1646                                 //{
1647                                 //      $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);
1648                                 //}
1649                                 //else
1650                                 $v = $_xh[$parser]['value'];
1651                                 if ($_xh[$parser]['isf'])
1652                                 {
1653                                         $errno_v = $v->structmem('faultCode');
1654                                         $errstr_v = $v->structmem('faultString');
1655                                         $errno = $errno_v->scalarval();
1656
1657                                         if ($errno == 0)
1658                                         {
1659                                                 // FAULT returned, errno needs to reflect that
1660                                                 $errno = -1;
1661                                         }
1662
1663                                         $r = new xmlrpcresp($v, $errno, $errstr_v->scalarval());
1664                                 }
1665                                 else
1666                                 {
1667                                         $r=new xmlrpcresp($v);
1668                                 }
1669                         }
1670
1671                         $r->hdrs = $_xh[$parser]['headers'];
1672                         return $r;
1673                 }
1674         }
1675
1676         class xmlrpcval
1677         {
1678                 var $me=array();
1679                 var $mytype=0;
1680
1681                 function xmlrpcval($val=-1, $type='')
1682                 {
1683                         global $xmlrpcTypes;
1684                         $this->me=array();
1685                         $this->mytype=0;
1686                         if ($val!=-1 || !is_int($val) || $type!='')
1687                         {
1688                                 if ($type=='')
1689                                 {
1690                                         $type='string';
1691                                 }
1692                                 if ($xmlrpcTypes[$type]==1)
1693                                 {
1694                                         $this->addScalar($val,$type);
1695                                 }
1696                                 elseif ($xmlrpcTypes[$type]==2)
1697                                 {
1698                                         $this->addArray($val);
1699                                 }
1700                                 elseif ($xmlrpcTypes[$type]==3)
1701                                 {
1702                                         $this->addStruct($val);
1703                                 }
1704                         }
1705                 }
1706
1707                 function addScalar($val, $type='string')
1708                 {
1709                         global $xmlrpcTypes, $xmlrpcBoolean;
1710
1711                         if ($this->mytype==1)
1712                         {
1713                                 echo '<B>xmlrpcval</B>: scalar can have only one value<BR>';
1714                                 return 0;
1715                         }
1716                         $typeof=$xmlrpcTypes[$type];
1717                         if ($typeof!=1)
1718                         {
1719                                 echo '<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>';
1720                                 return 0;
1721                         }
1722
1723                         if ($type==$xmlrpcBoolean)
1724                         {
1725                                 if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
1726                                 {
1727                                         $val=1;
1728                                 }
1729                                 else
1730                                 {
1731                                         $val=0;
1732                                 }
1733                         }
1734
1735                         if ($this->mytype==2)
1736                         {
1737                                 // we're adding to an array here
1738                                 $ar=$this->me['array'];
1739                                 $ar[]=new xmlrpcval($val, $type);
1740                                 $this->me['array']=$ar;
1741                         }
1742                         else
1743                         {
1744                                 // a scalar, so set the value and remember we're scalar
1745                                 $this->me[$type]=$val;
1746                                 $this->mytype=$typeof;
1747                         }
1748                         return 1;
1749                 }
1750
1751                 function addArray($vals)
1752                 {
1753                         global $xmlrpcTypes;
1754                         if ($this->mytype!=0)
1755                         {
1756                                 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
1757                                 return 0;
1758                         }
1759
1760                         $this->mytype=$xmlrpcTypes['array'];
1761                         $this->me['array']=$vals;
1762                         return 1;
1763                 }
1764
1765                 function addStruct($vals)
1766                 {
1767                         global $xmlrpcTypes;
1768                         if ($this->mytype!=0)
1769                         {
1770                                 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
1771                                 return 0;
1772                         }
1773                         $this->mytype=$xmlrpcTypes['struct'];
1774                         $this->me['struct']=$vals;
1775                         return 1;
1776                 }
1777
1778                 function dump($ar)
1779                 {
1780                         reset($ar);
1781                         while ( list( $key, $val ) = each( $ar ) )
1782                         {
1783                                 echo "$key => $val<br>";
1784                                 if ($key == 'array')
1785                                 {
1786                                         while ( list( $key2, $val2 ) = each( $val ) )
1787                                         {
1788                                                 echo "-- $key2 => $val2<br>";
1789                                         }
1790                                 }
1791                         }
1792                 }
1793
1794                 function kindOf()
1795                 {
1796                         switch($this->mytype)
1797                         {
1798                                 case 3:
1799                                         return 'struct';
1800                                         break;
1801                                 case 2:
1802                                         return 'array';
1803                                         break;
1804                                 case 1:
1805                                         return 'scalar';
1806                                         break;
1807                                 default:
1808                                         return 'undef';
1809                         }
1810                 }
1811
1812                 function serializedata($typ, $val)
1813                 {
1814                         $rs='';
1815                         global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,
1816                         $xmlrpcBoolean;
1817                         switch(@$xmlrpcTypes[$typ])
1818                         {
1819                                 case 3:
1820                                         // struct
1821                                         $rs.="<struct>\n";
1822                                         reset($val);
1823                                         while(list($key2, $val2)=each($val))
1824                                         {
1825                                                 $rs.="<member><name>${key2}</name>\n";
1826                                                 $rs.=$this->serializeval($val2);
1827                                                 $rs.="</member>\n";
1828                                         }
1829                                         $rs.='</struct>';
1830                                         break;
1831                                 case 2:
1832                                         // array
1833                                         $rs.="<array>\n<data>\n";
1834                                         for($i=0; $i<sizeof($val); $i++)
1835                                         {
1836                                                 $rs.=$this->serializeval($val[$i]);
1837                                         }
1838                                         $rs.="</data>\n</array>";
1839                                         break;
1840                                 case 1:
1841                                         switch ($typ)
1842                                         {
1843                                                 case $xmlrpcBase64:
1844                                                         $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
1845                                                         break;
1846                                                 case $xmlrpcBoolean:
1847                                                         $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
1848                                                         break;
1849                                                 case $xmlrpcString:
1850                                                         // G. Giunta 2005/2/13: do NOT use htmlentities, since
1851                                                         // it will produce named html entities, which are invalid xml
1852                                                         // $rs.="<${typ}>" . xmlrpc_encode_entitites($val). "</${typ}>";
1853                                                         // $rs.="<${typ}>" . htmlentities($val). "</${typ}>";
1854                                                         
1855                                                         // N. Leenheer 2005/6/30: Use CDATA instead... 
1856                                                         $rs.="<${typ}><![CDATA[" . $val. "]]></${typ}>";
1857                                                         break;
1858                                                 default:
1859                                                         $rs.="<${typ}>${val}</${typ}>";
1860                                         }
1861                                         break;
1862                                 default:
1863                                         break;
1864                         }
1865                         return $rs;
1866                 }
1867
1868                 function serialize()
1869                 {
1870                         return $this->serializeval($this);
1871                 }
1872
1873                 function serializeval($o)
1874                 {
1875                         //global $xmlrpcTypes;
1876                         $rs='';
1877                         $ar=$o->me;
1878                         reset($ar);
1879                         list($typ, $val) = each($ar);
1880                         $rs.='<value>';
1881                         $rs.=$this->serializedata($typ, $val);
1882                         $rs.="</value>\n";
1883                         return $rs;
1884                 }
1885
1886                 function structmem($m)
1887                 {
1888                         $nv=$this->me['struct'][$m];
1889                         return $nv;
1890                 }
1891
1892                 function structreset()
1893                 {
1894                         reset($this->me['struct']);
1895                 }
1896
1897                 function structeach()
1898                 {
1899                         return each($this->me['struct']);
1900                 }
1901
1902                 function getval()
1903                 {
1904                         // UNSTABLE
1905                         global $xmlrpcBoolean, $xmlrpcBase64;
1906                         reset($this->me);
1907                         list($a,$b)=each($this->me);
1908                         // contributed by I Sofer, 2001-03-24
1909                         // add support for nested arrays to scalarval
1910                         // i've created a new method here, so as to
1911                         // preserve back compatibility
1912
1913                         if (is_array($b))
1914                         {
1915                                 @reset($b);
1916                                 while(list($id,$cont) = @each($b))
1917                                 {
1918                                         $b[$id] = $cont->scalarval();
1919                                 }
1920                         }
1921
1922                         // add support for structures directly encoding php objects
1923                         if (is_object($b))
1924                         {
1925                                 $t = get_object_vars($b);
1926                                 @reset($t);
1927                                 while(list($id,$cont) = @each($t))
1928                                 {
1929                                         $t[$id] = $cont->scalarval();
1930                                 }
1931                                 @reset($t);
1932                                 while(list($id,$cont) = @each($t))
1933                                 {
1934                                         //eval('$b->'.$id.' = $cont;');
1935                                         @$b->$id = $cont;
1936                                 }
1937                         }
1938                         // end contrib
1939                         return $b;
1940                 }
1941
1942                 function scalarval()
1943                 {
1944                         //global $xmlrpcBoolean, $xmlrpcBase64;
1945                         reset($this->me);
1946                         list($a,$b)=each($this->me);
1947                         return $b;
1948                 }
1949
1950                 function scalartyp()
1951                 {
1952                         global $xmlrpcI4, $xmlrpcInt;
1953                         reset($this->me);
1954                         list($a,$b)=each($this->me);
1955                         if ($a==$xmlrpcI4)
1956                         {
1957                                 $a=$xmlrpcInt;
1958                         }
1959                         return $a;
1960                 }
1961
1962                 function arraymem($m)
1963                 {
1964                         $nv=$this->me['array'][$m];
1965                         return $nv;
1966                 }
1967
1968                 function arraysize()
1969                 {
1970                         reset($this->me);
1971                         list($a,$b)=each($this->me);
1972                         return sizeof($b);
1973                 }
1974         }
1975
1976         // date helpers
1977         function iso8601_encode($timet, $utc=0)
1978         {
1979                 // return an ISO8601 encoded string
1980                 // really, timezones ought to be supported
1981                 // but the XML-RPC spec says:
1982                 //
1983                 // "Don't assume a timezone. It should be specified by the server in its
1984                 // documentation what assumptions it makes about timezones."
1985                 // 
1986                 // these routines always assume localtime unless 
1987                 // $utc is set to 1, in which case UTC is assumed
1988                 // and an adjustment for locale is made when encoding
1989                 if (!$utc)
1990                 {
1991                         $t=strftime("%Y%m%dT%H:%M:%S", $timet);
1992                 }
1993                 else
1994                 {
1995                         if (function_exists('gmstrftime'))
1996                         {
1997                                 // gmstrftime doesn't exist in some versions
1998                                 // of PHP
1999                                 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
2000                         }
2001                         else
2002                         {
2003                                 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z'));
2004                         }
2005                 }
2006                 return $t;
2007         }
2008
2009         function iso8601_decode($idate, $utc=0)
2010         {
2011                 // return a timet in the localtime, or UTC
2012                 $t=0;
2013                 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs))
2014                 {
2015                         if ($utc)
2016                         {
2017                                 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
2018                         }
2019                         else
2020                         {
2021                                 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
2022                         }
2023                 } 
2024                 return $t;
2025         }
2026
2027         /****************************************************************
2028         * xmlrpc_decode takes a message in PHP xmlrpc object format and *
2029         * tranlates it into native PHP types.                           *
2030         *                                                               *
2031         * author: Dan Libby (dan@libby.com)                             *
2032         ****************************************************************/
2033         function php_xmlrpc_decode($xmlrpc_val)
2034         {
2035                 $kind = $xmlrpc_val->kindOf();
2036
2037                 if($kind == 'scalar')
2038                 {
2039                         return $xmlrpc_val->scalarval();
2040                 }
2041                 elseif($kind == 'array')
2042                 {
2043                         $size = $xmlrpc_val->arraysize();
2044                         $arr = array();
2045
2046                         for($i = 0; $i < $size; $i++)
2047                         {
2048                                 $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i));
2049                         }
2050                         return $arr;
2051                 }
2052                 elseif($kind == 'struct')
2053                 {
2054                         $xmlrpc_val->structreset();
2055                         $arr = array();
2056
2057                         while(list($key,$value)=$xmlrpc_val->structeach())
2058                         {
2059                                 $arr[$key] = php_xmlrpc_decode($value);
2060                         }
2061                         return $arr;
2062                 }
2063         }
2064
2065         if(function_exists('xmlrpc_decode'))
2066         {
2067                 define('XMLRPC_EPI_ENABLED','1');
2068         }
2069         else
2070         {
2071                 define('XMLRPC_EPI_ENABLED','0');
2072                 function xmlrpc_decode($xmlrpc_val)
2073                 {
2074                         $kind = $xmlrpc_val->kindOf();
2075
2076                         if($kind == 'scalar')
2077                         {
2078                                 return $xmlrpc_val->scalarval();
2079                         }
2080                         elseif($kind == 'array')
2081                         {
2082                                 $size = $xmlrpc_val->arraysize();
2083                                 $arr = array();
2084
2085                                 for($i = 0; $i < $size; $i++)
2086                                 {
2087                                         $arr[]=xmlrpc_decode($xmlrpc_val->arraymem($i));
2088                                 }
2089                                 return $arr;
2090                         }
2091                         elseif($kind == 'struct')
2092                         {
2093                                 $xmlrpc_val->structreset();
2094                                 $arr = array();
2095
2096                                 while(list($key,$value)=$xmlrpc_val->structeach())
2097                                 {
2098                                         $arr[$key] = xmlrpc_decode($value);
2099                                 }
2100                                 return $arr;
2101                         }
2102                 }
2103         }
2104
2105         /****************************************************************
2106         * xmlrpc_encode takes native php types and encodes them into    *
2107         * xmlrpc PHP object format.                                     *
2108         * BUG: All sequential arrays are turned into structs.  I don't  *
2109         * know of a good way to determine if an array is sequential     *
2110         * only.                                                         *
2111         *                                                               *
2112         * feature creep -- could support more types via optional type   *
2113         * argument.                                                     *
2114         *                                                               *
2115         * author: Dan Libby (dan@libby.com)                             *
2116         ****************************************************************/
2117         function php_xmlrpc_encode($php_val)
2118         {
2119                 global $xmlrpcInt;
2120                 global $xmlrpcDouble;
2121                 global $xmlrpcString;
2122                 global $xmlrpcArray;
2123                 global $xmlrpcStruct;
2124                 global $xmlrpcBoolean;
2125
2126                 $type = gettype($php_val);
2127                 $xmlrpc_val = new xmlrpcval;
2128
2129                 switch($type)
2130                 {
2131                         case 'array':
2132                         case 'object':
2133                                 $arr = array();
2134                                 while (list($k,$v) = each($php_val))
2135                                 {
2136                                         $arr[$k] = php_xmlrpc_encode($v);
2137                                 }
2138                                 $xmlrpc_val->addStruct($arr);
2139                                 break;
2140                         case 'integer':
2141                                 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
2142                                 break;
2143                         case 'double':
2144                                 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
2145                                 break;
2146                         case 'string':
2147                                 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
2148                                 break;
2149                                 // <G_Giunta_2001-02-29>
2150                                 // Add support for encoding/decoding of booleans, since they are supported in PHP
2151                         case 'boolean':
2152                                 $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
2153                                 break;
2154                                 // </G_Giunta_2001-02-29>
2155                         // catch "resource", "NULL", "user function", "unknown type"
2156                         //case 'unknown type':
2157                         default:
2158                                 // giancarlo pinerolo <ping@alt.it>
2159                                 // it has to return 
2160                                 // an empty object in case (which is already
2161                                 // at this point), not a boolean. 
2162                                 break;
2163                         }
2164                         return $xmlrpc_val;
2165         }
2166
2167         if(XMLRPC_EPI_ENABLED == '0')
2168         {
2169                 function xmlrpc_encode($php_val)
2170                 {
2171                         global $xmlrpcInt;
2172                         global $xmlrpcDouble;
2173                         global $xmlrpcString;
2174                         global $xmlrpcArray;
2175                         global $xmlrpcStruct;
2176                         global $xmlrpcBoolean;
2177
2178                         $type = gettype($php_val);
2179                         $xmlrpc_val = new xmlrpcval;
2180
2181                         switch($type)
2182                         {
2183                                 case 'array':
2184                                 case 'object':
2185                                         $arr = array();
2186                                         while (list($k,$v) = each($php_val))
2187                                         {
2188                                                 $arr[$k] = xmlrpc_encode($v);
2189                                         }
2190                                         $xmlrpc_val->addStruct($arr);
2191                                         break;
2192                                 case 'integer':
2193                                         $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
2194                                         break;
2195                                 case 'double':
2196                                         $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
2197                                         break;
2198                                 case 'string':
2199                                         $xmlrpc_val->addScalar($php_val, $xmlrpcString);
2200                                         break;
2201                                         // <G_Giunta_2001-02-29>
2202                                         // Add support for encoding/decoding of booleans, since they are supported in PHP
2203                                 case 'boolean':
2204                                         $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
2205                                         break;
2206                                         // </G_Giunta_2001-02-29>
2207                                 //case 'unknown type':
2208                                 default:
2209                                         // giancarlo pinerolo <ping@alt.it>
2210                                         // it has to return 
2211                                         // an empty object in case (which is already
2212                                         // at this point), not a boolean. 
2213                                         break;
2214                         }
2215                         return $xmlrpc_val;
2216                 }
2217         }
2218 ?>