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