/[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.4 - (show annotations)
Wed Feb 5 22:10:59 2003 UTC (21 years, 6 months ago) by joko
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +6 -2 lines
- removed previous patch
+ fixed problem ("remote side is not available leads to fatal php error") elsewhere: 'sendPayloadHTTP10' now doesn't continue if (socket-) connection fails

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

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