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