/[cvs]/nfo/site/htdocs/libs/XML/RPC.php
ViewVC logotype

Contents of /nfo/site/htdocs/libs/XML/RPC.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations)
Mon Aug 30 02:35:56 2004 UTC (20 years ago) by joko
Branch: MAIN
CVS Tags: alpha-20040904-1, HEAD
initial commit

1 <?php
2 // /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // by Edd Dumbill (C) 1999-2001
4 // <edd@usefulinc.com>
5 // $Id: RPC.php,v 1.21 2004/03/15 13:51:44 pajoye Exp $
6
7 // License is granted to use or modify this software ("XML-RPC for PHP")
8 // for commercial or non-commercial use provided the copyright of the author
9 // is preserved in any distributed or derivative work.
10
11 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
12 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14 // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
15 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
22 // Adapted to PEAR standards by Stig S�her Bakken <stig@php.net> and
23 // Martin Jansen <mj@php.net>
24 // /* $id$ */
25
26 if (!function_exists('xml_parser_create')) {
27 // Win 32 fix. From: "Leo West" <lwest@imaginet.fr>
28 if ($WINDIR) {
29 dl("php_xml.dll");
30 } else {
31 dl("xml.so");
32 }
33 }
34
35 define('XML_RPC_ERROR_INVALID_TYPE', 101);
36 define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
37 define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
38 define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
39
40 $GLOBALS['XML_RPC_I4'] = "i4";
41 $GLOBALS['XML_RPC_Int'] = "int";
42 $GLOBALS['XML_RPC_Boolean'] = "boolean";
43 $GLOBALS['XML_RPC_Double'] = "double";
44 $GLOBALS['XML_RPC_String'] = "string";
45 $GLOBALS['XML_RPC_DateTime'] = "dateTime.iso8601";
46 $GLOBALS['XML_RPC_Base64'] = "base64";
47 $GLOBALS['XML_RPC_Array'] = "array";
48 $GLOBALS['XML_RPC_Struct'] = "struct";
49
50 $GLOBALS['XML_RPC_Types'] = array($GLOBALS['XML_RPC_I4'] => 1,
51 $GLOBALS['XML_RPC_Int'] => 1,
52 $GLOBALS['XML_RPC_Boolean'] => 1,
53 $GLOBALS['XML_RPC_String'] => 1,
54 $GLOBALS['XML_RPC_Double'] => 1,
55 $GLOBALS['XML_RPC_DateTime'] => 1,
56 $GLOBALS['XML_RPC_Base64'] => 1,
57 $GLOBALS['XML_RPC_Array'] => 2,
58 $GLOBALS['XML_RPC_Struct'] => 3);
59
60 $GLOBALS['XML_RPC_entities'] = array("quot" => '"',
61 "amp" => "&",
62 "lt" => "<",
63 "gt" => ">",
64 "apos" => "'");
65
66 $GLOBALS['XML_RPC_err']["unknown_method"] = 1;
67 $GLOBALS['XML_RPC_str']["unknown_method"] = "Unknown method";
68 $GLOBALS['XML_RPC_err']["invalid_return"] = 2;
69 $GLOBALS['XML_RPC_str']["invalid_return"] = "Invalid return payload: enabling debugging to examine incoming payload";
70 $GLOBALS['XML_RPC_err']["incorrect_params"] = 3;
71 $GLOBALS['XML_RPC_str']["incorrect_params"] = "Incorrect parameters passed to method";
72 $GLOBALS['XML_RPC_err']["introspect_unknown"] = 4;
73 $GLOBALS['XML_RPC_str']["introspect_unknown"] = "Can't introspect: method unknown";
74 $GLOBALS['XML_RPC_err']["http_error"] = 5;
75 $GLOBALS['XML_RPC_str']["http_error"] = "Didn't receive 200 OK from remote server.";
76
77 $GLOBALS['XML_RPC_defencoding'] = "UTF-8";
78
79 // let user errors start at 800
80 $GLOBALS['XML_RPC_erruser'] = 800;
81
82 // let XML parse errors start at 100
83 $GLOBALS['XML_RPC_errxml'] = 100;
84
85 // formulate backslashes for escaping regexp
86 $GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
87
88 $GLOBALS['XML_RPC_twoslash'] = $GLOBALS['XML_RPC_backslash'] . $GLOBALS['XML_RPC_backslash'];
89 $GLOBALS['XML_RPC_twoslash'] = "2SLS";
90
91 // used to store state during parsing
92 // quick explanation of components:
93 // st - used to build up a string for evaluation
94 // ac - used to accumulate values
95 // qt - used to decide if quotes are needed for evaluation
96 // cm - used to denote struct or array (comma needed)
97 // isf - used to indicate a fault
98 // lv - used to indicate "looking for a value": implements
99 // the logic to allow values with no types to be strings
100 // params - used to store parameters in method calls
101 // method - used to store method name
102
103 $GLOBALS['XML_RPC_xh'] = array();
104
105 function XML_RPC_entity_decode($string)
106 {
107 $top = split("&", $string);
108 $op = "";
109 $i = 0;
110 while($i < sizeof($top)) {
111 if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs)) {
112 $op .= ereg_replace("^[#a-zA-Z0-9]+;",
113 XML_RPC_lookup_entity($regs[1]),
114 $top[$i]);
115 } else {
116 if ($i == 0) {
117 $op = $top[$i];
118 } else {
119 $op .= "&" . $top[$i];
120 }
121 }
122
123 $i++;
124 }
125 return $op;
126 }
127
128
129 function XML_RPC_lookup_entity($ent)
130 {
131 global $XML_RPC_entities;
132
133 if ($XML_RPC_entities[strtolower($ent)]) {
134 return $XML_RPC_entities[strtolower($ent)];
135 }
136
137 if (ereg("^#([0-9]+)$", $ent, $regs)) {
138 return chr($regs[1]);
139 }
140
141 return "?";
142 }
143
144
145 function XML_RPC_se($parser, $name, $attrs)
146 {
147 global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
148
149 switch ($name) {
150 case "STRUCT":
151 case "ARRAY":
152 $XML_RPC_xh[$parser]['st'] .= "array(";
153 $XML_RPC_xh[$parser]['cm']++;
154 // this last line turns quoting off
155 // this means if we get an empty array we'll
156 // simply get a bit of whitespace in the eval
157 $XML_RPC_xh[$parser]['qt'] = 0;
158 break;
159
160 case "NAME":
161 $XML_RPC_xh[$parser]['st'] .= "'";
162 $XML_RPC_xh[$parser]['ac'] = "";
163 break;
164
165 case "FAULT":
166 $XML_RPC_xh[$parser]['isf'] = 1;
167 break;
168
169 case "PARAM":
170 $XML_RPC_xh[$parser]['st'] = "";
171 break;
172
173 case "VALUE":
174 $XML_RPC_xh[$parser]['st'] .= "new XML_RPC_Value(";
175 $XML_RPC_xh[$parser]['lv'] = 1;
176 $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
177 $XML_RPC_xh[$parser]['ac'] = "";
178 $XML_RPC_xh[$parser]['qt'] = 0;
179 // look for a value: if this is still 1 by the
180 // time we reach the first data segment then the type is string
181 // by implication and we need to add in a quote
182 break;
183
184 case "I4":
185 case "INT":
186 case "STRING":
187 case "BOOLEAN":
188 case "DOUBLE":
189 case "DATETIME.ISO8601":
190 case "BASE64":
191 $XML_RPC_xh[$parser]['ac'] = ""; // reset the accumulator
192
193 if ($name == "DATETIME.ISO8601" || $name == "STRING") {
194 $XML_RPC_xh[$parser]['qt'] = 1;
195
196 if ($name == "DATETIME.ISO8601") {
197 $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
198 }
199
200 } elseif ($name == "BASE64") {
201 $XML_RPC_xh[$parser]['qt'] = 2;
202 } else {
203 // No quoting is required here -- but
204 // at the end of the element we must check
205 // for data format errors.
206 $XML_RPC_xh[$parser]['qt'] = 0;
207 }
208 break;
209
210 case "MEMBER":
211 $XML_RPC_xh[$parser]['ac'] = "";
212 break;
213
214 default:
215 break;
216 }
217
218 if ($name!="VALUE") {
219 $XML_RPC_xh[$parser]['lv'] = 0;
220 }
221 }
222
223
224 function XML_RPC_ee($parser, $name)
225 {
226 global $XML_RPC_xh,$XML_RPC_Types,$XML_RPC_String;
227
228 switch ($name) {
229 case "STRUCT":
230 case "ARRAY":
231 if ($XML_RPC_xh[$parser]['cm'] && substr($XML_RPC_xh[$parser]['st'], -1) == ',') {
232 $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'],0,-1);
233 }
234
235 $XML_RPC_xh[$parser]['st'] .= ")";
236 $XML_RPC_xh[$parser]['vt'] = strtolower($name);
237 $XML_RPC_xh[$parser]['cm']--;
238 break;
239
240 case "NAME":
241 $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . "' => ";
242 break;
243
244 case "BOOLEAN":
245 // special case here: we translate boolean 1 or 0 into PHP
246 // constants true or false
247 if ($XML_RPC_xh[$parser]['ac'] == '1') {
248 $XML_RPC_xh[$parser]['ac'] = "true";
249 } else {
250 $XML_RPC_xh[$parser]['ac'] = "false";
251 }
252
253 $XML_RPC_xh[$parser]['vt'] = strtolower($name);
254 // Drop through intentionally.
255
256 case "I4":
257 case "INT":
258 case "STRING":
259 case "DOUBLE":
260 case "DATETIME.ISO8601":
261 case "BASE64":
262 if ($XML_RPC_xh[$parser]['qt'] == 1) {
263 // we use double quotes rather than single so backslashification works OK
264 $XML_RPC_xh[$parser]['st'] .= "\"" . $XML_RPC_xh[$parser]['ac'] . "\"";
265 } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
266 $XML_RPC_xh[$parser]['st'] .= "base64_decode('" . $XML_RPC_xh[$parser]['ac'] . "')";
267 } elseif ($name=="BOOLEAN") {
268 $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
269 } else {
270 // we have an I4, INT or a DOUBLE
271 // we must check that only 0123456789-.<space> are characters here
272 if (!ereg("^\-?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
273 $this->raiseError("Non-numeric value recieved in INT or DOUBLE", XML_RPC_ERROR_NON_NUMERIC_FOUND);
274 $XML_RPC_xh[$parser]['st'] .= "ERROR_NON_NUMERIC_FOUND";
275 } else {
276 // it's ok, add it on
277 $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
278 }
279 }
280
281 $XML_RPC_xh[$parser]['ac'] = "";
282 $XML_RPC_xh[$parser]['qt'] = 0;
283 $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
284 break;
285
286 case "VALUE":
287 // deal with a string value
288 if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
289 $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
290
291 $XML_RPC_xh[$parser]['st'] .= "\"" . $XML_RPC_xh[$parser]['ac'] . "\"";
292 }
293
294 // This if () detects if no scalar was inside <VALUE></VALUE>
295 // and pads an empty "".
296 if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
297 $XML_RPC_xh[$parser]['st'] .= '""';
298 }
299 $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
300 if ($XML_RPC_xh[$parser]['cm']) {
301 $XML_RPC_xh[$parser]['st'] .= ",";
302 }
303 break;
304
305 case "MEMBER":
306 $XML_RPC_xh[$parser]['ac'] = "";
307 $XML_RPC_xh[$parser]['qt'] = 0;
308 break;
309
310 case "DATA":
311 $XML_RPC_xh[$parser]['ac'] = "";
312 $XML_RPC_xh[$parser]['qt'] = 0;
313 break;
314
315 case "PARAM":
316 $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
317 break;
318
319 case "METHODNAME":
320 $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", "", $XML_RPC_xh[$parser]['ac']);
321 break;
322
323 case "BOOLEAN":
324 // special case here: we translate boolean 1 or 0 into PHP
325 // constants true or false
326 if ($XML_RPC_xh[$parser]['ac'] == '1') {
327 $XML_RPC_xh[$parser]['ac'] = "true";
328 } else {
329 $XML_RPC_xh[$parser]['ac'] = "false";
330 }
331
332 $XML_RPC_xh[$parser]['vt'] = strtolower($name);
333 break;
334
335 default:
336 break;
337 }
338
339 // if it's a valid type name, set the type
340 if (isset($XML_RPC_Types[strtolower($name)])) {
341 $XML_RPC_xh[$parser]['vt'] = strtolower($name);
342 }
343 }
344
345
346 function XML_RPC_cd($parser, $data)
347 {
348 global $XML_RPC_xh, $XML_RPC_backslash;
349
350 if ($XML_RPC_xh[$parser]['lv'] != 3) {
351 // "lookforvalue==3" means that we've found an entire value
352 // and should discard any further character data
353
354 if ($XML_RPC_xh[$parser]['lv'] == 1) {
355 // if we've found text and we're just in a <value> then
356 // turn quoting on, as this will be a string
357 $XML_RPC_xh[$parser]['qt'] = 1;
358 // and say we've found a value
359 $XML_RPC_xh[$parser]['lv'] = 2;
360 }
361
362 // replace characters that eval would
363 // do special things with
364 if (isset($XML_RPC_xh[$parser]['ac'])) {
365 $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
366 str_replace('"', '\"', str_replace(chr(92),
367 $XML_RPC_backslash, $data)));
368 } else {
369 $XML_RPC_xh[$parser]['ac'] = '';
370 }
371 }
372 }
373
374
375 function XML_RPC_dh($parser, $data)
376 {
377 global $XML_RPC_xh;
378
379 if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
380 if ($XML_RPC_xh[$parser]['lv'] == 1) {
381 $XML_RPC_xh[$parser]['qt'] = 1;
382 $XML_RPC_xh[$parser]['lv'] = 2;
383 }
384 $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
385 str_replace('"', '\"', str_replace(chr(92),
386 $XML_RPC_backslash, $data)));
387 }
388 }
389
390 /**
391 * Base class
392 *
393 * This class provides common functions for all of the XML_RPC classes.
394 */
395 class XML_RPC_Base {
396 function raiseError($msg, $code)
397 {
398 include_once 'PEAR.php';
399 PEAR::raiseError(get_class($this) . ": " . $msg, $code);
400 }
401 }
402
403 class XML_RPC_Client extends XML_RPC_Base {
404 var $path;
405 var $server;
406 var $port;
407 var $errno;
408 var $errstring;
409 var $debug = 0;
410 var $username = "";
411 var $password = "";
412
413 function XML_RPC_Client($path, $server, $port = 80,
414 $proxy = '', $proxy_port = 8080,
415 $proxy_user = '', $proxy_pass = '')
416 {
417 $this->port = $port;
418 $this->server = $server;
419 $this->path = $path;
420 $this->proxy = $proxy;
421 $this->proxy_port = $proxy_port;
422 $this->proxy_user = $proxy_user;
423 $this->proxy_pass = $proxy_pass;
424 }
425
426 function setDebug($in)
427 {
428 if ($in) {
429 $this->debug = 1;
430 } else {
431 $this->debug = 0;
432 }
433 }
434
435 function setCredentials($u, $p)
436 {
437 $this->username = $u;
438 $this->password = $p;
439 }
440
441 function send($msg, $timeout = 0)
442 {
443 // where msg is an xmlrpcmsg
444 $msg->debug = $this->debug;
445 return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
446 $timeout, $this->username,
447 $this->password);
448 }
449
450 function sendPayloadHTTP10($msg, $server, $port, $timeout=0,
451 $username = "", $password = "")
452 {
453 // If we're using a proxy open a socket to the proxy server instead to the xml-rpc server
454 if ($this->proxy){
455 if ($timeout > 0) {
456 $fp = fsockopen($this->proxy, $this->proxy_port, $this->errno, $this->errstr, $timeout);
457 } else {
458 $fp = fsockopen($this->proxy, $this->proxy_port, $this->errno, $this->errstr);
459 }
460 } else {
461 if ($timeout > 0) {
462 $fp = fsockopen($server, $port, $this->errno, $this->errstr, $timeout);
463 } else {
464 $fp = fsockopen($server, $port, $this->errno, $this->errstr);
465 }
466 }
467
468 if (!$fp && $this->proxy) {
469 $this->raiseError(
470 "Connection to proxy server " . $this->proxy . ":" . $this->proxy_port . " failed",
471 XML_RPC_ERROR_CONNECTION_FAILED);
472 } elseif (!$fp) {
473 $this->raiseError(
474 "Connection to RPC server " . $this->server . " failed",
475 XML_RPC_ERROR_CONNECTION_FAILED);
476 }
477
478 // Only create the payload if it was not created previously
479 if (empty($msg->payload)) {
480 $msg->createPayload();
481 }
482
483 // thanks to Grant Rauscher <grant7@firstworld.net> for this
484 $credentials = "";
485 if ($username != "") {
486 $credentials = "Authorization: Basic " .
487 base64_encode($username . ":" . $password) . "\r\n";
488 }
489
490
491 if ($this->proxy) {
492 $op = "POST http://" . $this->server;
493
494 if ($this->proxy_port) {
495 $op .= ":" . $this->port;
496 }
497 } else {
498 $op = "POST ";
499 }
500
501 $op .= $this->path. " HTTP/1.0\r\n" .
502 "User-Agent: PEAR XML_RPC\r\n" .
503 "Host: " . $this->server . "\r\n";
504 if ($this->proxy && $this->proxy_user != '') {
505 $op .= 'Proxy-Authorization: Basic ' .
506 base64_encode($this->proxy_user . ':' . $this->proxy_pass) .
507 "\r\n";
508 }
509 $op .= $credentials .
510 "Content-Type: text/xml\r\n" .
511 "Content-Length: " . strlen($msg->payload) . "\r\n\r\n" .
512 $msg->payload;
513
514 if (!fputs($fp, $op, strlen($op))) {
515 $this->errstr = "Write error";
516 return 0;
517 }
518 $resp = $msg->parseResponseFile($fp);
519 fclose($fp);
520 return $resp;
521 }
522 }
523
524
525 class XML_RPC_Response extends XML_RPC_Base
526 {
527 var $xv;
528 var $fn;
529 var $fs;
530 var $hdrs;
531
532 function XML_RPC_Response($val, $fcode = 0, $fstr = "")
533 {
534 if ($fcode != 0) {
535 $this->fn = $fcode;
536 $this->fs = htmlspecialchars($fstr);
537 } else {
538 $this->xv = $val;
539 }
540 }
541
542 function faultCode()
543 {
544 if (isset($this->fn)) {
545 return $this->fn;
546 } else {
547 return 0;
548 }
549 }
550
551 function faultString()
552 {
553 return $this->fs;
554 }
555
556 function value()
557 {
558 return $this->xv;
559 }
560
561 function serialize()
562 {
563 $rs = "<methodResponse>\n";
564 if ($this->fn) {
565 $rs .= "<fault>
566 <value>
567 <struct>
568 <member>
569 <name>faultCode</name>
570 <value><int>" . $this->fn . "</int></value>
571 </member>
572 <member>
573 <name>faultString</name>
574 <value><string>" . $this->fs . "</string></value>
575 </member>
576 </struct>
577 </value>
578 </fault>";
579 } else {
580 $rs .= "<params>\n<param>\n" . $this->xv->serialize() .
581 "</param>\n</params>";
582 }
583 $rs .= "\n</methodResponse>";
584 return $rs;
585 }
586 }
587
588
589 class XML_RPC_Message extends XML_RPC_Base
590 {
591 var $payload;
592 var $methodname;
593 var $params = array();
594 var $debug = 0;
595
596 function XML_RPC_Message($meth, $pars = 0)
597 {
598 $this->methodname = $meth;
599 if (is_array($pars) && sizeof($pars)>0) {
600 for($i = 0; $i < sizeof($pars); $i++) {
601 $this->addParam($pars[$i]);
602 }
603 }
604 }
605
606 function xml_header()
607 {
608 return "<?xml version=\"1.0\"?>\n<methodCall>\n";
609 }
610
611 function xml_footer()
612 {
613 return "</methodCall>\n";
614 }
615
616 function createPayload()
617 {
618 $this->payload = $this->xml_header();
619 $this->payload .= "<methodName>" . $this->methodname . "</methodName>\n";
620 $this->payload .= "<params>\n";
621 for($i = 0; $i < sizeof($this->params); $i++) {
622 $p = $this->params[$i];
623 $this->payload .= "<param>\n" . $p->serialize() . "</param>\n";
624 }
625 $this->payload .= "</params>\n";
626 $this->payload .= $this->xml_footer();
627 $this->payload = str_replace("\n", "\r\n", $this->payload);
628 }
629
630 function method($meth = "")
631 {
632 if ($meth != "") {
633 $this->methodname = $meth;
634 }
635 return $this->methodname;
636 }
637
638 function serialize()
639 {
640 $this->createPayload();
641 return $this->payload;
642 }
643
644 function addParam($par)
645 {
646 $this->params[] = $par;
647 }
648
649 function getParam($i)
650 {
651 return $this->params[$i];
652 }
653
654 function getNumParams()
655 {
656 return sizeof($this->params);
657 }
658
659 function parseResponseFile($fp)
660 {
661 $ipd = "";
662
663 while($data = fread($fp, 32768)) {
664 $ipd .= $data;
665 }
666 return $this->parseResponse($ipd);
667 }
668
669 function parseResponse($data = "")
670 {
671 global $XML_RPC_xh,$XML_RPC_err,$XML_RPC_str;
672 global $XML_RPC_defencoding;
673
674 $parser = xml_parser_create($XML_RPC_defencoding);
675
676 $XML_RPC_xh[$parser] = array();
677
678 $XML_RPC_xh[$parser]['st'] = "";
679 $XML_RPC_xh[$parser]['cm'] = 0;
680 $XML_RPC_xh[$parser]['isf'] = 0;
681 $XML_RPC_xh[$parser]['ac'] = "";
682 $XML_RPC_xh[$parser]['qt'] = "";
683
684 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
685 xml_set_element_handler($parser, "XML_RPC_se", "XML_RPC_ee");
686 xml_set_character_data_handler($parser, "XML_RPC_cd");
687 xml_set_default_handler($parser, "XML_RPC_dh");
688 $xmlrpc_value = new XML_RPC_Value;
689
690 $hdrfnd = 0;
691 if ($this->debug) {
692 print "<PRE>---GOT---\n";
693 print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
694 print "\n---END---\n</PRE>";
695 }
696
697 // see if we got an HTTP 200 OK, else bomb
698 // but only do this if we're using the HTTP protocol.
699 if (ereg("^HTTP",$data) &&
700 !ereg("^HTTP/[0-9\.]+ 200 ", $data)) {
701 $errstr = substr($data, 0, strpos($data, "\n")-1);
702 error_log("HTTP error, got response: " . $errstr);
703 $r = new XML_RPC_Response(0, $XML_RPC_err["http_error"],
704 $XML_RPC_str["http_error"] . " (" .
705 $errstr . ")");
706 xml_parser_free($parser);
707 return $r;
708 }
709 // gotta get rid of headers here
710
711
712 if ((!$hdrfnd) && ($brpos = strpos($data,"\r\n\r\n"))) {
713 $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos);
714 $data = substr($data, $brpos + 4);
715 $hdrfnd = 1;
716 }
717
718 // be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
719 // thanks to Luca Mariano <luca.mariano@email.it>
720 $data = substr($data, 0, strpos($data, "</methodResponse>") + 17);
721
722 if (!xml_parse($parser, $data, sizeof($data))) {
723 // thanks to Peter Kocks <peter.kocks@baygate.com>
724 if ((xml_get_current_line_number($parser)) == 1) {
725 $errstr = "XML error at line 1, check URL";
726 } else {
727 $errstr = sprintf("XML error: %s at line %d",
728 xml_error_string(xml_get_error_code($parser)),
729 xml_get_current_line_number($parser));
730 }
731 error_log($errstr);
732 $r = new XML_RPC_Response(0, $XML_RPC_err["invalid_return"],
733 $XML_RPC_str["invalid_return"]);
734 xml_parser_free($parser);
735 return $r;
736 }
737 xml_parser_free($parser);
738 if ($this->debug) {
739 print "<PRE>---EVALING---[" .
740 strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
741 htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---</PRE>";
742 }
743 if (strlen($XML_RPC_xh[$parser]['st']) == 0) {
744 // then something odd has happened
745 // and it's time to generate a client side error
746 // indicating something odd went on
747 $r = new XML_RPC_Response(0, $XML_RPC_err["invalid_return"],
748 $XML_RPC_str["invalid_return"]);
749 } else {
750 eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;');
751 if ($XML_RPC_xh[$parser]['isf']) {
752 $f = $v->structmem("faultCode");
753 $fs = $v->structmem("faultString");
754 $r = new XML_RPC_Response($v, $f->scalarval(),
755 $fs->scalarval());
756 } else {
757 $r = new XML_RPC_Response($v);
758 }
759 }
760 $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
761 return $r;
762 }
763
764 }
765
766
767 class XML_RPC_Value extends XML_RPC_Base
768 {
769 var $me = array();
770 var $mytype = 0;
771
772 function XML_RPC_Value($val = -1, $type = "")
773 {
774 global $XML_RPC_Types;
775 $this->me = array();
776 $this->mytype = 0;
777 if ($val != -1 || $type != "") {
778 if ($type == "") {
779 $type="string";
780 }
781 if ($XML_RPC_Types[$type] == 1) {
782 $this->addScalar($val,$type);
783 } elseif ($XML_RPC_Types[$type] == 2) {
784 $this->addArray($val);
785 } elseif ($XML_RPC_Types[$type] == 3) {
786 $this->addStruct($val);
787 }
788 }
789 }
790
791 function addScalar($val, $type = "string")
792 {
793 global $XML_RPC_Types, $XML_RPC_Boolean;
794
795 if ($this->mytype == 1) {
796 $this->raiseError("Scalar can have only one value", XML_RPC_ERROR_INVALID_TYPE);
797 return 0;
798 }
799 $typeof = $XML_RPC_Types[$type];
800 if ($typeof != 1) {
801 $this->raiseError("Not a scalar type (${typeof})", XML_RPC_ERROR_INVALID_TYPE);
802 return 0;
803 }
804
805 if ($type == $XML_RPC_Boolean) {
806 if (strcasecmp($val,"true") == 0 ||
807 $val == 1 ||
808 ($val == true &&
809 strcasecmp($val,"false"))) {
810
811 $val = 1;
812 } else {
813 $val = 0;
814 }
815 }
816
817 if ($this->mytype == 2) {
818 // we're adding to an array here
819 $ar = $this->me["array"];
820 $ar[] = new XML_RPC_Value($val, $type);
821 $this->me["array"] = $ar;
822 } else {
823 // a scalar, so set the value and remember we're scalar
824 $this->me[$type] = $val;
825 $this->mytype = $typeof;
826 }
827 return 1;
828 }
829
830 function addArray($vals)
831 {
832 global $XML_RPC_Types;
833 if ($this->mytype != 0) {
834 $this->raiseError(
835 "Already initialized as a [" . $this->kindOf() . "]",
836 XML_RPC_ERROR_ALREADY_INITIALIZED);
837 return 0;
838 }
839 $this->mytype = $XML_RPC_Types["array"];
840 $this->me["array"] = $vals;
841 return 1;
842 }
843
844 function addStruct($vals)
845 {
846 global $XML_RPC_Types;
847 if ($this->mytype != 0) {
848 $this->raiseError(
849 "Already initialized as a [" . $this->kindOf() . "]",
850 XML_RPC_ERROR_ALREADY_INITIALIZED);
851 return 0;
852 }
853 $this->mytype = $XML_RPC_Types["struct"];
854 $this->me["struct"] = $vals;
855 return 1;
856 }
857
858 function dump($ar)
859 {
860 reset($ar);
861 while (list( $key, $val ) = each($ar)) {
862 echo "$key => $val<br>";
863 if ($key == 'array') {
864 while ( list( $key2, $val2 ) = each( $val ) ) {
865 echo "-- $key2 => $val2<br>";
866 }
867 }
868 }
869 }
870
871 function kindOf()
872 {
873 switch ($this->mytype) {
874 case 3:
875 return "struct";
876 break;
877 case 2:
878 return "array";
879 break;
880 case 1:
881 return "scalar";
882 break;
883 default:
884 return "undef";
885 }
886 }
887
888 function serializedata($typ, $val)
889 {
890 $rs = "";
891 global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean;
892 switch ($XML_RPC_Types[$typ]) {
893 case 3:
894 // struct
895 $rs .= "<struct>\n";
896 reset($val);
897 while(list($key2, $val2) = each($val)) {
898 $rs .= "<member><name>${key2}</name>\n";
899 $rs .= $this->serializeval($val2);
900 $rs .= "</member>\n";
901 }
902 $rs .= "</struct>";
903 break;
904 case 2:
905 // array
906 $rs .= "<array>\n<data>\n";
907 for($i = 0; $i < sizeof($val); $i++) {
908 $rs .= $this->serializeval($val[$i]);
909 }
910 $rs .= "</data>\n</array>";
911 break;
912 case 1:
913 switch ($typ) {
914 case $XML_RPC_Base64:
915 $rs .= "<${typ}>" . base64_encode($val) . "</${typ}>";
916 break;
917 case $XML_RPC_Boolean:
918 $rs .= "<${typ}>" . ($val ? "1" : "0") . "</${typ}>";
919 break;
920 case $XML_RPC_String:
921 $rs .= "<${typ}>" . htmlspecialchars($val). "</${typ}>";
922 break;
923 default:
924 $rs .= "<${typ}>${val}</${typ}>";
925 }
926 break;
927 default:
928 break;
929 }
930 return $rs;
931 }
932
933 function serialize()
934 {
935 return $this->serializeval($this);
936 }
937
938 function serializeval($o)
939 {
940 $rs = "";
941 $ar = $o->me;
942 reset($ar);
943 list($typ, $val) = each($ar);
944 $rs .= "<value>";
945 $rs .= $this->serializedata($typ, $val);
946 $rs .= "</value>\n";
947 return $rs;
948 }
949
950 function structmem($m)
951 {
952 $nv = $this->me["struct"][$m];
953 return $nv;
954 }
955
956 function structreset()
957 {
958 reset($this->me["struct"]);
959 }
960
961 function structeach()
962 {
963 return each($this->me["struct"]);
964 }
965
966 function getval() {
967 // UNSTABLE
968 global $XML_RPC_BOOLEAN, $XML_RPC_Base64;
969
970 reset($this->me);
971 list($a,$b) = each($this->me);
972
973 // contributed by I Sofer, 2001-03-24
974 // add support for nested arrays to scalarval
975 // i've created a new method here, so as to
976 // preserve back compatibility
977
978 if (is_array($b)) {
979 foreach ($b as $id => $cont) {
980 $b[$id] = $cont->scalarval();
981 }
982 }
983
984 // add support for structures directly encoding php objects
985 if (is_object($b)) {
986 $t = get_object_vars($b);
987 foreach ($t as $id => $cont) {
988 $t[$id] = $cont->scalarval();
989 }
990 foreach ($t as $id => $cont) {
991 eval('$b->'.$id.' = $cont;');
992 }
993 }
994
995 // end contrib
996 return $b;
997 }
998
999 function scalarval()
1000 {
1001 global $XML_RPC_Boolean, $XML_RPC_Base64;
1002 reset($this->me);
1003 list($a,$b) = each($this->me);
1004 return $b;
1005 }
1006
1007 function scalartyp()
1008 {
1009 global $XML_RPC_I4, $XML_RPC_Int;
1010 reset($this->me);
1011 list($a,$b) = each($this->me);
1012 if ($a == $XML_RPC_I4) {
1013 $a = $XML_RPC_Int;
1014 }
1015 return $a;
1016 }
1017
1018 function arraymem($m)
1019 {
1020 $nv = $this->me["array"][$m];
1021 return $nv;
1022 }
1023
1024 function arraysize()
1025 {
1026 reset($this->me);
1027 list($a,$b) = each($this->me);
1028 return sizeof($b);
1029 }
1030 }
1031
1032
1033 /**
1034 * date helpers
1035 */
1036 function XML_RPC_iso8601_encode($timet, $utc = 0) {
1037 // return an ISO8601 encoded string
1038 // really, timezones ought to be supported
1039 // but the XML-RPC spec says:
1040 //
1041 // "Don't assume a timezone. It should be specified by the server in its
1042 // documentation what assumptions it makes about timezones."
1043 //
1044 // these routines always assume localtime unless
1045 // $utc is set to 1, in which case UTC is assumed
1046 // and an adjustment for locale is made when encoding
1047 if (!$utc) {
1048 $t = strftime("%Y%m%dT%H:%M:%S", $timet);
1049 } else {
1050 if (function_exists("gmstrftime")) {
1051 // gmstrftime doesn't exist in some versions
1052 // of PHP
1053 $t = gmstrftime("%Y%m%dT%H:%M:%S", $timet);
1054 } else {
1055 $t = strftime("%Y%m%dT%H:%M:%S", $timet - date("Z"));
1056 }
1057 }
1058
1059 return $t;
1060 }
1061
1062 function XML_RPC_iso8601_decode($idate, $utc = 0) {
1063 // return a timet in the localtime, or UTC
1064 $t = 0;
1065 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs)) {
1066
1067 if ($utc) {
1068 $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1069 } else {
1070 $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1071 }
1072 }
1073
1074 return $t;
1075 }
1076
1077 /**
1078 * Takes a message in PHP XML_RPC object format and translates it into native PHP types.
1079 *
1080 * @author Dan Libby <dan@libby.com>
1081 **/
1082 function XML_RPC_decode($XML_RPC_val) {
1083 $kind = $XML_RPC_val->kindOf();
1084
1085 if ($kind == "scalar") {
1086 return $XML_RPC_val->scalarval();
1087
1088 } elseif ($kind == "array") {
1089 $size = $XML_RPC_val->arraysize();
1090 $arr = array();
1091
1092 for($i = 0; $i < $size; $i++) {
1093 $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i));
1094 }
1095 return $arr;
1096
1097 } elseif ($kind == "struct") {
1098 $XML_RPC_val->structreset();
1099 $arr = array();
1100
1101 while(list($key,$value) = $XML_RPC_val->structeach()) {
1102 $arr[$key] = XML_RPC_decode($value);
1103 }
1104 return $arr;
1105 }
1106 }
1107
1108 /**
1109 * Takes native php types and encodes them into XML_RPC PHP object format.
1110 *
1111 * Feature creep -- could support more types via optional type argument.
1112 *
1113 * @author Dan Libby <dan@libby.com>
1114 **/
1115 function XML_RPC_encode($php_val) {
1116 global $XML_RPC_Boolean;
1117 global $XML_RPC_Int;
1118 global $XML_RPC_Double;
1119 global $XML_RPC_String;
1120 global $XML_RPC_Array;
1121 global $XML_RPC_Struct;
1122
1123 $type = gettype($php_val);
1124 $XML_RPC_val = new XML_RPC_Value;
1125
1126 switch ($type) {
1127 case "array":
1128 $keys = array_keys($php_val);
1129 $count = count($php_val);
1130 $firstkey = $keys[0];
1131 $lastkey = $keys[$count - 1];
1132 if ($firstkey === 0 && is_int($lastkey) && ($lastkey + 1) == $count) {
1133 $is_continuous = true;
1134 $expected = 0;
1135 foreach ($keys as $actual) {
1136 if ($actual != $expected) {
1137 $is_continuous = false;
1138 break;
1139 }
1140 $expected++;
1141 }
1142
1143 if ($is_continuous) {
1144 $arr = array();
1145 foreach ($php_val as $k => $v) {
1146 $arr[$k] = XML_RPC_encode($v);
1147 }
1148 $XML_RPC_val->addArray($arr);
1149 break;
1150 }
1151 }
1152 // fall though if not numerical and continuous
1153 case "object":
1154 $arr = array();
1155 foreach ($php_val as $k => $v) {
1156 $arr[$k] = XML_RPC_encode($v);
1157 }
1158 $XML_RPC_val->addStruct($arr);
1159 break;
1160
1161 case "integer":
1162 $XML_RPC_val->addScalar($php_val, $XML_RPC_Int);
1163 break;
1164
1165 case "double":
1166 $XML_RPC_val->addScalar($php_val, $XML_RPC_Double);
1167 break;
1168
1169 case "string":
1170 case "NULL":
1171 $XML_RPC_val->addScalar($php_val, $XML_RPC_String);
1172 break;
1173
1174 // <G_Giunta_2001-02-29>
1175 // Add support for encoding/decoding of booleans, since they are supported in PHP
1176 case "boolean":
1177 $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean);
1178 break;
1179 // </G_Giunta_2001-02-29>
1180
1181 case "unknown type":
1182 default:
1183 $XML_RPC_val = false;
1184 break;
1185 }
1186 return $XML_RPC_val;
1187 }
1188
1189 ?>

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed