2 // by Edd Dumbill (C) 1999-2002
\r
3 // <edd@usefulinc.com>
\r
4 // $Id: xmlrpc.inc.php,v 1.5 2005-08-13 07:24:44 kimitake Exp $
\r
8 // Copyright (c) 1999,2000,2002 Edd Dumbill.
\r
9 // All rights reserved.
\r
11 // Redistribution and use in source and binary forms, with or without
\r
12 // modification, are permitted provided that the following conditions
\r
15 // * Redistributions of source code must retain the above copyright
\r
16 // notice, this list of conditions and the following disclaimer.
\r
18 // * Redistributions in binary form must reproduce the above
\r
19 // copyright notice, this list of conditions and the following
\r
20 // disclaimer in the documentation and/or other materials provided
\r
21 // with the distribution.
\r
23 // * Neither the name of the "XML-RPC for PHP" nor the names of its
\r
24 // contributors may be used to endorse or promote products derived
\r
25 // from this software without specific prior written permission.
\r
27 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\r
28 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
\r
29 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
\r
30 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
\r
31 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
32 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
\r
33 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
\r
34 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\r
35 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
\r
36 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
\r
37 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
\r
38 // OF THE POSSIBILITY OF SUCH DAMAGE.
\r
40 if (!function_exists('xml_parser_create'))
\r
42 // Win 32 fix. From: 'Leo West' <lwest@imaginet.fr>
\r
53 // G. Giunta 2005/01/29: declare global these variables,
\r
54 // so that xmlrpc.inc will work even if included from within a function
\r
55 // NB: it will give warnings in PHP3, so we comment it out
\r
56 // Milosch: Next round, maybe we should explicitly request these via $GLOBALS where used.
\r
57 if (phpversion() >= '4')
\r
61 global $xmlrpcDouble;
\r
62 global $xmlrpcString;
\r
63 global $xmlrpcDateTime;
\r
64 global $xmlrpcBase64;
\r
65 global $xmlrpcArray;
\r
66 global $xmlrpcStruct;
\r
68 global $xmlrpcTypes;
\r
69 global $xmlEntities;
\r
72 global $xmlrpc_defencoding;
\r
73 global $xmlrpc_internalencoding;
\r
75 global $xmlrpcVersion;
\r
76 global $xmlrpcerruser;
\r
77 global $xmlrpcerrxml;
\r
78 global $xmlrpc_backslash;
\r
83 $xmlrpcBoolean='boolean';
\r
84 $xmlrpcDouble='double';
\r
85 $xmlrpcString='string';
\r
86 $xmlrpcDateTime='dateTime.iso8601';
\r
87 $xmlrpcBase64='base64';
\r
88 $xmlrpcArray='array';
\r
89 $xmlrpcStruct='struct';
\r
94 $xmlrpcBoolean => 1,
\r
97 $xmlrpcDateTime => 1,
\r
103 $xmlEntities=array(
\r
111 $xmlrpcerr['unknown_method']=1;
\r
112 $xmlrpcstr['unknown_method']='Unknown method';
\r
113 $xmlrpcerr['invalid_return']=2;
\r
114 $xmlrpcstr['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';
\r
115 $xmlrpcerr['incorrect_params']=3;
\r
116 $xmlrpcstr['incorrect_params']='Incorrect parameters passed to method';
\r
117 $xmlrpcerr['introspect_unknown']=4;
\r
118 $xmlrpcstr['introspect_unknown']="Can't introspect: method unknown";
\r
119 $xmlrpcerr['http_error']=5;
\r
120 $xmlrpcstr['http_error']="Didn't receive 200 OK from remote server.";
\r
121 $xmlrpcerr['no_data']=6;
\r
122 $xmlrpcstr['no_data']='No data received from server.';
\r
123 $xmlrpcerr['no_ssl']=7;
\r
124 $xmlrpcstr['no_ssl']='No SSL support compiled in.';
\r
125 $xmlrpcerr['curl_fail']=8;
\r
126 $xmlrpcstr['curl_fail']='CURL error';
\r
129 $xmlrpcerr['multicall_notstruct'] = 9;
\r
130 $xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';
\r
131 $xmlrpcerr['multicall_nomethod'] = 10;
\r
132 $xmlrpcstr['multicall_nomethod'] = 'missing methodName';
\r
133 $xmlrpcerr['multicall_notstring'] = 11;
\r
134 $xmlrpcstr['multicall_notstring'] = 'methodName is not a string';
\r
135 $xmlrpcerr['multicall_recursion'] = 12;
\r
136 $xmlrpcstr['multicall_recursion'] = 'recursive system.multicall forbidden';
\r
137 $xmlrpcerr['multicall_noparams'] = 13;
\r
138 $xmlrpcstr['multicall_noparams'] = 'missing params';
\r
139 $xmlrpcerr['multicall_notarray'] = 14;
\r
140 $xmlrpcstr['multicall_notarray'] = 'params is not an array';
\r
142 // The charset encoding expected by the server for received messages and
\r
143 // by the client for received responses
\r
144 $xmlrpc_defencoding='UTF-8';
\r
145 // The encoding used by PHP.
\r
146 // String values received will be converted to this.
\r
147 $xmlrpc_internalencoding='ISO-8859-1';
\r
149 $xmlrpcName='XML-RPC for PHP';
\r
150 $xmlrpcVersion='1.1.1';
\r
152 // let user errors start at 800
\r
153 $xmlrpcerruser=800;
\r
154 // let XML parse errors start at 100
\r
157 // formulate backslashes for escaping regexp
\r
158 $xmlrpc_backslash=chr(92).chr(92);
\r
160 // used to store state during parsing
\r
161 // quick explanation of components:
\r
162 // st - used to build up a string for evaluation
\r
163 // ac - used to accumulate values
\r
164 // qt - used to decide if quotes are needed for evaluation
\r
165 // cm - used to denote struct or array (comma needed)
\r
166 // isf - used to indicate a fault
\r
167 // lv - used to indicate "looking for a value": implements
\r
168 // the logic to allow values with no types to be strings
\r
169 // params - used to store parameters in method calls
\r
170 // method - used to store method name
\r
175 * To help correct communication of non-ascii chars inside strings, regardless
\r
176 * of the charset used when sending requests, parsing them, sending responses
\r
177 * and parsing responses, convert all non-ascii chars present in the message
\r
178 * into their equivalent 'charset entity'. Charset entities enumerated this way
\r
179 * are independent of the charset encoding used to transmit them, and all XML
\r
180 * parsers are bound to understand them.
\r
182 function xmlrpc_entity_decode($string)
\r
184 $top=split('&', $string);
\r
187 while($i<sizeof($top))
\r
189 if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs))
\r
191 $op.=ereg_replace("^[#a-zA-Z0-9]+;",
\r
192 xmlrpc_lookup_entity($regs[1]),
\r
203 $op.='&' . $top[$i];
\r
211 function xmlrpc_lookup_entity($ent)
\r
213 global $xmlEntities;
\r
215 if (isset($xmlEntities[strtolower($ent)]))
\r
217 return $xmlEntities[strtolower($ent)];
\r
219 if (ereg("^#([0-9]+)$", $ent, $regs))
\r
221 return chr($regs[1]);
\r
227 * These entities originate from HTML specs (1.1, proposed 2.0, etc),
\r
228 * and are taken directly from php-4.3.1/ext/mbstring/html_entities.c.
\r
229 * Until php provides functionality to translate these entities in its
\r
230 * core library, use this function.
\r
232 function xmlrpc_html_entity_xlate($data = '')
\r
235 " " => " ",
\r
236 "¡" => "¡",
\r
237 "¢" => "¢",
\r
238 "£" => "£",
\r
239 "¤" => "¤",
\r
240 "¥" => "¥",
\r
241 "¦" => "¦",
\r
242 "§" => "§",
\r
243 "¨" => "¨",
\r
244 "©" => "©",
\r
245 "ª" => "ª",
\r
246 "«" => "«",
\r
247 "¬" => "¬",
\r
248 "­" => "­",
\r
249 "®" => "®",
\r
250 "¯" => "¯",
\r
251 "°" => "°",
\r
252 "±" => "±",
\r
253 "²" => "²",
\r
254 "³" => "³",
\r
255 "´" => "´",
\r
256 "µ" => "µ",
\r
257 "¶" => "¶",
\r
258 "·" => "·",
\r
259 "¸" => "¸",
\r
260 "¹" => "¹",
\r
261 "º" => "º",
\r
262 "»" => "»",
\r
263 "¼" => "¼",
\r
264 "½" => "½",
\r
265 "¾" => "¾",
\r
266 "¿" => "¿",
\r
267 "À" => "À",
\r
268 "Á" => "Á",
\r
269 "Â" => "Â",
\r
270 "Ã" => "Ã",
\r
271 "Ä" => "Ä",
\r
272 "Å" => "Å",
\r
273 "Æ" => "Æ",
\r
274 "Ç" => "Ç",
\r
275 "È" => "È",
\r
276 "É" => "É",
\r
277 "Ê" => "Ê",
\r
278 "Ë" => "Ë",
\r
279 "Ì" => "Ì",
\r
280 "Í" => "Í",
\r
281 "Î" => "Î",
\r
282 "Ï" => "Ï",
\r
283 "Ð" => "Ð",
\r
284 "Ñ" => "Ñ",
\r
285 "Ò" => "Ò",
\r
286 "Ó" => "Ó",
\r
287 "Ô" => "Ô",
\r
288 "Õ" => "Õ",
\r
289 "Ö" => "Ö",
\r
290 "×" => "×",
\r
291 "Ø" => "Ø",
\r
292 "Ù" => "Ù",
\r
293 "Ú" => "Ú",
\r
294 "Û" => "Û",
\r
295 "Ü" => "Ü",
\r
296 "Ý" => "Ý",
\r
297 "Þ" => "Þ",
\r
298 "ß" => "ß",
\r
299 "à" => "à",
\r
300 "á" => "á",
\r
301 "â" => "â",
\r
302 "ã" => "ã",
\r
303 "ä" => "ä",
\r
304 "å" => "å",
\r
305 "æ" => "æ",
\r
306 "ç" => "ç",
\r
307 "è" => "è",
\r
308 "é" => "é",
\r
309 "ê" => "ê",
\r
310 "ë" => "ë",
\r
311 "ì" => "ì",
\r
312 "í" => "í",
\r
313 "î" => "î",
\r
314 "ï" => "ï",
\r
315 "ð" => "ð",
\r
316 "ñ" => "ñ",
\r
317 "ò" => "ò",
\r
318 "ó" => "ó",
\r
319 "ô" => "ô",
\r
320 "õ" => "õ",
\r
321 "ö" => "ö",
\r
322 "÷" => "÷",
\r
323 "ø" => "ø",
\r
324 "ù" => "ù",
\r
325 "ú" => "ú",
\r
326 "û" => "û",
\r
327 "ü" => "ü",
\r
328 "ý" => "ý",
\r
329 "þ" => "þ",
\r
330 "ÿ" => "ÿ",
\r
331 "Œ" => "Œ",
\r
332 "œ" => "œ",
\r
333 "Š" => "Š",
\r
334 "š" => "š",
\r
335 "Ÿ" => "Ÿ",
\r
336 "ƒ" => "ƒ",
\r
337 "ˆ" => "ˆ",
\r
338 "˜" => "˜",
\r
339 "Α" => "Α",
\r
340 "Β" => "Β",
\r
341 "Γ" => "Γ",
\r
342 "Δ" => "Δ",
\r
343 "Ε" => "Ε",
\r
344 "Ζ" => "Ζ",
\r
345 "Η" => "Η",
\r
346 "Θ" => "Θ",
\r
347 "Ι" => "Ι",
\r
348 "Κ" => "Κ",
\r
349 "Λ" => "Λ",
\r
350 "Μ" => "Μ",
\r
351 "Ν" => "Ν",
\r
352 "Ξ" => "Ξ",
\r
353 "Ο" => "Ο",
\r
354 "Π" => "Π",
\r
355 "Ρ" => "Ρ",
\r
356 "Σ" => "Σ",
\r
357 "Τ" => "Τ",
\r
358 "Υ" => "Υ",
\r
359 "Φ" => "Φ",
\r
360 "Χ" => "Χ",
\r
361 "Ψ" => "Ψ",
\r
362 "Ω" => "Ω",
\r
363 "β" => "β",
\r
364 "γ" => "γ",
\r
365 "δ" => "δ",
\r
366 "ε" => "ε",
\r
367 "ζ" => "ζ",
\r
368 "η" => "η",
\r
369 "θ" => "θ",
\r
370 "ι" => "ι",
\r
371 "κ" => "κ",
\r
372 "λ" => "λ",
\r
373 "μ" => "μ",
\r
374 "ν" => "ν",
\r
375 "ξ" => "ξ",
\r
376 "ο" => "ο",
\r
377 "π" => "π",
\r
378 "ρ" => "ρ",
\r
379 "ς" => "ς",
\r
380 "σ" => "σ",
\r
381 "τ" => "τ",
\r
382 "υ" => "υ",
\r
383 "φ" => "φ",
\r
384 "χ" => "χ",
\r
385 "ψ" => "ψ",
\r
386 "ω" => "ω",
\r
387 "ϑ" => "ϑ",
\r
388 "ϒ" => "ϒ",
\r
389 "ϖ" => "ϖ",
\r
390 " " => " ",
\r
391 " " => " ",
\r
392 " " => " ",
\r
393 "‌" => "‌",
\r
394 "‍" => "‍",
\r
395 "‎" => "‎",
\r
396 "‏" => "‏",
\r
397 "–" => "–",
\r
398 "—" => "—",
\r
399 "‘" => "‘",
\r
400 "’" => "’",
\r
401 "‚" => "‚",
\r
402 "“" => "“",
\r
403 "”" => "”",
\r
404 "„" => "„",
\r
405 "†" => "†",
\r
406 "‡" => "‡",
\r
407 "•" => "•",
\r
408 "…" => "…",
\r
409 "‰" => "‰",
\r
410 "′" => "′",
\r
411 "″" => "″",
\r
412 "‹" => "‹",
\r
413 "›" => "›",
\r
414 "‾" => "‾",
\r
415 "⁄" => "⁄",
\r
416 "€" => "€",
\r
417 "℘" => "℘",
\r
418 "ℑ" => "ℑ",
\r
419 "ℜ" => "ℜ",
\r
420 "™" => "™",
\r
421 "ℵ" => "ℵ",
\r
422 "←" => "←",
\r
423 "↑" => "↑",
\r
424 "→" => "→",
\r
425 "↓" => "↓",
\r
426 "↔" => "↔",
\r
427 "↵" => "↵",
\r
428 "⇐" => "⇐",
\r
429 "⇑" => "⇑",
\r
430 "⇒" => "⇒",
\r
431 "⇓" => "⇓",
\r
432 "⇔" => "⇔",
\r
433 "∀" => "∀",
\r
434 "∂" => "∂",
\r
435 "∃" => "∃",
\r
436 "∅" => "∅",
\r
437 "∇" => "∇",
\r
438 "∈" => "∈",
\r
439 "∉" => "∉",
\r
440 "∋" => "∋",
\r
441 "∏" => "∏",
\r
442 "∑" => "∑",
\r
443 "−" => "−",
\r
444 "∗" => "∗",
\r
445 "√" => "√",
\r
446 "∝" => "∝",
\r
447 "∞" => "∞",
\r
448 "∠" => "∠",
\r
449 "∧" => "∧",
\r
450 "∨" => "∨",
\r
451 "∩" => "∩",
\r
452 "∪" => "∪",
\r
453 "∫" => "∫",
\r
454 "∴" => "∴",
\r
455 "∼" => "∼",
\r
456 "≅" => "≅",
\r
457 "≈" => "≈",
\r
458 "≠" => "≠",
\r
459 "≡" => "≡",
\r
460 "≤" => "≤",
\r
461 "≥" => "≥",
\r
462 "⊂" => "⊂",
\r
463 "⊃" => "⊃",
\r
464 "⊄" => "⊄",
\r
465 "⊆" => "⊆",
\r
466 "⊇" => "⊇",
\r
467 "⊕" => "⊕",
\r
468 "⊗" => "⊗",
\r
469 "⊥" => "⊥",
\r
470 "⋅" => "⋅",
\r
471 "⌈" => "⌈",
\r
472 "⌉" => "⌉",
\r
473 "⌊" => "⌊",
\r
474 "⌋" => "⌋",
\r
475 "⟨" => "〈",
\r
476 "⟩" => "〉",
\r
477 "◊" => "◊",
\r
478 "♠" => "♠",
\r
479 "♣" => "♣",
\r
480 "♥" => "♥",
\r
481 "♦" => "♦");
\r
482 return strtr($data, $entities);
\r
485 function xmlrpc_encode_entitites($data)
\r
487 $length = strlen($data);
\r
489 for($position = 0; $position < $length; $position++)
\r
491 $character = substr($data, $position, 1);
\r
492 $code = Ord($character);
\r
495 $character = """;
\r
498 $character = "&";
\r
501 $character = "'";
\r
504 $character = "<";
\r
507 $character = ">";
\r
510 if ($code < 32 || $code > 159)
\r
511 $character = ("&#".strval($code).";");
\r
514 $escapeddata .= $character;
\r
516 return $escapeddata;
\r
519 function xmlrpc_se($parser, $name, $attrs)
\r
521 global $_xh, $xmlrpcDateTime, $xmlrpcString;
\r
527 $_xh[$parser]['st'].='array(';
\r
528 $_xh[$parser]['cm']++;
\r
529 // this last line turns quoting off
\r
530 // this means if we get an empty array we'll
\r
531 // simply get a bit of whitespace in the eval
\r
532 $_xh[$parser]['qt']=0;
\r
535 $_xh[$parser]['st'].='"';
\r
536 $_xh[$parser]['ac']='';
\r
539 $_xh[$parser]['isf']=1;
\r
542 $_xh[$parser]['st']='';
\r
545 $_xh[$parser]['st'].='new xmlrpcval(';
\r
546 $_xh[$parser]['vt']=$xmlrpcString;
\r
547 $_xh[$parser]['ac']='';
\r
548 $_xh[$parser]['qt']=0;
\r
549 $_xh[$parser]['lv']=1;
\r
550 // look for a value: if this is still 1 by the
\r
551 // time we reach the first data segment then the type is string
\r
552 // by implication and we need to add in a quote
\r
559 case 'DATETIME.ISO8601':
\r
561 $_xh[$parser]['ac']=''; // reset the accumulator
\r
563 if ($name=='DATETIME.ISO8601' || $name=='STRING')
\r
565 $_xh[$parser]['qt']=1;
\r
566 if ($name=='DATETIME.ISO8601')
\r
568 $_xh[$parser]['vt']=$xmlrpcDateTime;
\r
571 elseif ($name=='BASE64')
\r
573 $_xh[$parser]['qt']=2;
\r
577 // No quoting is required here -- but
\r
578 // at the end of the element we must check
\r
579 // for data format errors.
\r
580 $_xh[$parser]['qt']=0;
\r
584 $_xh[$parser]['ac']='';
\r
590 if ($name!='VALUE')
\r
592 $_xh[$parser]['lv']=0;
\r
596 function xmlrpc_ee($parser, $name)
\r
598 global $_xh,$xmlrpcTypes,$xmlrpcString;
\r
604 if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')
\r
606 $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
\r
608 $_xh[$parser]['st'].=')';
\r
609 $_xh[$parser]['vt']=strtolower($name);
\r
610 $_xh[$parser]['cm']--;
\r
613 $_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';
\r
616 // special case here: we translate boolean 1 or 0 into PHP
\r
617 // constants true or false
\r
618 // NB: this simple checks helps a lot sanitizing input, ie no
\r
619 // security problems around here
\r
620 if ($_xh[$parser]['ac']=='1')
\r
622 $_xh[$parser]['ac']='true';
\r
626 $_xh[$parser]['ac']='false';
\r
628 $_xh[$parser]['vt']=strtolower($name);
\r
629 // Drop through intentionally.
\r
634 case 'DATETIME.ISO8601':
\r
636 if ($_xh[$parser]['qt']==1)
\r
638 // we use double quotes rather than single so backslashification works OK
\r
639 $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
\r
641 elseif ($_xh[$parser]['qt']==2)
\r
643 $_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';
\r
645 elseif ($name=='BOOLEAN')
\r
647 $_xh[$parser]['st'].=$_xh[$parser]['ac'];
\r
649 elseif ($name=='DOUBLE')
\r
651 // we have a DOUBLE
\r
652 // we must check that only 0123456789-.<space> are characters here
\r
653 if (!ereg("^[+-]?[eE0123456789 \\t\\.]+$", $_xh[$parser]['ac']))
\r
655 // TODO: find a better way of throwing an error
\r
657 error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']);
\r
658 $_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
\r
662 // it's ok, add it on
\r
663 $_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];
\r
668 // we have an I4/INT
\r
669 // we must check that only 0123456789-<space> are characters here
\r
670 if (!ereg("^[+-]?[0123456789 \\t]+$", $_xh[$parser]['ac']))
\r
672 // TODO: find a better way of throwing an error
\r
674 error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']);
\r
675 $_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
\r
679 // it's ok, add it on
\r
680 $_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];
\r
683 $_xh[$parser]['ac']='';
\r
684 $_xh[$parser]['qt']=0;
\r
685 $_xh[$parser]['lv']=3; // indicate we've found a value
\r
688 // deal with a string value
\r
689 if (strlen($_xh[$parser]['ac'])>0 &&
\r
690 $_xh[$parser]['vt']==$xmlrpcString)
\r
692 $_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
\r
694 // This if() detects if no scalar was inside <VALUE></VALUE>
\r
695 // and pads an empty ''.
\r
696 if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(')
\r
698 $_xh[$parser]['st'].= '""';
\r
700 // G. Giunta 2005/03/12 save some chars in the reconstruction of string vals...
\r
701 if ($_xh[$parser]['vt'] != $xmlrpcString)
\r
702 $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
\r
704 $_xh[$parser]['st'].=")";
\r
705 if ($_xh[$parser]['cm'])
\r
707 $_xh[$parser]['st'].=',';
\r
711 $_xh[$parser]['ac']='';
\r
712 $_xh[$parser]['qt']=0;
\r
715 $_xh[$parser]['ac']='';
\r
716 $_xh[$parser]['qt']=0;
\r
719 $_xh[$parser]['params'][]=$_xh[$parser]['st'];
\r
722 $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);
\r
724 // BOOLEAN HAS BEEN ENUMERATED ABOVE!
\r
726 // special case here: we translate boolean 1 or 0 into PHP
\r
727 // constants true or false
\r
728 if ($_xh[$parser]['ac']=='1')
\r
730 $_xh[$parser]['ac']='true';
\r
734 $_xh[$parser]['ac']='false';
\r
735 $_xh[$parser]['vt']=strtolower($name);
\r
741 // if it's a valid type name, set the type
\r
742 if (isset($xmlrpcTypes[strtolower($name)]))
\r
744 $_xh[$parser]['vt']=strtolower($name);
\r
748 function xmlrpc_cd($parser, $data)
\r
750 global $_xh, $xmlrpc_backslash;
\r
752 //if (ereg("^[\n\r \t]+$", $data)) return;
\r
753 // print "adding [${data}]\n";
\r
755 if ($_xh[$parser]['lv']!=3)
\r
757 // "lookforvalue==3" means that we've found an entire value
\r
758 // and should discard any further character data
\r
759 if ($_xh[$parser]['lv']==1)
\r
761 // if we've found text and we're just in a <value> then
\r
762 // turn quoting on, as this will be a string
\r
763 $_xh[$parser]['qt']=1;
\r
764 // and say we've found a value
\r
765 $_xh[$parser]['lv']=2;
\r
767 if(!@isset($_xh[$parser]['ac']))
\r
769 $_xh[$parser]['ac'] = '';
\r
771 $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
\r
775 function xmlrpc_dh($parser, $data)
\r
777 global $_xh, $xmlrpc_backslash;
\r
778 if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
\r
780 if ($_xh[$parser]['lv']==1)
\r
782 $_xh[$parser]['qt']=1;
\r
783 $_xh[$parser]['lv']=2;
\r
785 $_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
\r
789 class xmlrpc_client
\r
803 var $no_multicall=false;
\r
805 function xmlrpc_client($path, $server, $port=0)
\r
807 $this->port=$port; $this->server=$server; $this->path=$path;
\r
810 function setDebug($in)
\r
822 function setCredentials($u, $p)
\r
824 $this->username=$u;
\r
825 $this->password=$p;
\r
828 function setCertificate($cert, $certpass)
\r
830 $this->cert = $cert;
\r
831 $this->certpass = $certpass;
\r
834 function setSSLVerifyPeer($i)
\r
836 $this->verifypeer = $i;
\r
839 function setSSLVerifyHost($i)
\r
841 $this->verifyhost = $i;
\r
844 function send($msg, $timeout=0, $method='http')
\r
846 if (is_array($msg))
\r
848 // $msg is an array of xmlrpcmsg's
\r
849 return $this->multicall($msg, $timeout, $method);
\r
852 // where msg is an xmlrpcmsg
\r
853 $msg->debug=$this->debug;
\r
855 if ($method == 'https')
\r
857 return $this->sendPayloadHTTPS($msg,
\r
859 $this->port, $timeout,
\r
860 $this->username, $this->password,
\r
866 return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
\r
867 $timeout, $this->username,
\r
872 function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
\r
874 global $xmlrpcerr, $xmlrpcstr, $xmlrpcName, $xmlrpcVersion, $xmlrpc_defencoding;
\r
881 $fp=@fsockopen($server, $port,$this->errno, $this->errstr, $timeout);
\r
885 $fp=@fsockopen($server, $port,$this->errno, $this->errstr);
\r
889 if ($timeout>0 && function_exists('stream_set_timeout'))
\r
890 stream_set_timeout($fp, $timeout);
\r
894 $this->errstr='Connect error';
\r
895 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']);
\r
898 // Only create the payload if it was not created previously
\r
899 if(empty($msg->payload))
\r
901 $msg->createPayload();
\r
904 // thanks to Grant Rauscher <grant7@firstworld.net>
\r
909 $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
\r
912 $op= "POST " . $this->path. " HTTP/1.0\r\n" .
\r
913 "User-Agent: " . $xmlrpcName . " " . $xmlrpcVersion . "\r\n" .
\r
914 "Host: ". $server . "\r\n" .
\r
916 "Accept-Charset: " . $xmlrpc_defencoding . "\r\n" .
\r
917 "Content-Type: text/xml\r\nContent-Length: " .
\r
918 strlen($msg->payload) . "\r\n\r\n" .
\r
921 if (!fputs($fp, $op, strlen($op)))
\r
923 $this->errstr='Write error';
\r
924 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']);
\r
927 $resp=$msg->parseResponseFile($fp);
\r
932 // contributed by Justin Miller <justin@voxel.net>
\r
933 // requires curl to be built into PHP
\r
934 function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='')
\r
936 global $xmlrpcerr, $xmlrpcstr, $xmlrpcVersion, $xmlrpc_internalencoding;
\r
942 // Only create the payload if it was not created previously
\r
943 if(empty($msg->payload))
\r
945 $msg->createPayload();
\r
948 if (!function_exists('curl_init'))
\r
950 $this->errstr='SSL unavailable on this install';
\r
951 $r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']);
\r
955 $curl = curl_init('https://' . $server . ':' . $port . $this->path);
\r
957 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
\r
958 // results into variable
\r
961 curl_setopt($curl, CURLOPT_VERBOSE, 1);
\r
963 curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC '.$xmlrpcVersion);
\r
964 // required for XMLRPC
\r
965 curl_setopt($curl, CURLOPT_POST, 1);
\r
967 curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
\r
969 curl_setopt($curl, CURLOPT_HEADER, 1);
\r
970 // return the header too
\r
971 curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml', 'Accept-Charset: '.$xmlrpc_internalencoding));
\r
972 // whether to verify remote host's cert
\r
973 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
\r
974 // 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
\r
975 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
\r
976 // required for XMLRPC
\r
979 curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
\r
981 // timeout is borked
\r
982 if ($username && $password)
\r
984 curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
\r
989 curl_setopt($curl, CURLOPT_SSLCERT, $cert);
\r
994 curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass);
\r
996 // set cert password
\r
998 $result = curl_exec($curl);
\r
1002 $this->errstr='no response';
\r
1003 $resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl));
\r
1004 curl_close($curl);
\r
1008 curl_close($curl);
\r
1009 $resp = $msg->parseResponse($result);
\r
1014 function multicall($msgs, $timeout=0, $method='http')
\r
1018 if (! $this->no_multicall)
\r
1020 $results = $this->_try_multicall($msgs, $timeout, $method);
\r
1021 /* TODO - this is not php3-friendly */
\r
1022 // if($results !== false)
\r
1023 if(is_array($results))
\r
1025 // Either the system.multicall succeeded, or the send
\r
1026 // failed (e.g. due to HTTP timeout). In either case,
\r
1027 // we're done for now.
\r
1032 // system.multicall unsupported by server,
\r
1033 // don't try it next time...
\r
1034 $this->no_multicall = true;
\r
1038 // system.multicall is unupported by server:
\r
1039 // Emulate multicall via multiple requests
\r
1040 $results = array();
\r
1041 //foreach($msgs as $msg)
\r
1043 while(list(,$msg) = @each($msgs))
\r
1045 $results[] = $this->send($msg, $timeout, $method);
\r
1050 // Attempt to boxcar $msgs via system.multicall.
\r
1051 function _try_multicall($msgs, $timeout, $method)
\r
1053 // Construct multicall message
\r
1055 //foreach($msgs as $msg)
\r
1057 while(list(,$msg) = @each($msgs))
\r
1059 $call['methodName'] = new xmlrpcval($msg->method(),'string');
\r
1060 $numParams = $msg->getNumParams();
\r
1061 $params = array();
\r
1062 for ($i = 0; $i < $numParams; $i++)
\r
1064 $params[$i] = $msg->getParam($i);
\r
1066 $call['params'] = new xmlrpcval($params, 'array');
\r
1067 $calls[] = new xmlrpcval($call, 'struct');
\r
1069 $multicall = new xmlrpcmsg('system.multicall');
\r
1070 $multicall->addParam(new xmlrpcval($calls, 'array'));
\r
1072 // Attempt RPC call
\r
1073 $result = $this->send($multicall, $timeout, $method);
\r
1074 if(!is_object($result))
\r
1076 return ($result || 0); // transport failed
\r
1079 if($result->faultCode() != 0)
\r
1081 return false; // system.multicall failed
\r
1084 // Unpack responses.
\r
1085 $rets = $result->value();
\r
1086 if($rets->kindOf() != 'array')
\r
1088 return false; // bad return type from system.multicall
\r
1090 $numRets = $rets->arraysize();
\r
1091 if($numRets != count($msgs))
\r
1093 return false; // wrong number of return values.
\r
1096 $response = array();
\r
1097 for ($i = 0; $i < $numRets; $i++)
\r
1099 $val = $rets->arraymem($i);
\r
1100 switch ($val->kindOf())
\r
1103 if($val->arraysize() != 1)
\r
1105 return false; // Bad value
\r
1107 // Normal return value
\r
1108 $response[$i] = new xmlrpcresp($val->arraymem(0));
\r
1111 $code = $val->structmem('faultCode');
\r
1112 if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
\r
1116 $str = $val->structmem('faultString');
\r
1117 if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
\r
1121 $response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
\r
1129 } // end class xmlrpc_client
\r
1136 var $hdrs = array();
\r
1138 function xmlrpcresp($val, $fcode = 0, $fstr = '')
\r
1143 $this->errno = $fcode;
\r
1144 $this->errstr = $fstr;
\r
1145 //$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
\r
1147 elseif (!is_object($val))
\r
1149 // programmer error
\r
1150 error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value.");
\r
1151 $this->val = new xmlrpcval();
\r
1156 $this->val = $val;
\r
1160 function faultCode()
\r
1162 return $this->errno;
\r
1165 function faultString()
\r
1167 return $this->errstr;
\r
1172 return $this->val;
\r
1175 function serialize()
\r
1177 $result = "<methodResponse>\n";
\r
1180 // G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients
\r
1181 $result .= '<fault>
\r
1185 <name>faultCode</name>
\r
1186 <value><int>' . $this->errno . '</int></value>
\r
1189 <name>faultString</name>
\r
1190 <value><string>' . xmlrpc_encode_entitites($this->errstr) . '</string></value>
\r
1198 $result .= "<params>\n<param>\n" .
\r
1199 $this->val->serialize() .
\r
1200 "</param>\n</params>";
\r
1202 $result .= "\n</methodResponse>";
\r
1211 var $params=array();
\r
1214 function xmlrpcmsg($meth, $pars=0)
\r
1216 $this->methodname=$meth;
\r
1217 if (is_array($pars) && sizeof($pars)>0)
\r
1219 for($i=0; $i<sizeof($pars); $i++)
\r
1221 $this->addParam($pars[$i]);
\r
1226 function xml_header()
\r
1228 return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
\r
1231 function xml_footer()
\r
1233 return "</methodCall>\n";
\r
1236 function createPayload()
\r
1238 $this->payload=$this->xml_header();
\r
1239 $this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
\r
1240 // if (sizeof($this->params)) {
\r
1241 $this->payload.="<params>\n";
\r
1242 for($i=0; $i<sizeof($this->params); $i++)
\r
1244 $p=$this->params[$i];
\r
1245 $this->payload.="<param>\n" . $p->serialize() .
\r
1248 $this->payload.="</params>\n";
\r
1250 $this->payload.=$this->xml_footer();
\r
1251 //$this->payload=str_replace("\n", "\r\n", $this->payload);
\r
1254 function method($meth='')
\r
1258 $this->methodname=$meth;
\r
1260 return $this->methodname;
\r
1263 function serialize()
\r
1265 $this->createPayload();
\r
1266 return $this->payload;
\r
1269 function addParam($par) { $this->params[]=$par; }
\r
1270 function getParam($i) { return $this->params[$i]; }
\r
1271 function getNumParams() { return sizeof($this->params); }
\r
1273 function parseResponseFile($fp)
\r
1276 while($data=fread($fp, 32768))
\r
1280 return $this->parseResponse($ipd);
\r
1283 function parseResponse($data='')
\r
1285 global $_xh,$xmlrpcerr,$xmlrpcstr;
\r
1286 global $xmlrpc_defencoding, $xmlrpc_internalencoding;
\r
1291 //by maHo, replaced htmlspecialchars with htmlentities
\r
1292 print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
\r
1297 error_log('No response received from server.');
\r
1298 $r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']);
\r
1301 // see if we got an HTTP 200 OK, else bomb
\r
1302 // but only do this if we're using the HTTP protocol.
\r
1303 if(ereg("^HTTP",$data))
\r
1305 // Strip HTTP 1.1 100 Continue header if present
\r
1306 while (ereg('^HTTP/1.1 1[0-9]{2}', $data))
\r
1308 $pos = strpos($data, 'HTTP', 12);
\r
1309 // server sent a Continue header without any (valid) content following...
\r
1310 // give the client a chance to know it
\r
1311 if (!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
\r
1313 $data = substr($data, $pos);
\r
1315 if (!ereg("^HTTP/[0-9\\.]+ 200 ", $data))
\r
1317 $errstr= substr($data, 0, strpos($data, "\n")-1);
\r
1318 error_log('HTTP error, got response: ' .$errstr);
\r
1319 $r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')');
\r
1323 $parser = xml_parser_create($xmlrpc_defencoding);
\r
1325 // G. Giunta 2004/04/06
\r
1326 // Clean up the accumulator, or it will grow indefinitely long
\r
1327 // if making xmlrpc calls for a while
\r
1329 $_xh[$parser]=array();
\r
1330 $_xh[$parser]['headers'] = array();
\r
1332 // separate HTTP headers from data
\r
1333 if (ereg("^HTTP", $data))
\r
1335 // be tolerant to usage of \n instead of \r\n to separate headers and data
\r
1336 // (even though it is not valid http)
\r
1337 $pos = strpos($data,"\r\n\r\n");
\r
1338 if($pos || is_int($pos))
\r
1342 $pos = strpos($data,"\n\n");
\r
1343 if($pos || is_int($pos))
\r
1347 // No separation between response headers and body: fault?
\r
1351 // be tolerant to line endings, and extra empty lines
\r
1352 $ar = split("\r?\n", trim(substr($data, 0, $pos)));
\r
1353 while (list(,$line) = @each($ar))
\r
1355 // take care of multi-line headers
\r
1356 $arr = explode(':',$line);
\r
1357 if(count($arr) > 1)
\r
1359 $header_name = trim($arr[0]);
\r
1360 // TO DO: some headers (the ones that allow a CSV list of values)
\r
1361 // do allow many values to be passed using multiple header lines.
\r
1362 // We should add content to $_xh[$parser]['headers'][$header_name]
\r
1363 // instead of replacing it for those...
\r
1364 $_xh[$parser]['headers'][$header_name] = $arr[1];
\r
1365 for ($i = 2; $i < count($arr); $i++)
\r
1367 $_xh[$parser]['headers'][$header_name] .= ':'.$arr[$i];
\r
1369 $_xh[$parser]['headers'][$header_name] = trim($_xh[$parser]['headers'][$header_name]);
\r
1370 } else if (isset($header_name))
\r
1372 $_xh[$parser]['headers'][$header_name] .= ' ' . trim($line);
\r
1375 $data = substr($data, $bd);
\r
1377 if ($this->debug && count($_xh[$parser]['headers']))
\r
1380 //foreach ($_xh[$parser]['headers'] as $header)
\r
1381 @reset($_xh[$parser]['headers']);
\r
1382 while(list($header, $value) = @each($_xh[$parser]['headers']))
\r
1384 print "HEADER: $header: $value\n";
\r
1390 // be tolerant of extra whitespace in response body
\r
1391 $data = trim($data);
\r
1393 // be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
\r
1394 // idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
\r
1396 $pos = strpos($data, "</methodResponse>");
\r
1397 while ($pos || is_int($pos))
\r
1400 $pos = strpos($data, "</methodResponse>", $bd);
\r
1403 $data = substr($data, 0, $bd);
\r
1405 $_xh[$parser]['st']='';
\r
1406 $_xh[$parser]['cm']=0;
\r
1407 $_xh[$parser]['isf']=0;
\r
1408 $_xh[$parser]['ac']='';
\r
1409 $_xh[$parser]['qt']='';
\r
1411 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
\r
1412 // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
\r
1413 // the xml parser to give us back data in the expected charset
\r
1414 xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding);
\r
1416 xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
\r
1417 xml_set_character_data_handler($parser, 'xmlrpc_cd');
\r
1418 xml_set_default_handler($parser, 'xmlrpc_dh');
\r
1419 //$xmlrpc_value=new xmlrpcval;
\r
1421 if (!xml_parse($parser, $data, sizeof($data)))
\r
1423 // thanks to Peter Kocks <peter.kocks@baygate.com>
\r
1424 if((xml_get_current_line_number($parser)) == 1)
\r
1426 $errstr = 'XML error at line 1, check URL';
\r
1430 $errstr = sprintf('XML error: %s at line %d',
\r
1431 xml_error_string(xml_get_error_code($parser)),
\r
1432 xml_get_current_line_number($parser));
\r
1434 error_log($errstr);
\r
1435 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return'].' ('.$errstr.')');
\r
1436 xml_parser_free($parser);
\r
1439 $r->hdrs = $_xh[$parser]['headers'];
\r
1442 xml_parser_free($parser);
\r
1445 print "<PRE>---EVALING---[" .
\r
1446 strlen($_xh[$parser]['st']) . " chars]---\n" .
\r
1447 htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";
\r
1449 if (strlen($_xh[$parser]['st'])==0)
\r
1451 // then something odd has happened
\r
1452 // and it's time to generate a client side error
\r
1453 // indicating something odd went on
\r
1454 $r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
\r
1455 $xmlrpcstr['invalid_return']);
\r
1460 @eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');
\r
1463 $r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);
\r
1466 if ($_xh[$parser]['isf'])
\r
1468 $errno_v = $v->structmem('faultCode');
\r
1469 $errstr_v = $v->structmem('faultString');
\r
1470 $errno = $errno_v->scalarval();
\r
1474 // FAULT returned, errno needs to reflect that
\r
1478 $r = new xmlrpcresp($v, $errno, $errstr_v->scalarval());
\r
1482 $r=new xmlrpcresp($v);
\r
1486 $r->hdrs = $_xh[$parser]['headers'];
\r
1496 function xmlrpcval($val=-1, $type='')
\r
1498 global $xmlrpcTypes;
\r
1499 $this->me=array();
\r
1501 if ($val!=-1 || !is_int($val) || $type!='')
\r
1507 if ($xmlrpcTypes[$type]==1)
\r
1509 $this->addScalar($val,$type);
\r
1511 elseif ($xmlrpcTypes[$type]==2)
\r
1513 $this->addArray($val);
\r
1515 elseif ($xmlrpcTypes[$type]==3)
\r
1517 $this->addStruct($val);
\r
1522 function addScalar($val, $type='string')
\r
1524 global $xmlrpcTypes, $xmlrpcBoolean;
\r
1526 if ($this->mytype==1)
\r
1528 echo '<B>xmlrpcval</B>: scalar can have only one value<BR>';
\r
1531 $typeof=$xmlrpcTypes[$type];
\r
1534 echo '<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>';
\r
1538 if ($type==$xmlrpcBoolean)
\r
1540 if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
\r
1550 if ($this->mytype==2)
\r
1552 // we're adding to an array here
\r
1553 $ar=$this->me['array'];
\r
1554 $ar[]=new xmlrpcval($val, $type);
\r
1555 $this->me['array']=$ar;
\r
1559 // a scalar, so set the value and remember we're scalar
\r
1560 $this->me[$type]=$val;
\r
1561 $this->mytype=$typeof;
\r
1566 function addArray($vals)
\r
1568 global $xmlrpcTypes;
\r
1569 if ($this->mytype!=0)
\r
1571 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
\r
1575 $this->mytype=$xmlrpcTypes['array'];
\r
1576 $this->me['array']=$vals;
\r
1580 function addStruct($vals)
\r
1582 global $xmlrpcTypes;
\r
1583 if ($this->mytype!=0)
\r
1585 echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
\r
1588 $this->mytype=$xmlrpcTypes['struct'];
\r
1589 $this->me['struct']=$vals;
\r
1593 function dump($ar)
\r
1596 while ( list( $key, $val ) = each( $ar ) )
\r
1598 echo "$key => $val<br>";
\r
1599 if ($key == 'array')
\r
1601 while ( list( $key2, $val2 ) = each( $val ) )
\r
1603 echo "-- $key2 => $val2<br>";
\r
1611 switch($this->mytype)
\r
1627 function serializedata($typ, $val)
\r
1630 global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,
\r
1632 switch(@$xmlrpcTypes[$typ])
\r
1636 $rs.="<struct>\n";
\r
1638 while(list($key2, $val2)=each($val))
\r
1640 $rs.="<member><name>${key2}</name>\n";
\r
1641 $rs.=$this->serializeval($val2);
\r
1642 $rs.="</member>\n";
\r
1648 $rs.="<array>\n<data>\n";
\r
1649 for($i=0; $i<sizeof($val); $i++)
\r
1651 $rs.=$this->serializeval($val[$i]);
\r
1653 $rs.="</data>\n</array>";
\r
1658 case $xmlrpcBase64:
\r
1659 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
\r
1661 case $xmlrpcBoolean:
\r
1662 $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
\r
1664 case $xmlrpcString:
\r
1665 // G. Giunta 2005/2/13: do NOT use htmlentities, since
\r
1666 // it will produce named html entities, which are invalid xml
\r
1667 // $rs.="<${typ}>" . xmlrpc_encode_entitites($val). "</${typ}>";
\r
1668 // $rs.="<${typ}>" . htmlentities($val). "</${typ}>";
\r
1670 // N. Leenheer 2005/6/30: Use CDATA instead...
\r
1671 $rs.="<${typ}><![CDATA[" . $val. "]]></${typ}>";
\r
1674 $rs.="<${typ}>${val}</${typ}>";
\r
1683 function serialize()
\r
1685 return $this->serializeval($this);
\r
1688 function serializeval($o)
\r
1690 //global $xmlrpcTypes;
\r
1694 list($typ, $val) = each($ar);
\r
1696 $rs.=$this->serializedata($typ, $val);
\r
1697 $rs.="</value>\n";
\r
1701 function structmem($m)
\r
1703 $nv=$this->me['struct'][$m];
\r
1707 function structreset()
\r
1709 reset($this->me['struct']);
\r
1712 function structeach()
\r
1714 return each($this->me['struct']);
\r
1720 global $xmlrpcBoolean, $xmlrpcBase64;
\r
1722 list($a,$b)=each($this->me);
\r
1723 // contributed by I Sofer, 2001-03-24
\r
1724 // add support for nested arrays to scalarval
\r
1725 // i've created a new method here, so as to
\r
1726 // preserve back compatibility
\r
1731 while(list($id,$cont) = @each($b))
\r
1733 $b[$id] = $cont->scalarval();
\r
1737 // add support for structures directly encoding php objects
\r
1738 if (is_object($b))
\r
1740 $t = get_object_vars($b);
\r
1742 while(list($id,$cont) = @each($t))
\r
1744 $t[$id] = $cont->scalarval();
\r
1747 while(list($id,$cont) = @each($t))
\r
1749 eval('$b->'.$id.' = $cont;');
\r
1756 function scalarval()
\r
1758 //global $xmlrpcBoolean, $xmlrpcBase64;
\r
1760 list($a,$b)=each($this->me);
\r
1764 function scalartyp()
\r
1766 global $xmlrpcI4, $xmlrpcInt;
\r
1768 list($a,$b)=each($this->me);
\r
1769 if ($a==$xmlrpcI4)
\r
1776 function arraymem($m)
\r
1778 $nv=$this->me['array'][$m];
\r
1782 function arraysize()
\r
1785 list($a,$b)=each($this->me);
\r
1786 return sizeof($b);
\r
1791 function iso8601_encode($timet, $utc=0)
\r
1793 // return an ISO8601 encoded string
\r
1794 // really, timezones ought to be supported
\r
1795 // but the XML-RPC spec says:
\r
1797 // "Don't assume a timezone. It should be specified by the server in its
\r
1798 // documentation what assumptions it makes about timezones."
\r
1800 // these routines always assume localtime unless
\r
1801 // $utc is set to 1, in which case UTC is assumed
\r
1802 // and an adjustment for locale is made when encoding
\r
1805 $t=strftime("%Y%m%dT%H:%M:%S", $timet);
\r
1809 if (function_exists('gmstrftime'))
\r
1811 // gmstrftime doesn't exist in some versions
\r
1813 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
\r
1817 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z'));
\r
1823 function iso8601_decode($idate, $utc=0)
\r
1825 // return a timet in the localtime, or UTC
\r
1827 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs))
\r
1831 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
\r
1835 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
\r
1841 /****************************************************************
\r
1842 * xmlrpc_decode takes a message in PHP xmlrpc object format and *
\r
1843 * tranlates it into native PHP types. *
\r
1845 * author: Dan Libby (dan@libby.com) *
\r
1846 ****************************************************************/
\r
1847 function php_xmlrpc_decode($xmlrpc_val)
\r
1849 $kind = $xmlrpc_val->kindOf();
\r
1851 if($kind == 'scalar')
\r
1853 return $xmlrpc_val->scalarval();
\r
1855 elseif($kind == 'array')
\r
1857 $size = $xmlrpc_val->arraysize();
\r
1860 for($i = 0; $i < $size; $i++)
\r
1862 $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i));
\r
1866 elseif($kind == 'struct')
\r
1868 $xmlrpc_val->structreset();
\r
1871 while(list($key,$value)=$xmlrpc_val->structeach())
\r
1873 $arr[$key] = php_xmlrpc_decode($value);
\r
1879 if(function_exists('xmlrpc_decode'))
\r
1881 define('XMLRPC_EPI_ENABLED','1');
\r
1885 define('XMLRPC_EPI_ENABLED','0');
\r
1886 function xmlrpc_decode($xmlrpc_val)
\r
1888 $kind = $xmlrpc_val->kindOf();
\r
1890 if($kind == 'scalar')
\r
1892 return $xmlrpc_val->scalarval();
\r
1894 elseif($kind == 'array')
\r
1896 $size = $xmlrpc_val->arraysize();
\r
1899 for($i = 0; $i < $size; $i++)
\r
1901 $arr[]=xmlrpc_decode($xmlrpc_val->arraymem($i));
\r
1905 elseif($kind == 'struct')
\r
1907 $xmlrpc_val->structreset();
\r
1910 while(list($key,$value)=$xmlrpc_val->structeach())
\r
1912 $arr[$key] = xmlrpc_decode($value);
\r
1919 /****************************************************************
\r
1920 * xmlrpc_encode takes native php types and encodes them into *
\r
1921 * xmlrpc PHP object format. *
\r
1922 * BUG: All sequential arrays are turned into structs. I don't *
\r
1923 * know of a good way to determine if an array is sequential *
\r
1926 * feature creep -- could support more types via optional type *
\r
1929 * author: Dan Libby (dan@libby.com) *
\r
1930 ****************************************************************/
\r
1931 function php_xmlrpc_encode($php_val)
\r
1933 global $xmlrpcInt;
\r
1934 global $xmlrpcDouble;
\r
1935 global $xmlrpcString;
\r
1936 global $xmlrpcArray;
\r
1937 global $xmlrpcStruct;
\r
1938 global $xmlrpcBoolean;
\r
1940 $type = gettype($php_val);
\r
1941 $xmlrpc_val = new xmlrpcval;
\r
1948 while (list($k,$v) = each($php_val))
\r
1950 $arr[$k] = php_xmlrpc_encode($v);
\r
1952 $xmlrpc_val->addStruct($arr);
\r
1955 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
\r
1958 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
\r
1961 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
\r
1963 // <G_Giunta_2001-02-29>
\r
1964 // Add support for encoding/decoding of booleans, since they are supported in PHP
\r
1966 $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
\r
1968 // </G_Giunta_2001-02-29>
\r
1969 // catch "resource", "NULL", "user function", "unknown type"
\r
1970 //case 'unknown type':
\r
1972 // giancarlo pinerolo <ping@alt.it>
\r
1973 // it has to return
\r
1974 // an empty object in case (which is already
\r
1975 // at this point), not a boolean.
\r
1978 return $xmlrpc_val;
\r
1981 if(XMLRPC_EPI_ENABLED == '0')
\r
1983 function xmlrpc_encode($php_val)
\r
1985 global $xmlrpcInt;
\r
1986 global $xmlrpcDouble;
\r
1987 global $xmlrpcString;
\r
1988 global $xmlrpcArray;
\r
1989 global $xmlrpcStruct;
\r
1990 global $xmlrpcBoolean;
\r
1992 $type = gettype($php_val);
\r
1993 $xmlrpc_val = new xmlrpcval;
\r
2000 while (list($k,$v) = each($php_val))
\r
2002 $arr[$k] = xmlrpc_encode($v);
\r
2004 $xmlrpc_val->addStruct($arr);
\r
2007 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
\r
2010 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
\r
2013 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
\r
2015 // <G_Giunta_2001-02-29>
\r
2016 // Add support for encoding/decoding of booleans, since they are supported in PHP
\r
2018 $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
\r
2020 // </G_Giunta_2001-02-29>
\r
2021 //case 'unknown type':
\r
2023 // giancarlo pinerolo <ping@alt.it>
\r
2024 // it has to return
\r
2025 // an empty object in case (which is already
\r
2026 // at this point), not a boolean.
\r
2029 return $xmlrpc_val;
\r