/[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.2 - (show annotations)
Mon Oct 28 00:54:16 2002 UTC (21 years, 11 months ago) by cvsjoko
Branch: MAIN
Changes since 1.1: +135 -123 lines
+ new versions: 1.0.4

1 <?php
2 // by Edd Dumbill (C) 1999-2001
3 // <edd@usefulinc.com>
4 // $Id: RPC.php,v 1.11 2002/10/02 21:10:19 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,
376 $proxy = '', $proxy_port = 8080,
377 $proxy_user = '', $proxy_pass = '')
378 {
379 $this->port=$port;
380 $this->server=$server;
381 $this->path=$path;
382 $this->proxy = $proxy;
383 $this->proxy_port = $proxy_port;
384 $this->proxy_user = $proxy_user;
385 $this->proxy_pass = $proxy_pass;
386 }
387
388 function setDebug($in)
389 {
390 if ($in) {
391 $this->debug=1;
392 } else {
393 $this->debug=0;
394 }
395 }
396
397 function setCredentials($u, $p)
398 {
399 $this->username=$u;
400 $this->password=$p;
401 }
402
403 function send($msg, $timeout=0)
404 {
405 // where msg is an xmlrpcmsg
406 $msg->debug=$this->debug;
407 return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
408 $timeout, $this->username,
409 $this->password);
410 }
411
412 function sendPayloadHTTP10($msg, $server, $port, $timeout=0,
413 $username="", $password="")
414 {
415 // If we're using a proxy open a socket to the proxy server instead to the xml-rpc server
416 if($this->proxy){
417 if($timeout > 0) {
418 $fp=fsockopen($this->proxy, $this->proxy_port, $this->errno, $this->errstr, $timeout);
419 }
420 else {
421 $fp=fsockopen($this->proxy, $this->proxy_port, $this->errno, $this->errstr);
422 }
423 }
424 else {
425 if($timeout > 0) {
426 $fp=fsockopen($server, $port, $this->errno, $this->errstr, $timeout);
427 }
428 else {
429 $fp=fsockopen($server, $port, $this->errno, $this->errstr);
430 }
431 }
432
433 if(!$fp && $this->proxy) {
434 PEAR::raiseError("Connection to proxy server ".$this->proxy.":".$this->proxy_port." failed");
435 }
436 else if(!$fp) {
437 PEAR::raiseError("Connection to RPC server ".$this->server." failed");
438 }
439
440 // Only create the payload if it was not created previously
441 if(empty($msg->payload)) $msg->createPayload();
442
443 // thanks to Grant Rauscher <grant7@firstworld.net>
444 // for this
445 $credentials="";
446 if ($username!="") {
447 $credentials="Authorization: Basic " .
448 base64_encode($username . ":" . $password) . "\r\n";
449 }
450
451
452 if($this->proxy) {
453 $op = "POST http://" . $this->server;
454
455 if($this->proxy_port) {
456 $op .= ":" . $this->port;
457 }
458 }
459 else {
460 $op = "POST ";
461 }
462
463 $op .= $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" .
464 "Host: ". $this->server . "\r\n";
465 if ($this->proxy && $this->proxy_user != '') {
466 $op .= 'Proxy-Authorization: Basic ' .
467 base64_encode($this->proxy_user . ':' . $this->proxy_pass) .
468 "\r\n";
469 }
470 $op .= $credentials .
471 "Content-Type: text/xml\r\nContent-Length: " .
472 strlen($msg->payload) . "\r\n\r\n" .
473 $msg->payload;
474
475 // print($op);
476
477 if (!fputs($fp, $op, strlen($op))) {
478 $this->errstr="Write error";
479 return 0;
480 }
481 $resp=$msg->parseResponseFile($fp);
482 fclose($fp);
483 return $resp;
484 }
485 }
486
487
488 class XML_RPC_Response
489 {
490 var $xv;
491 var $fn;
492 var $fs;
493 var $hdrs;
494
495 function XML_RPC_Response($val, $fcode=0, $fstr="")
496 {
497 if ($fcode!=0) {
498 $this->fn=$fcode;
499 $this->fs=htmlspecialchars($fstr);
500 } else {
501 $this->xv=$val;
502 }
503 }
504
505 function faultCode()
506 {
507 if (isset($this->fn))
508 return $this->fn;
509 else
510 return 0;
511 }
512
513 function faultString() { return $this->fs; }
514 function value() { return $this->xv; }
515
516 function serialize() {
517 $rs="<methodResponse>\n";
518 if ($this->fn) {
519 $rs.="<fault>
520 <value>
521 <struct>
522 <member>
523 <name>faultCode</name>
524 <value><int>" . $this->fn . "</int></value>
525 </member>
526 <member>
527 <name>faultString</name>
528 <value><string>" . $this->fs . "</string></value>
529 </member>
530 </struct>
531 </value>
532 </fault>";
533 } else {
534 $rs.="<params>\n<param>\n" . $this->xv->serialize() .
535 "</param>\n</params>";
536 }
537 $rs.="\n</methodResponse>";
538 return $rs;
539 }
540 }
541
542
543 class XML_RPC_Message
544 {
545 var $payload;
546 var $methodname;
547 var $params = array();
548 var $debug=0;
549
550 function XML_RPC_Message($meth, $pars=0)
551 {
552 $this->methodname=$meth;
553 if (is_array($pars) && sizeof($pars)>0) {
554 for($i=0; $i<sizeof($pars); $i++)
555 $this->addParam($pars[$i]);
556 }
557 }
558
559 function xml_header()
560 {
561 return "<?xml version=\"1.0\"?>\n<methodCall>\n";
562 }
563
564 function xml_footer()
565 {
566 return "</methodCall>\n";
567 }
568
569 function createPayload()
570 {
571 $this->payload=$this->xml_header();
572 $this->payload.="<methodName>" . $this->methodname . "</methodName>\n";
573 // if (sizeof($this->params)) {
574 $this->payload.="<params>\n";
575 for($i=0; $i<sizeof($this->params); $i++) {
576 $p=$this->params[$i];
577 $this->payload.="<param>\n" . $p->serialize() .
578 "</param>\n";
579 }
580 $this->payload.="</params>\n";
581 // }
582 $this->payload.=$this->xml_footer();
583 $this->payload=str_replace("\n", "\r\n", $this->payload);
584 }
585
586 function method($meth="")
587 {
588 if ($meth!="") {
589 $this->methodname=$meth;
590 }
591 return $this->methodname;
592 }
593
594 function serialize()
595 {
596 $this->createPayload();
597 return $this->payload;
598 }
599
600 function addParam($par) { $this->params[]=$par; }
601 function getParam($i) { return $this->params[$i]; }
602 function getNumParams() { return sizeof($this->params); }
603
604 function parseResponseFile($fp)
605 {
606 $ipd="";
607
608 while($data=fread($fp, 32768)) {
609 $ipd.=$data;
610 }
611 return $this->parseResponse($ipd);
612 }
613
614 function parseResponse($data="")
615 {
616 global $XML_RPC_xh,$XML_RPC_err,$XML_RPC_str;
617 global $XML_RPC_defencoding;
618
619 $parser = xml_parser_create($XML_RPC_defencoding);
620
621 $XML_RPC_xh[$parser]=array();
622
623 $XML_RPC_xh[$parser]['st']="";
624 $XML_RPC_xh[$parser]['cm']=0;
625 $XML_RPC_xh[$parser]['isf']=0;
626 $XML_RPC_xh[$parser]['ac']="";
627 $XML_RPC_xh[$parser]['qt']="";
628
629 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
630 xml_set_element_handler($parser, "XML_RPC_se", "XML_RPC_ee");
631 xml_set_character_data_handler($parser, "XML_RPC_cd");
632 xml_set_default_handler($parser, "XML_RPC_dh");
633 $xmlrpc_value = new XML_RPC_Value;
634
635 $hdrfnd=0;
636 if ($this->debug) {
637 print "<PRE>---GOT---\n";
638 print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
639 print "\n---END---\n</PRE>";
640 }
641 // see if we got an HTTP 200 OK, else bomb
642 // but only do this if we're using the HTTP protocol.
643 if (ereg("^HTTP",$data) &&
644 !ereg("^HTTP/[0-9\.]+ 200 ", $data)) {
645 $errstr= substr($data, 0, strpos($data, "\n")-1);
646 error_log("HTTP error, got response: " .$errstr);
647 $r=new XML_RPC_Response(0, $XML_RPC_err["http_error"],
648 $XML_RPC_str["http_error"]. " (" .
649 $errstr . ")");
650 xml_parser_free($parser);
651 return $r;
652 }
653 // gotta get rid of headers here
654
655
656 if ((!$hdrfnd) && ($brpos = strpos($data,"\r\n\r\n"))) {
657 $XML_RPC_xh[$parser]['ha'] = substr($data,0,$brpos);
658 $data= substr($data,$brpos+4);
659 $hdrfnd=1;
660 }
661
662 if (!xml_parse($parser, $data, sizeof($data))) {
663 // thanks to Peter Kocks <peter.kocks@baygate.com>
664 if((xml_get_current_line_number($parser)) == 1)
665 $errstr = "XML error at line 1, check URL";
666 else
667 $errstr = sprintf("XML error: %s at line %d",
668 xml_error_string(xml_get_error_code($parser)),
669 xml_get_current_line_number($parser));
670 error_log($errstr);
671 $r=new XML_RPC_Response(0, $XML_RPC_err["invalid_return"],
672 $XML_RPC_str["invalid_return"]);
673 xml_parser_free($parser);
674 return $r;
675 }
676 xml_parser_free($parser);
677 if ($this->debug) {
678 print "<PRE>---EVALING---[" .
679 strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
680 htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---</PRE>";
681 }
682 if (strlen($XML_RPC_xh[$parser]['st'])==0) {
683 // then something odd has happened
684 // and it's time to generate a client side error
685 // indicating something odd went on
686 $r=new XML_RPC_Response(0, $XML_RPC_err["invalid_return"],
687 $XML_RPC_str["invalid_return"]);
688 } else {
689 eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;');
690 if ($XML_RPC_xh[$parser]['isf']) {
691 $f=$v->structmem("faultCode");
692 $fs=$v->structmem("faultString");
693 $r=new XML_RPC_Response($v, $f->scalarval(),
694 $fs->scalarval());
695 } else {
696 $r=new XML_RPC_Response($v);
697 }
698 }
699 $r->hdrs=split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]);
700 return $r;
701 }
702
703 }
704
705
706 class XML_RPC_Value
707 {
708 var $me=array();
709 var $mytype=0;
710
711 function XML_RPC_Value($val=-1, $type="")
712 {
713 global $XML_RPC_Types;
714 $this->me=array();
715 $this->mytype=0;
716 if ($val!=-1 || $type!="") {
717 if ($type=="") $type="string";
718 if ($XML_RPC_Types[$type]==1) {
719 $this->addScalar($val,$type);
720 }
721 else if ($XML_RPC_Types[$type]==2)
722 $this->addArray($val);
723 else if ($XML_RPC_Types[$type]==3)
724 $this->addStruct($val);
725 }
726 }
727
728 function addScalar($val, $type="string")
729 {
730 global $XML_RPC_Types, $XML_RPC_Boolean;
731
732 if ($this->mytype==1) {
733 echo "<B>XML_RPC_Value</B>: scalar can have only one value<BR>";
734 return 0;
735 }
736 $typeof=$XML_RPC_Types[$type];
737 if ($typeof!=1) {
738 echo "<B>XML_RPC_Value</B>: not a scalar type (${typeof})<BR>";
739 return 0;
740 }
741
742 if ($type==$XML_RPC_Boolean) {
743 if (strcasecmp($val,"true")==0 ||
744 $val==1 ||
745 ($val==true &&
746 strcasecmp($val,"false"))) {
747
748 $val=1;
749 } else {
750 $val=0;
751 }
752 }
753
754 if ($this->mytype==2) {
755 // we're adding to an array here
756 $ar=$this->me["array"];
757 $ar[]=new XML_RPC_Value($val, $type);
758 $this->me["array"]=$ar;
759 } else {
760 // a scalar, so set the value and remember we're scalar
761 $this->me[$type]=$val;
762 $this->mytype=$typeof;
763 }
764 return 1;
765 }
766
767 function addArray($vals)
768 {
769 global $XML_RPC_Types;
770 if ($this->mytype!=0) {
771 echo "<B>XML_RPC_Value</B>: already initialized as a [" .
772 $this->kindOf() . "]<BR>";
773 return 0;
774 }
775 $this->mytype=$XML_RPC_Types["array"];
776 $this->me["array"]=$vals;
777 return 1;
778 }
779
780 function addStruct($vals)
781 {
782 global $XML_RPC_Types;
783 if ($this->mytype!=0) {
784 echo "<B>XML_RPC_Value</B>: already initialized as a [" .
785 $this->kindOf() . "]<BR>";
786 return 0;
787 }
788 $this->mytype=$XML_RPC_Types["struct"];
789 $this->me["struct"]=$vals;
790 return 1;
791 }
792
793 function dump($ar)
794 {
795 reset($ar);
796 while ( list( $key, $val ) = each( $ar ) ) {
797 echo "$key => $val<br>";
798 if ($key == 'array')
799 while ( list( $key2, $val2 ) = each( $val ) ) {
800 echo "-- $key2 => $val2<br>";
801 }
802 }
803 }
804
805 function kindOf()
806 {
807 switch($this->mytype) {
808 case 3:
809 return "struct";
810 break;
811 case 2:
812 return "array";
813 break;
814 case 1:
815 return "scalar";
816 break;
817 default:
818 return "undef";
819 }
820 }
821
822 function serializedata($typ, $val)
823 {
824 $rs="";
825 global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean;
826 switch($XML_RPC_Types[$typ]) {
827 case 3:
828 // struct
829 $rs.="<struct>\n";
830 reset($val);
831 while(list($key2, $val2)=each($val)) {
832 $rs.="<member><name>${key2}</name>\n";
833 $rs.=$this->serializeval($val2);
834 $rs.="</member>\n";
835 }
836 $rs.="</struct>";
837 break;
838 case 2:
839 // array
840 $rs.="<array>\n<data>\n";
841 for($i=0; $i<sizeof($val); $i++) {
842 $rs.=$this->serializeval($val[$i]);
843 }
844 $rs.="</data>\n</array>";
845 break;
846 case 1:
847 switch ($typ) {
848 case $XML_RPC_Base64:
849 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
850 break;
851 case $XML_RPC_Boolean:
852 $rs.="<${typ}>" . ($val ? "1" : "0") . "</${typ}>";
853 break;
854 case $XML_RPC_String:
855 $rs.="<${typ}>" . htmlspecialchars($val). "</${typ}>";
856 break;
857 default:
858 $rs.="<${typ}>${val}</${typ}>";
859 }
860 break;
861 default:
862 break;
863 }
864 return $rs;
865 }
866
867 function serialize()
868 {
869 return $this->serializeval($this);
870 }
871
872 function serializeval($o)
873 {
874 global $XML_RPC_Types;
875 $rs="";
876 $ar=$o->me;
877 reset($ar);
878 list($typ, $val) = each($ar);
879 $rs.="<value>";
880 $rs.=$this->serializedata($typ, $val);
881 $rs.="</value>\n";
882 return $rs;
883 }
884
885 function structmem($m)
886 {
887 $nv=$this->me["struct"][$m];
888 return $nv;
889 }
890
891 function structreset()
892 {
893 reset($this->me["struct"]);
894 }
895
896 function structeach()
897 {
898 return each($this->me["struct"]);
899 }
900
901 function getval() {
902 // UNSTABLE
903 global $XML_RPC_BOOLEAN, $XML_RPC_Base64;
904
905 reset($this->me);
906 list($a,$b)=each($this->me);
907
908 // contributed by I Sofer, 2001-03-24
909 // add support for nested arrays to scalarval
910 // i've created a new method here, so as to
911 // preserve back compatibility
912
913 if (is_array($b)) {
914 foreach ($b as $id => $cont) {
915 $b[$id] = $cont->scalarval();
916 }
917 }
918
919 // add support for structures directly encoding php objects
920 if (is_object($b)) {
921 $t = get_object_vars($b);
922 foreach ($t as $id => $cont) {
923 $t[$id] = $cont->scalarval();
924 }
925 foreach ($t as $id => $cont) {
926 eval('$b->'.$id.' = $cont;');
927 }
928 }
929
930 // end contrib
931 return $b;
932 }
933
934 function scalarval()
935 {
936 global $XML_RPC_Boolean, $XML_RPC_Base64;
937 reset($this->me);
938 list($a,$b)=each($this->me);
939 return $b;
940 }
941
942 function scalartyp()
943 {
944 global $XML_RPC_I4, $XML_RPC_Int;
945 reset($this->me);
946 list($a,$b)=each($this->me);
947 if ($a==$XML_RPC_I4)
948 $a=$XML_RPC_Int;
949 return $a;
950 }
951
952 function arraymem($m)
953 {
954 $nv=$this->me["array"][$m];
955 return $nv;
956 }
957
958 function arraysize()
959 {
960 reset($this->me);
961 list($a,$b)=each($this->me);
962 return sizeof($b);
963 }
964 }
965
966
967 /**
968 * date helpers
969 */
970 function XML_RPC_iso8601_encode($timet, $utc=0) {
971 // return an ISO8601 encoded string
972 // really, timezones ought to be supported
973 // but the XML-RPC spec says:
974 //
975 // "Don't assume a timezone. It should be specified by the server in its
976 // documentation what assumptions it makes about timezones."
977 //
978 // these routines always assume localtime unless
979 // $utc is set to 1, in which case UTC is assumed
980 // and an adjustment for locale is made when encoding
981 if (!$utc) {
982 $t=strftime("%Y%m%dT%H:%M:%S", $timet);
983 } else {
984 if (function_exists("gmstrftime"))
985 // gmstrftime doesn't exist in some versions
986 // of PHP
987 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
988 else {
989 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date("Z"));
990 }
991 }
992
993 return $t;
994 }
995
996 function XML_RPC_iso8601_decode($idate, $utc=0) {
997 // return a timet in the localtime, or UTC
998 $t=0;
999 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",$idate, $regs)) {
1000
1001 if ($utc) {
1002 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1003 } else {
1004 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1005 }
1006 }
1007
1008 return $t;
1009 }
1010
1011 /******************************************************************
1012 * XML_RPC_decode takes a message in PHP XML_RPC object format and *
1013 * tranlates it into native PHP types. *
1014 * *
1015 * author: Dan Libby (dan@libby.com) *
1016 ******************************************************************/
1017 function XML_RPC_decode($XML_RPC_val) {
1018 $kind = $XML_RPC_val->kindOf();
1019
1020 if($kind == "scalar") {
1021 return $XML_RPC_val->scalarval();
1022 }
1023 else if($kind == "array") {
1024 $size = $XML_RPC_val->arraysize();
1025 $arr = array();
1026
1027 for($i = 0; $i < $size; $i++) {
1028 $arr[]=XML_RPC_decode($XML_RPC_val->arraymem($i));
1029 }
1030 return $arr;
1031 }
1032 else if($kind == "struct") {
1033 $XML_RPC_val->structreset();
1034 $arr = array();
1035
1036 while(list($key,$value)=$XML_RPC_val->structeach()) {
1037 $arr[$key] = XML_RPC_decode($value);
1038 }
1039 return $arr;
1040 }
1041 }
1042
1043 /*****************************************************************
1044 * XML_RPC_encode takes native php types and encodes them into *
1045 * XML_RPC PHP object format. *
1046 * BUG: All sequential arrays are turned into structs. I don't *
1047 * know of a good way to determine if an array is sequential *
1048 * only. *
1049 * *
1050 * feature creep -- could support more types via optional type *
1051 * argument. *
1052 * *
1053 * author: Dan Libby (dan@libby.com) *
1054 *****************************************************************/
1055 function XML_RPC_encode($php_val) {
1056 global $XML_RPC_Boolean;
1057 global $XML_RPC_Int;
1058 global $XML_RPC_Double;
1059 global $XML_RPC_String;
1060 global $XML_RPC_Array;
1061 global $XML_RPC_Struct;
1062
1063 $type = gettype($php_val);
1064 $XML_RPC_val = new XML_RPC_value;
1065
1066 switch($type) {
1067 case "array":
1068 case "object":
1069 $arr = array();
1070 while (list($k,$v) = each($php_val)) {
1071 $arr[$k] = XML_RPC_encode($v);
1072 }
1073 $XML_RPC_val->addStruct($arr);
1074 break;
1075 case "integer":
1076 $XML_RPC_val->addScalar($php_val, $XML_RPC_Int);
1077 break;
1078 case "double":
1079 $XML_RPC_val->addScalar($php_val, $XML_RPC_Double);
1080 break;
1081 case "string":
1082 case "NULL":
1083 $XML_RPC_val->addScalar($php_val, $XML_RPC_String);
1084 break;
1085 // <G_Giunta_2001-02-29>
1086 // Add support for encoding/decoding of booleans, since they are supported in PHP
1087 case "boolean":
1088 $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean);
1089 break;
1090 // </G_Giunta_2001-02-29>
1091 case "unknown type":
1092 default:
1093 $XML_RPC_val = false;
1094 break;
1095 }
1096 return $XML_RPC_val;
1097 }
1098
1099 ?>

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