/[cvs]/nfo/php/libs/net.php.pear/XML/RPC/RPC.php
ViewVC logotype

Contents of /nfo/php/libs/net.php.pear/XML/RPC/RPC.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations)
Wed Oct 9 00:45:02 2002 UTC (22 years ago) by cvsjoko
Branch: MAIN
no message

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

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