2 // by Edd Dumbill (C) 1999-2002
4 // $Id: xmlrpc.inc.php,v 1.6 2006-07-12 07:11:47 kimitake Exp $
5 // $NucleusJP: xmlrpc.inc.php,v 1.5 2005/08/13 07:24:44 kimitake Exp $
8 // Copyright (c) 1999,2000,2002 Edd Dumbill.
9 // All rights reserved.
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions
15 // * Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
18 // * Redistributions in binary form must reproduce the above
19 // copyright notice, this list of conditions and the following
20 // disclaimer in the documentation and/or other materials provided
21 // with the distribution.
23 // * Neither the name of the "XML-RPC for PHP" nor the names of its
24 // contributors may be used to endorse or promote products derived
25 // from this software without specific prior written permission.
27 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38 // OF THE POSSIBILITY OF SUCH DAMAGE.
40 if (!function_exists('xml_parser_create'))
42 // Win 32 fix. From: 'Leo West' <lwest@imaginet.fr>
53 // G. Giunta 2005/01/29: declare global these variables,
54 // so that xmlrpc.inc will work even if included from within a function
55 // NB: it will give warnings in PHP3, so we comment it out
56 // Milosch: Next round, maybe we should explicitly request these via $GLOBALS where used.
57 if (phpversion() >= '4')
62 global $xmlrpcBoolean;
64 global $xmlrpcDateTime;
73 global $xmlrpc_defencoding;
74 global $xmlrpc_internalencoding;
76 global $xmlrpcVersion;
77 global $xmlrpcerruser;
79 global $xmlrpc_backslash;
84 $xmlrpcBoolean='boolean';
85 $xmlrpcDouble='double';
86 $xmlrpcString='string';
87 $xmlrpcDateTime='dateTime.iso8601';
88 $xmlrpcBase64='base64';
90 $xmlrpcStruct='struct';
104 $xmlrpc_valid_parents = array(
105 'BOOLEAN' => array('VALUE' => 'VALUE'),
106 'I4' => array('VALUE' => 'VALUE'),
107 'INT' => array('VALUE' => 'VALUE'),
108 'STRING' => array('VALUE' => 'VALUE'),
109 'DOUBLE' => array('VALUE' => 'VALUE'),
110 'DATETIME.ISO8601' => array('VALUE' => 'VALUE'),
111 'BASE64' => array('VALUE' => 'VALUE'),
112 'ARRAY' => array('VALUE' => 'VALUE'),
113 'STRUCT' => array('VALUE' => 'VALUE'),
114 'PARAM' => array('PARAMS' => 'PARAMS'),
115 'METHODNAME' => array('METHODCALL' => 'METHODCALL'),
116 'PARAMS' => array('METHODCALL' => 'METHODCALL', 'METHODRESPONSE' => 'METHODRESPONSE'),
117 'MEMBER' => array('STRUCT' => 'STRUCT'),
118 'NAME' => array('MEMBER' => 'MEMBER'),
119 'DATA' => array('ARRAY' => 'ARRAY'),
120 'FAULT' => array('METHODRESPONSE' => 'METHODRESPONSE'),
121 'VALUE' => array('MEMBER' => 'MEMBER', 'DATA' => 'DATA', 'PARAM' => 'PARAM', 'FAULT' => 'FAULT')
132 $xmlrpcerr['unknown_method']=1;
133 $xmlrpcstr['unknown_method']='Unknown method';
134 $xmlrpcerr['invalid_return']=2;
135 $xmlrpcstr['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';
136 $xmlrpcerr['incorrect_params']=3;
137 $xmlrpcstr['incorrect_params']='Incorrect parameters passed to method';
138 $xmlrpcerr['introspect_unknown']=4;
139 $xmlrpcstr['introspect_unknown']="Can't introspect: method unknown";
140 $xmlrpcerr['http_error']=5;
141 $xmlrpcstr['http_error']="Didn't receive 200 OK from remote server.";
142 $xmlrpcerr['no_data']=6;
143 $xmlrpcstr['no_data']='No data received from server.';
144 $xmlrpcerr['no_ssl']=7;
145 $xmlrpcstr['no_ssl']='No SSL support compiled in.';
146 $xmlrpcerr['curl_fail']=8;
147 $xmlrpcstr['curl_fail']='CURL error';
148 $xmlrpcerr['invalid_request']=15;
149 $xmlrpcstr['invalid_request']='Invalid request payload';
151 $xmlrpcerr['multicall_notstruct'] = 9;
152 $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';
153 $xmlrpcerr['multicall_nomethod'] = 10;
154 $xmlrpcstr['multicall_nomethod'] = 'missing methodName';
155 $xmlrpcerr['multicall_notstring'] = 11;
156 $xmlrpcstr['multicall_notstring'] = 'methodName is not a string';
157 $xmlrpcerr['multicall_recursion'] = 12;
158 $xmlrpcstr['multicall_recursion'] = 'recursive system.multicall forbidden';
159 $xmlrpcerr['multicall_noparams'] = 13;
160 $xmlrpcstr['multicall_noparams'] = 'missing params';
161 $xmlrpcerr['multicall_notarray'] = 14;
162 $xmlrpcstr['multicall_notarray'] = 'params is not an array';
164 // The charset encoding expected by the server for received messages and
165 // by the client for received responses
166 $xmlrpc_defencoding='UTF-8';
167 // The encoding used by PHP.
168 // String values received will be converted to this.
169 $xmlrpc_internalencoding='ISO-8859-1';
171 $xmlrpcName='XML-RPC for PHP';
172 $xmlrpcVersion='1.2.1';
174 // let user errors start at 800
176 // let XML parse errors start at 100
179 // formulate backslashes for escaping regexp
180 $xmlrpc_backslash=chr(92).chr(92);
182 // used to store state during parsing
183 // quick explanation of components:
184 // ac - used to accumulate values
185 // isf - used to indicate a fault
186 // lv - used to indicate "looking for a value": implements
187 // the logic to allow values with no types to be strings
188 // params - used to store parameters in method calls
189 // method - used to store method name
190 // stack - array with genealogy of xml elements names:
191 // used to validate nesting of xmlrpc elements
196 * To help correct communication of non-ascii chars inside strings, regardless
197 * of the charset used when sending requests, parsing them, sending responses
198 * and parsing responses, convert all non-ascii chars present in the message
199 * into their equivalent 'charset entity'. Charset entities enumerated this way
200 * are independent of the charset encoding used to transmit them, and all XML
201 * parsers are bound to understand them.
203 function xmlrpc_entity_decode($string)
205 $top=split('&', $string);
208 while($i<sizeof($top))
210 if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs))
212 $op.=ereg_replace("^[#a-zA-Z0-9]+;",
213 xmlrpc_lookup_entity($regs[1]),
232 function xmlrpc_lookup_entity($ent)
236 if (isset($xmlEntities[strtolower($ent)]))
238 return $xmlEntities[strtolower($ent)];
240 if (ereg("^#([0-9]+)$", $ent, $regs))
242 return chr($regs[1]);
248 * These entities originate from HTML specs (1.1, proposed 2.0, etc),
249 * and are taken directly from php-4.3.1/ext/mbstring/html_entities.c.
250 * Until php provides functionality to translate these entities in its
251 * core library, use this function.
253 function xmlrpc_html_entity_xlate($data = '')
256 " " => " ",
257 "¡" => "¡",
258 "¢" => "¢",
259 "£" => "£",
260 "¤" => "¤",
262 "¦" => "¦",
263 "§" => "§",
265 "©" => "©",
266 "ª" => "ª",
267 "«" => "«",
271 "¯" => "¯",
273 "±" => "±",
274 "²" => "²",
275 "³" => "³",
276 "´" => "´",
277 "µ" => "µ",
278 "¶" => "¶",
279 "·" => "·",
280 "¸" => "¸",
281 "¹" => "¹",
282 "º" => "º",
283 "»" => "»",
284 "¼" => "¼",
285 "½" => "½",
286 "¾" => "¾",
287 "¿" => "¿",
288 "À" => "À",
289 "Á" => "Á",
290 "Â" => "Â",
291 "Ã" => "Ã",
292 "Ä" => "Ä",
293 "Å" => "Å",
294 "Æ" => "Æ",
295 "Ç" => "Ç",
296 "È" => "È",
297 "É" => "É",
298 "Ê" => "Ê",
299 "Ë" => "Ë",
300 "Ì" => "Ì",
301 "Í" => "Í",
302 "Î" => "Î",
303 "Ï" => "Ï",
305 "Ñ" => "Ñ",
306 "Ò" => "Ò",
307 "Ó" => "Ó",
308 "Ô" => "Ô",
309 "Õ" => "Õ",
310 "Ö" => "Ö",
311 "×" => "×",
312 "Ø" => "Ø",
313 "Ù" => "Ù",
314 "Ú" => "Ú",
315 "Û" => "Û",
316 "Ü" => "Ü",
317 "Ý" => "Ý",
318 "Þ" => "Þ",
319 "ß" => "ß",
320 "à" => "à",
321 "á" => "á",
322 "â" => "â",
323 "ã" => "ã",
324 "ä" => "ä",
325 "å" => "å",
326 "æ" => "æ",
327 "ç" => "ç",
328 "è" => "è",
329 "é" => "é",
330 "ê" => "ê",
331 "ë" => "ë",
332 "ì" => "ì",
333 "í" => "í",
334 "î" => "î",
335 "ï" => "ï",
337 "ñ" => "ñ",
338 "ò" => "ò",
339 "ó" => "ó",
340 "ô" => "ô",
341 "õ" => "õ",
342 "ö" => "ö",
343 "÷" => "÷",
344 "ø" => "ø",
345 "ù" => "ù",
346 "ú" => "ú",
347 "û" => "û",
348 "ü" => "ü",
349 "ý" => "ý",
350 "þ" => "þ",
351 "ÿ" => "ÿ",
352 "Œ" => "Œ",
353 "œ" => "œ",
354 "Š" => "Š",
355 "š" => "š",
356 "Ÿ" => "Ÿ",
357 "ƒ" => "ƒ",
358 "ˆ" => "ˆ",
359 "˜" => "˜",
360 "Α" => "Α",
361 "Β" => "Β",
362 "Γ" => "Γ",
363 "Δ" => "Δ",
364 "Ε" => "Ε",
365 "Ζ" => "Ζ",
367 "Θ" => "Θ",
368 "Ι" => "Ι",
369 "Κ" => "Κ",
370 "Λ" => "Λ",
374 "Ο" => "Ο",
377 "Σ" => "Σ",
379 "Υ" => "Υ",
383 "Ω" => "Ω",
384 "β" => "β",
385 "γ" => "γ",
386 "δ" => "δ",
387 "ε" => "ε",
388 "ζ" => "ζ",
390 "θ" => "θ",
391 "ι" => "ι",
392 "κ" => "κ",
393 "λ" => "λ",
397 "ο" => "ο",
400 "ς" => "ς",
401 "σ" => "σ",
403 "υ" => "υ",
407 "ω" => "ω",
408 "ϑ" => "ϑ",
409 "ϒ" => "ϒ",
411 " " => " ",
412 " " => " ",
413 " " => " ",
414 "‌" => "‌",
415 "‍" => "‍",
416 "‎" => "‎",
417 "‏" => "‏",
418 "–" => "–",
419 "—" => "—",
420 "‘" => "‘",
421 "’" => "’",
422 "‚" => "‚",
423 "“" => "“",
424 "”" => "”",
425 "„" => "„",
426 "†" => "†",
427 "‡" => "‡",
428 "•" => "•",
429 "…" => "…",
430 "‰" => "‰",
431 "′" => "′",
432 "″" => "″",
433 "‹" => "‹",
434 "›" => "›",
435 "‾" => "‾",
436 "⁄" => "⁄",
437 "€" => "€",
438 "℘" => "℘",
439 "ℑ" => "ℑ",
440 "ℜ" => "ℜ",
441 "™" => "™",
442 "ℵ" => "ℵ",
443 "←" => "←",
444 "↑" => "↑",
445 "→" => "→",
446 "↓" => "↓",
447 "↔" => "↔",
448 "↵" => "↵",
449 "⇐" => "⇐",
450 "⇑" => "⇑",
451 "⇒" => "⇒",
452 "⇓" => "⇓",
453 "⇔" => "⇔",
454 "∀" => "∀",
455 "∂" => "∂",
456 "∃" => "∃",
457 "∅" => "∅",
458 "∇" => "∇",
459 "∈" => "∈",
460 "∉" => "∉",
462 "∏" => "∏",
463 "∑" => "∑",
464 "−" => "−",
465 "∗" => "∗",
466 "√" => "√",
467 "∝" => "∝",
468 "∞" => "∞",
469 "∠" => "∠",
470 "∧" => "∧",
472 "∩" => "∩",
473 "∪" => "∪",
474 "∫" => "∫",
475 "∴" => "∴",
476 "∼" => "∼",
477 "≅" => "≅",
478 "≈" => "≈",
480 "≡" => "≡",
483 "⊂" => "⊂",
484 "⊃" => "⊃",
485 "⊄" => "⊄",
486 "⊆" => "⊆",
487 "⊇" => "⊇",
488 "⊕" => "⊕",
489 "⊗" => "⊗",
490 "⊥" => "⊥",
491 "⋅" => "⋅",
492 "⌈" => "⌈",
493 "⌉" => "⌉",
494 "⌊" => "⌊",
495 "⌋" => "⌋",
496 "⟨" => "〈",
497 "⟩" => "〉",
498 "◊" => "◊",
499 "♠" => "♠",
500 "♣" => "♣",
501 "♥" => "♥",
502 "♦" => "♦");
503 return strtr($data, $entities);
506 function xmlrpc_encode_entitites($data)
508 $length = strlen($data);
510 for($position = 0; $position < $length; $position++)
512 $character = substr($data, $position, 1);
513 $code = Ord($character);
516 $character = """;
519 $character = "&";
522 $character = "'";
531 if ($code < 32 || $code > 159)
532 $character = ("&#".strval($code).";");
535 $escapeddata .= $character;
540 function xmlrpc_se($parser, $name, $attrs)
542 global $_xh, $xmlrpcDateTime, $xmlrpcString, $xmlrpc_valid_parents;
544 // if invalid xmlrpc already detected, skip all processing
545 if ($_xh[$parser]['isf'] < 2)
548 // check for correct element nesting
549 // top level element can only be of 2 types
550 if ($_xh[$parser]['sp'] == 0)
552 if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
554 $_xh[$parser]['isf'] = 2;
555 $_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
561 // not top level element: see if parent is OK
562 $parent = $_xh[$parser]['stack'][$_xh[$parser]['sp']-1];
563 if (!isset($xmlrpc_valid_parents[$name][$parent]))
565 $_xh[$parser]['isf'] = 2;
566 $_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of $parent";
575 //$_xh[$parser]['st'].='array(';
576 //$_xh[$parser]['cm']++;
577 // this last line turns quoting off
578 // this means if we get an empty array we'll
579 // simply get a bit of whitespace in the eval
580 //$_xh[$parser]['qt']=0;
582 // create an empty array to hold child values, and push it onto appropriate stack
584 $cur_val['values'] = array();
585 $cur_val['type'] = $name;
586 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']] = $cur_val;
587 $_xh[$parser]['vsp']++;
591 //$_xh[$parser]['st'].='"';
592 $_xh[$parser]['ac']='';
595 $_xh[$parser]['isf']=1;
598 //$_xh[$parser]['st']='';
599 // clear value, so we can check later if no value will passed for this param/member
600 $_xh[$parser]['value']='';
603 //$_xh[$parser]['st'].='new xmlrpcval(';
604 // look for a value: if this is still true by the
605 // time we reach the end tag for value then the type is string
607 $_xh[$parser]['vt']='value';
608 $_xh[$parser]['ac']='';
609 //$_xh[$parser]['qt']=0;
610 $_xh[$parser]['lv']=1;
617 case 'DATETIME.ISO8601':
619 if ($_xh[$parser]['vt']!='value')
621 //two data elements inside a value: an error occurred!
622 $_xh[$parser]['isf'] = 2;
623 $_xh[$parser]['isf_reason'] = "$name element following a {$_xh[$parser]['vt']} element inside a single value";
627 // reset the accumulator
628 $_xh[$parser]['ac']='';
630 /*if ($name=='DATETIME.ISO8601' || $name=='STRING')
632 $_xh[$parser]['qt']=1;
633 if ($name=='DATETIME.ISO8601')
635 $_xh[$parser]['vt']=$xmlrpcDateTime;
638 elseif ($name=='BASE64')
640 $_xh[$parser]['qt']=2;
644 // No quoting is required here -- but
645 // at the end of the element we must check
646 // for data format errors.
647 $_xh[$parser]['qt']=0;
651 //$_xh[$parser]['ac']='';
652 // avoid warnings later on if no NAME is found before VALUE inside
653 // a struct member predefining member name as NULL
654 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['name'] = '';
655 // clear value, so we can check later if no value will passed for this param/member
656 $_xh[$parser]['value']='';
660 case 'METHODRESPONSE':
662 // valid elements that add little to processing
665 /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
666 $_xh[$parser]['isf'] = 2;
667 $_xh[$parser]['isf_reason'] = "found not-xmlrpc xml element $name";
671 // Save current element name to stack, to validate nesting
672 $_xh[$parser]['stack'][$_xh[$parser]['sp']] = $name;
673 $_xh[$parser]['sp']++;
677 $_xh[$parser]['lv']=0;
682 function xmlrpc_ee($parser, $name)
684 global $_xh,$xmlrpcTypes,$xmlrpcString,$xmlrpcDateTime;
686 if ($_xh[$parser]['isf'] < 2)
689 // push this element name from stack
690 // NB: if XML validates, correct opening/closing is guaranteed and
691 // we do not have to check for $name == $curr_elem.
692 // we also checked for proper nesting at start of elements...
693 $_xh[$parser]['sp']--;
694 $curr_elem = $_xh[$parser]['stack'][$_xh[$parser]['sp']];
695 unset($_xh[$parser]['stack'][$_xh[$parser]['sp']]);
700 //if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')
702 // $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
704 //$_xh[$parser]['st'].=')';
706 // fetch out of stack array of values, and promote it to current value
707 $_xh[$parser]['vsp']--;
708 $cur_val = $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']];
709 unset($_xh[$parser]['valuestack'][$_xh[$parser]['vsp']]);
710 $_xh[$parser]['value'] = $cur_val['values'];
712 $_xh[$parser]['vt']=strtolower($name);
713 //$_xh[$parser]['cm']--;
716 //$_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';
717 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['name'] = $_xh[$parser]['ac'];
724 case 'DATETIME.ISO8601':
726 $_xh[$parser]['vt']=strtolower($name);
727 //if ($_xh[$parser]['qt']==1)
730 // we use double quotes rather than single so backslashification works OK
731 //$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
732 $_xh[$parser]['value']=$_xh[$parser]['ac'];
734 elseif ($name=='DATETIME.ISO8601')
736 $_xh[$parser]['vt']=$xmlrpcDateTime;
737 $_xh[$parser]['value']=$_xh[$parser]['ac'];
739 elseif ($name=='BASE64')
741 //$_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';
743 ///@todo check for failure of base64 decoding / catch warnings
744 $_xh[$parser]['value']=base64_decode($_xh[$parser]['ac']);
746 elseif ($name=='BOOLEAN')
748 // special case here: we translate boolean 1 or 0 into PHP
749 // constants true or false
750 // NB: this simple checks helps a lot sanitizing input, ie no
751 // security problems around here
753 // [MOD] S. Verberkt (Legolas) (13/02/2006 21:16): Also accept 'true' and 'false'
754 if ($_xh[$parser]['ac']=='1' || strcasecmp($_xh[$parser]['ac'], 'true') == 0)
756 //$_xh[$parser]['ac']='true';
757 $_xh[$parser]['value']=true;
761 //$_xh[$parser]['ac']='false';
762 // log if receiveing something strange, even though we set the value to false anyway
763 if ($_xh[$parser]['ac']!='0' && strcasecmp($_xh[$parser]['ac'], 'false') != 0)
764 error_log('XML-RPC: invalid value received in BOOLEAN: '.$_xh[$parser]['ac']);
765 $_xh[$parser]['value']=false;
769 //$_xh[$parser]['st'].=$_xh[$parser]['ac'];
771 elseif ($name=='DOUBLE')
774 // we must check that only 0123456789-.<space> are characters here
775 if (!ereg("^[+-]?[eE0123456789 \\t\\.]+$", $_xh[$parser]['ac']))
777 // TODO: find a better way of throwing an error
779 error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']);
780 //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
781 $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';
785 // it's ok, add it on
786 //$_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];
787 $_xh[$parser]['value']=(double)$_xh[$parser]['ac'];
793 // we must check that only 0123456789-<space> are characters here
794 if (!ereg("^[+-]?[0123456789 \\t]+$", $_xh[$parser]['ac']))
796 // TODO: find a better way of throwing an error
798 error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']);
799 //$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
800 $_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';
804 // it's ok, add it on
805 //$_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];
806 $_xh[$parser]['value']=(int)$_xh[$parser]['ac'];
809 $_xh[$parser]['ac']='';
810 //$_xh[$parser]['qt']=0;
811 $_xh[$parser]['lv']=3; // indicate we've found a value
814 // This if() detects if no scalar was inside <VALUE></VALUE>
815 if ($_xh[$parser]['vt']=='value')
817 $_xh[$parser]['value']=$_xh[$parser]['ac'];
818 $_xh[$parser]['vt']=$xmlrpcString;
820 /*if (strlen($_xh[$parser]['ac'])>0 &&
821 $_xh[$parser]['vt']==$xmlrpcString)
823 $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
825 // This if() detects if no scalar was inside <VALUE></VALUE>
826 // and pads an empty ''.
827 if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(')
829 $_xh[$parser]['st'].= '""';
831 // G. Giunta 2005/03/12 save some chars in the reconstruction of string vals...
832 if ($_xh[$parser]['vt'] != $xmlrpcString)
833 $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
835 $_xh[$parser]['st'].=")";
836 if ($_xh[$parser]['cm'])
838 $_xh[$parser]['st'].=',';
841 // build the xmlrpc val out of the data received, and substitute it
842 $temp = new xmlrpcval($_xh[$parser]['value'], $_xh[$parser]['vt']);
843 // check if we are inside an array or struct:
844 // if value just built is inside an array, let's move it into array on the stack
845 if ($_xh[$parser]['vsp'] && $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['type']=='ARRAY')
847 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['values'][] = $temp;
851 $_xh[$parser]['value'] = $temp;
855 $_xh[$parser]['ac']='';
856 //$_xh[$parser]['qt']=0;
857 // add to array in the stack the last element built
858 // unless no VALUE was found
859 if ($_xh[$parser]['value'])
861 $_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['values'][$_xh[$parser]['valuestack'][$_xh[$parser]['vsp']-1]['name']] = $_xh[$parser]['value'];
864 error_log('XML-RPC: missing VALUE inside STRUCT in received xml');
867 $_xh[$parser]['ac']='';
868 //$_xh[$parser]['qt']=0;
871 //$_xh[$parser]['params'][]=$_xh[$parser]['st'];
872 if ($_xh[$parser]['value'])
873 $_xh[$parser]['params'][]=$_xh[$parser]['value'];
875 error_log('XML-RPC: missing VALUE inside PARAM in received xml');
878 $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);
883 case 'METHORESPONSE':
886 // End of INVALID ELEMENT!
887 // shall we add an assert here for unreachable code???
890 // if it's a valid type name, set the type
891 /*if (isset($xmlrpcTypes[strtolower($name)]))
893 $_xh[$parser]['vt']=strtolower($name);
899 function xmlrpc_cd($parser, $data)
901 global $_xh, $xmlrpc_backslash;
903 //if (ereg("^[\n\r \t]+$", $data)) return;
904 // print "adding [${data}]\n";
906 // skip processing if xml fault already detected
907 if ($_xh[$parser]['isf'] < 2)
909 if ($_xh[$parser]['lv']!=3)
911 // "lookforvalue==3" means that we've found an entire value
912 // and should discard any further character data
913 if ($_xh[$parser]['lv']==1)
915 // if we've found text and we're just in a <value> then
916 // turn quoting on, as this will be a string
917 //$_xh[$parser]['qt']=1;
918 // and say we've found a value
919 $_xh[$parser]['lv']=2;
921 if(!@isset($_xh[$parser]['ac']))
923 $_xh[$parser]['ac'] = '';
925 //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
926 $_xh[$parser]['ac'].=$data;
931 function xmlrpc_dh($parser, $data)
933 global $_xh, $xmlrpc_backslash;
935 // skip processing if xml fault already detected
936 if ($_xh[$parser]['isf'] < 2)
938 if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
940 if ($_xh[$parser]['lv']==1)
942 //$_xh[$parser]['qt']=1;
943 $_xh[$parser]['lv']=2;
945 //$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
946 $_xh[$parser]['ac'].=$data;
965 var $no_multicall=false;
967 function xmlrpc_client($path, $server, $port=0)
969 $this->port=$port; $this->server=$server; $this->path=$path;
972 function setDebug($in)
984 function setCredentials($u, $p)
990 function setCertificate($cert, $certpass)
993 $this->certpass = $certpass;
996 function setSSLVerifyPeer($i)
998 $this->verifypeer = $i;
1001 function setSSLVerifyHost($i)
1003 $this->verifyhost = $i;
1006 function send($msg, $timeout=0, $method='http')
1010 // $msg is an array of xmlrpcmsg's
1011 return $this->multicall($msg, $timeout, $method);
1014 // where msg is an xmlrpcmsg
1015 $msg->debug=$this->debug;
1017 if ($method == 'https')
1019 return $this->sendPayloadHTTPS($msg,
1021 $this->port, $timeout,
1022 $this->username, $this->password,
1028 return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
1029 $timeout, $this->username,
1034 function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
1036 global $xmlrpcerr, $xmlrpcstr, $xmlrpcName, $xmlrpcVersion, $xmlrpc_defencoding;
1043 $fp=@fsockopen($server, $port,$this->errno, $this->errstr, $timeout);
1047 $fp=@fsockopen($server, $port,$this->errno, $this->errstr);
1051 if ($timeout>0 && function_exists('stream_set_timeout'))
1052 stream_set_timeout($fp, $timeout);
1056 $this->errstr='Connect error';
1057 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']);
1060 // Only create the payload if it was not created previously
1061 if(empty($msg->payload))
1063 $msg->createPayload();
1066 // thanks to Grant Rauscher <grant7@firstworld.net>
1071 $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
1074 $op= "POST " . $this->path. " HTTP/1.0\r\n" .
1075 "User-Agent: " . $xmlrpcName . " " . $xmlrpcVersion . "\r\n" .
1076 "Host: ". $server . "\r\n" .
1078 "Accept-Charset: " . $xmlrpc_defencoding . "\r\n" .
1079 "Content-Type: text/xml\r\nContent-Length: " .
1080 strlen($msg->payload) . "\r\n\r\n" .
1083 if (!fputs($fp, $op, strlen($op)))
1085 $this->errstr='Write error';
1086 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']);
1089 $resp=$msg->parseResponseFile($fp);
1094 // contributed by Justin Miller <justin@voxel.net>
1095 // requires curl to be built into PHP
1096 function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='')
1098 global $xmlrpcerr, $xmlrpcstr, $xmlrpcVersion, $xmlrpc_internalencoding;
1104 // Only create the payload if it was not created previously
1105 if(empty($msg->payload))
1107 $msg->createPayload();
1110 if (!function_exists('curl_init'))
1112 $this->errstr='SSL unavailable on this install';
1113 $r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']);
1117 $curl = curl_init('https://' . $server . ':' . $port . $this->path);
1119 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
1120 // results into variable
1123 curl_setopt($curl, CURLOPT_VERBOSE, 1);
1125 curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC '.$xmlrpcVersion);
1126 // required for XMLRPC
1127 curl_setopt($curl, CURLOPT_POST, 1);
1129 curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
1131 curl_setopt($curl, CURLOPT_HEADER, 1);
1132 // return the header too
1133 curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml', 'Accept-Charset: '.$xmlrpc_internalencoding));
1134 // whether to verify remote host's cert
1135 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
1136 // whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
1137 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
1138 // required for XMLRPC
1141 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
1143 // timeout is borked
1144 if ($username && $password)
1146 curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
1151 curl_setopt($curl, CURLOPT_SSLCERT, $cert);
1156 curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass);
1158 // set cert password
1160 $result = curl_exec($curl);
1164 $this->errstr='no response';
1165 $resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl));
1171 $resp = $msg->parseResponse($result);
1176 function multicall($msgs, $timeout=0, $method='http')
1180 if (! $this->no_multicall)
1182 $results = $this->_try_multicall($msgs, $timeout, $method);
1183 /* TODO - this is not php3-friendly */
1184 // if($results !== false)
1185 if(is_array($results))
1187 // Either the system.multicall succeeded, or the send
1188 // failed (e.g. due to HTTP timeout). In either case,
1189 // we're done for now.
1194 // system.multicall unsupported by server,
1195 // don't try it next time...
1196 $this->no_multicall = true;
1200 // system.multicall is unupported by server:
1201 // Emulate multicall via multiple requests
1203 //foreach($msgs as $msg)
1205 while(list(,$msg) = @each($msgs))
1207 $results[] = $this->send($msg, $timeout, $method);
1212 // Attempt to boxcar $msgs via system.multicall.
1213 function _try_multicall($msgs, $timeout, $method)
1215 // Construct multicall message
1217 //foreach($msgs as $msg)
1219 while(list(,$msg) = @each($msgs))
1221 $call['methodName'] = new xmlrpcval($msg->method(),'string');
1222 $numParams = $msg->getNumParams();
1224 for ($i = 0; $i < $numParams; $i++)
1226 $params[$i] = $msg->getParam($i);
1228 $call['params'] = new xmlrpcval($params, 'array');
1229 $calls[] = new xmlrpcval($call, 'struct');
1231 $multicall = new xmlrpcmsg('system.multicall');
1232 $multicall->addParam(new xmlrpcval($calls, 'array'));
1235 $result = $this->send($multicall, $timeout, $method);
1236 if(!is_object($result))
1238 return ($result || 0); // transport failed
1241 if($result->faultCode() != 0)
1243 return false; // system.multicall failed
1246 // Unpack responses.
1247 $rets = $result->value();
1248 if($rets->kindOf() != 'array')
1250 return false; // bad return type from system.multicall
1252 $numRets = $rets->arraysize();
1253 if($numRets != count($msgs))
1255 return false; // wrong number of return values.
1258 $response = array();
1259 for ($i = 0; $i < $numRets; $i++)
1261 $val = $rets->arraymem($i);
1262 switch ($val->kindOf())
1265 if($val->arraysize() != 1)
1267 return false; // Bad value
1269 // Normal return value
1270 $response[$i] = new xmlrpcresp($val->arraymem(0));
1273 $code = $val->structmem('faultCode');
1274 if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
1278 $str = $val->structmem('faultString');
1279 if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
1283 $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
1291 } // end class xmlrpc_client
1298 var $hdrs = array();
1300 function xmlrpcresp($val, $fcode = 0, $fstr = '')
1305 $this->errno = $fcode;
1306 $this->errstr = $fstr;
1307 //$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
1309 elseif (!is_object($val))
1312 error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value.");
1313 $this->val = new xmlrpcval();
1322 function faultCode()
1324 return $this->errno;
1327 function faultString()
1329 return $this->errstr;
1337 function serialize()
1339 $result = "<methodResponse>\n";
1342 // G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients
1347 <name>faultCode</name>
1348 <value><int>' . $this->errno . '</int></value>
1351 <name>faultString</name>
1352 <value><string>' . xmlrpc_encode_entitites($this->errstr) . '</string></value>
1360 $result .= "<params>\n<param>\n" .
1361 $this->val->serialize() .
1362 "</param>\n</params>";
1364 $result .= "\n</methodResponse>";
1373 var $params=array();
1376 function xmlrpcmsg($meth, $pars=0)
1378 $this->methodname=$meth;
1379 if (is_array($pars) && sizeof($pars)>0)
1381 for($i=0; $i<sizeof($pars); $i++)
1383 $this->addParam($pars[$i]);
1388 function xml_header()
1390 return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
1393 function xml_footer()
1395 return "</methodCall>\n";
1398 function createPayload()
1400 $this->payload=$this->xml_header();
1401 $this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
1402 // if (sizeof($this->params)) {
1403 $this->payload.="<params>\n";
1404 for($i=0; $i<sizeof($this->params); $i++)
1406 $p=$this->params[$i];
1407 $this->payload.="<param>\n" . $p->serialize() .
1410 $this->payload.="</params>\n";
1412 $this->payload.=$this->xml_footer();
1413 //$this->payload=str_replace("\n", "\r\n", $this->payload);
1416 function method($meth='')
1420 $this->methodname=$meth;
1422 return $this->methodname;
1425 function serialize()
1427 $this->createPayload();
1428 return $this->payload;
1431 function addParam($par) { $this->params[]=$par; }
1432 function getParam($i) { return $this->params[$i]; }
1433 function getNumParams() { return sizeof($this->params); }
1435 function parseResponseFile($fp)
1438 while($data=fread($fp, 32768))
1442 return $this->parseResponse($ipd);
1445 function parseResponse($data='')
1447 global $_xh,$xmlrpcerr,$xmlrpcstr;
1448 global $xmlrpc_defencoding, $xmlrpc_internalencoding;
1453 //by maHo, replaced htmlspecialchars with htmlentities
1454 print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
1459 error_log('No response received from server.');
1460 $r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']);
1463 // see if we got an HTTP 200 OK, else bomb
1464 // but only do this if we're using the HTTP protocol.
1465 if(ereg("^HTTP",$data))
1467 // Strip HTTP 1.1 100 Continue header if present
1468 while (ereg('^HTTP/1.1 1[0-9]{2}', $data))
1470 $pos = strpos($data, 'HTTP', 12);
1471 // server sent a Continue header without any (valid) content following...
1472 // give the client a chance to know it
1473 if (!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
1475 $data = substr($data, $pos);
1477 if (!ereg("^HTTP/[0-9\\.]+ 200 ", $data))
1479 $errstr= substr($data, 0, strpos($data, "\n")-1);
1480 error_log('HTTP error, got response: ' .$errstr);
1481 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')');
1485 $parser = xml_parser_create($xmlrpc_defencoding);
1487 // G. Giunta 2004/04/06
1488 // Clean up the accumulator, or it will grow indefinitely long
1489 // if making xmlrpc calls for a while
1491 $_xh[$parser]=array();
1492 $_xh[$parser]['headers'] = array();
1493 $_xh[$parser]['stack'] = array();
1494 $_xh[$parser]['sp'] = 0;
1495 $_xh[$parser]['valuestack'] = array();
1496 $_xh[$parser]['vsp'] = 0;
1498 // separate HTTP headers from data
1499 if (ereg("^HTTP", $data))
1501 // be tolerant to usage of \n instead of \r\n to separate headers and data
1502 // (even though it is not valid http)
1503 $pos = strpos($data,"\r\n\r\n");
1504 if($pos || is_int($pos))
1508 $pos = strpos($data,"\n\n");
1509 if($pos || is_int($pos))
1513 // No separation between response headers and body: fault?
1517 // be tolerant to line endings, and extra empty lines
1518 $ar = split("\r?\n", trim(substr($data, 0, $pos)));
1519 while (list(,$line) = @each($ar))
1521 // take care of multi-line headers
1522 $arr = explode(':',$line);
1525 $header_name = trim($arr[0]);
1526 // TO DO: some headers (the ones that allow a CSV list of values)
1527 // do allow many values to be passed using multiple header lines.
1528 // We should add content to $_xh[$parser]['headers'][$header_name]
1529 // instead of replacing it for those...
1530 $_xh[$parser]['headers'][$header_name] = $arr[1];
1531 for ($i = 2; $i < count($arr); $i++)
1533 $_xh[$parser]['headers'][$header_name] .= ':'.$arr[$i];
1535 $_xh[$parser]['headers'][$header_name] = trim($_xh[$parser]['headers'][$header_name]);
1536 } else if (isset($header_name))
1538 $_xh[$parser]['headers'][$header_name] .= ' ' . trim($line);
1541 $data = substr($data, $bd);
1543 if ($this->debug && count($_xh[$parser]['headers']))
1546 //foreach ($_xh[$parser]['headers'] as $header)
1547 @reset($_xh[$parser]['headers']);
1548 while(list($header, $value) = @each($_xh[$parser]['headers']))
1550 print "HEADER: $header: $value\n";
1556 // be tolerant of extra whitespace in response body
1557 $data = trim($data);
1559 // be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
1560 // idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
1562 $pos = strpos($data, "</methodResponse>");
1563 while ($pos || is_int($pos))
1566 $pos = strpos($data, "</methodResponse>", $bd);
1569 $data = substr($data, 0, $bd);
1571 //$_xh[$parser]['st']='';
1572 //$_xh[$parser]['cm']=0;
1573 $_xh[$parser]['isf']=0;
1574 $_xh[$parser]['isf_reason']=0;
1575 $_xh[$parser]['ac']='';
1576 //$_xh[$parser]['qt']='';
1578 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
1579 // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
1580 // the xml parser to give us back data in the expected charset
1581 xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding);
1583 xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
1584 xml_set_character_data_handler($parser, 'xmlrpc_cd');
1585 xml_set_default_handler($parser, 'xmlrpc_dh');
1586 //$xmlrpc_value=new xmlrpcval;
1588 if (!xml_parse($parser, $data, sizeof($data)))
1590 // thanks to Peter Kocks <peter.kocks@baygate.com>
1591 if((xml_get_current_line_number($parser)) == 1)
1593 $errstr = 'XML error at line 1, check URL';
1597 $errstr = sprintf('XML error: %s at line %d',
1598 xml_error_string(xml_get_error_code($parser)),
1599 xml_get_current_line_number($parser));
1602 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return'].' ('.$errstr.')');
1603 xml_parser_free($parser);
1606 $r->hdrs = $_xh[$parser]['headers'];
1609 xml_parser_free($parser);
1611 if ($_xh[$parser]['isf'] > 1)
1615 ///@todo echo something for user?
1618 $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
1619 $xmlrpcstr['invalid_return'] . ' ' . $_xh[$parser]['isf_reason']);
1621 //else if (strlen($_xh[$parser]['st'])==0)
1622 else if (!is_object($_xh[$parser]['value']))
1624 // then something odd has happened
1625 // and it's time to generate a client side error
1626 // indicating something odd went on
1627 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
1628 $xmlrpcstr['invalid_return']);
1635 //print "<PRE>---EVALING---[" .
1636 //strlen($_xh[$parser]['st']) . " chars]---\n" .
1637 //htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";
1638 print "<PRE>---PARSED---\n" ;
1639 var_dump($_xh[$parser]['value']);
1640 print "\n---END---</PRE>";
1644 //@eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');
1647 // $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);
1650 $v = $_xh[$parser]['value'];
1651 if ($_xh[$parser]['isf'])
1653 $errno_v = $v->structmem('faultCode');
1654 $errstr_v = $v->structmem('faultString');
1655 $errno = $errno_v->scalarval();
1659 // FAULT returned, errno needs to reflect that
1663 $r = new xmlrpcresp($v, $errno, $errstr_v->scalarval());
1667 $r=new xmlrpcresp($v);
1671 $r->hdrs = $_xh[$parser]['headers'];
1681 function xmlrpcval($val=-1, $type='')
1683 global $xmlrpcTypes;
1686 if ($val!=-1 || !is_int($val) || $type!='')
1692 if ($xmlrpcTypes[$type]==1)
1694 $this->addScalar($val,$type);
1696 elseif ($xmlrpcTypes[$type]==2)
1698 $this->addArray($val);
1700 elseif ($xmlrpcTypes[$type]==3)
1702 $this->addStruct($val);
1707 function addScalar($val, $type='string')
1709 global $xmlrpcTypes, $xmlrpcBoolean;
1711 if ($this->mytype==1)
1713 echo '<B>xmlrpcval</B>: scalar can have only one value<BR>';
1716 $typeof=$xmlrpcTypes[$type];
1719 echo '<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>';
1723 if ($type==$xmlrpcBoolean)
1725 if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
1735 if ($this->mytype==2)
1737 // we're adding to an array here
1738 $ar=$this->me['array'];
1739 $ar[]=new xmlrpcval($val, $type);
1740 $this->me['array']=$ar;
1744 // a scalar, so set the value and remember we're scalar
1745 $this->me[$type]=$val;
1746 $this->mytype=$typeof;
1751 function addArray($vals)
1753 global $xmlrpcTypes;
1754 if ($this->mytype!=0)
1756 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
1760 $this->mytype=$xmlrpcTypes['array'];
1761 $this->me['array']=$vals;
1765 function addStruct($vals)
1767 global $xmlrpcTypes;
1768 if ($this->mytype!=0)
1770 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
1773 $this->mytype=$xmlrpcTypes['struct'];
1774 $this->me['struct']=$vals;
1781 while ( list( $key, $val ) = each( $ar ) )
1783 echo "$key => $val<br>";
1784 if ($key == 'array')
1786 while ( list( $key2, $val2 ) = each( $val ) )
1788 echo "-- $key2 => $val2<br>";
1796 switch($this->mytype)
1812 function serializedata($typ, $val)
1815 global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,
1817 switch(@$xmlrpcTypes[$typ])
1823 while(list($key2, $val2)=each($val))
1825 $rs.="<member><name>${key2}</name>\n";
1826 $rs.=$this->serializeval($val2);
1833 $rs.="<array>\n<data>\n";
1834 for($i=0; $i<sizeof($val); $i++)
1836 $rs.=$this->serializeval($val[$i]);
1838 $rs.="</data>\n</array>";
1844 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
1846 case $xmlrpcBoolean:
1847 $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
1850 // G. Giunta 2005/2/13: do NOT use htmlentities, since
1851 // it will produce named html entities, which are invalid xml
1852 // $rs.="<${typ}>" . xmlrpc_encode_entitites($val). "</${typ}>";
1853 // $rs.="<${typ}>" . htmlentities($val). "</${typ}>";
1855 // N. Leenheer 2005/6/30: Use CDATA instead...
1856 $rs.="<${typ}><![CDATA[" . $val. "]]></${typ}>";
1859 $rs.="<${typ}>${val}</${typ}>";
1868 function serialize()
1870 return $this->serializeval($this);
1873 function serializeval($o)
1875 //global $xmlrpcTypes;
1879 list($typ, $val) = each($ar);
1881 $rs.=$this->serializedata($typ, $val);
1886 function structmem($m)
1888 $nv=$this->me['struct'][$m];
1892 function structreset()
1894 reset($this->me['struct']);
1897 function structeach()
1899 return each($this->me['struct']);
1905 global $xmlrpcBoolean, $xmlrpcBase64;
1907 list($a,$b)=each($this->me);
1908 // contributed by I Sofer, 2001-03-24
1909 // add support for nested arrays to scalarval
1910 // i've created a new method here, so as to
1911 // preserve back compatibility
1916 while(list($id,$cont) = @each($b))
1918 $b[$id] = $cont->scalarval();
1922 // add support for structures directly encoding php objects
1925 $t = get_object_vars($b);
1927 while(list($id,$cont) = @each($t))
1929 $t[$id] = $cont->scalarval();
1932 while(list($id,$cont) = @each($t))
1934 //eval('$b->'.$id.' = $cont;');
1942 function scalarval()
1944 //global $xmlrpcBoolean, $xmlrpcBase64;
1946 list($a,$b)=each($this->me);
1950 function scalartyp()
1952 global $xmlrpcI4, $xmlrpcInt;
1954 list($a,$b)=each($this->me);
1962 function arraymem($m)
1964 $nv=$this->me['array'][$m];
1968 function arraysize()
1971 list($a,$b)=each($this->me);
1977 function iso8601_encode($timet, $utc=0)
1979 // return an ISO8601 encoded string
1980 // really, timezones ought to be supported
1981 // but the XML-RPC spec says:
1983 // "Don't assume a timezone. It should be specified by the server in its
1984 // documentation what assumptions it makes about timezones."
1986 // these routines always assume localtime unless
1987 // $utc is set to 1, in which case UTC is assumed
1988 // and an adjustment for locale is made when encoding
1991 $t=strftime("%Y%m%dT%H:%M:%S", $timet);
1995 if (function_exists('gmstrftime'))
1997 // gmstrftime doesn't exist in some versions
1999 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
2003 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z'));
2009 function iso8601_decode($idate, $utc=0)
2011 // return a timet in the localtime, or UTC
2013 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs))
2017 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
2021 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
2027 /****************************************************************
2028 * xmlrpc_decode takes a message in PHP xmlrpc object format and *
2029 * tranlates it into native PHP types. *
2031 * author: Dan Libby (dan@libby.com) *
2032 ****************************************************************/
2033 function php_xmlrpc_decode($xmlrpc_val)
2035 $kind = $xmlrpc_val->kindOf();
2037 if($kind == 'scalar')
2039 return $xmlrpc_val->scalarval();
2041 elseif($kind == 'array')
2043 $size = $xmlrpc_val->arraysize();
2046 for($i = 0; $i < $size; $i++)
2048 $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i));
2052 elseif($kind == 'struct')
2054 $xmlrpc_val->structreset();
2057 while(list($key,$value)=$xmlrpc_val->structeach())
2059 $arr[$key] = php_xmlrpc_decode($value);
2065 if(function_exists('xmlrpc_decode'))
2067 define('XMLRPC_EPI_ENABLED','1');
2071 define('XMLRPC_EPI_ENABLED','0');
2072 function xmlrpc_decode($xmlrpc_val)
2074 $kind = $xmlrpc_val->kindOf();
2076 if($kind == 'scalar')
2078 return $xmlrpc_val->scalarval();
2080 elseif($kind == 'array')
2082 $size = $xmlrpc_val->arraysize();
2085 for($i = 0; $i < $size; $i++)
2087 $arr[]=xmlrpc_decode($xmlrpc_val->arraymem($i));
2091 elseif($kind == 'struct')
2093 $xmlrpc_val->structreset();
2096 while(list($key,$value)=$xmlrpc_val->structeach())
2098 $arr[$key] = xmlrpc_decode($value);
2105 /****************************************************************
2106 * xmlrpc_encode takes native php types and encodes them into *
2107 * xmlrpc PHP object format. *
2108 * BUG: All sequential arrays are turned into structs. I don't *
2109 * know of a good way to determine if an array is sequential *
2112 * feature creep -- could support more types via optional type *
2115 * author: Dan Libby (dan@libby.com) *
2116 ****************************************************************/
2117 function php_xmlrpc_encode($php_val)
2120 global $xmlrpcDouble;
2121 global $xmlrpcString;
2122 global $xmlrpcArray;
2123 global $xmlrpcStruct;
2124 global $xmlrpcBoolean;
2126 $type = gettype($php_val);
2127 $xmlrpc_val = new xmlrpcval;
2134 while (list($k,$v) = each($php_val))
2136 $arr[$k] = php_xmlrpc_encode($v);
2138 $xmlrpc_val->addStruct($arr);
2141 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
2144 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
2147 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
2149 // <G_Giunta_2001-02-29>
2150 // Add support for encoding/decoding of booleans, since they are supported in PHP
2152 $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
2154 // </G_Giunta_2001-02-29>
2155 // catch "resource", "NULL", "user function", "unknown type"
2156 //case 'unknown type':
2158 // giancarlo pinerolo <ping@alt.it>
2160 // an empty object in case (which is already
2161 // at this point), not a boolean.
2167 if(XMLRPC_EPI_ENABLED == '0')
2169 function xmlrpc_encode($php_val)
2172 global $xmlrpcDouble;
2173 global $xmlrpcString;
2174 global $xmlrpcArray;
2175 global $xmlrpcStruct;
2176 global $xmlrpcBoolean;
2178 $type = gettype($php_val);
2179 $xmlrpc_val = new xmlrpcval;
2186 while (list($k,$v) = each($php_val))
2188 $arr[$k] = xmlrpc_encode($v);
2190 $xmlrpc_val->addStruct($arr);
2193 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
2196 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
2199 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
2201 // <G_Giunta_2001-02-29>
2202 // Add support for encoding/decoding of booleans, since they are supported in PHP
2204 $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
2206 // </G_Giunta_2001-02-29>
2207 //case 'unknown type':
2209 // giancarlo pinerolo <ping@alt.it>
2211 // an empty object in case (which is already
2212 // at this point), not a boolean.