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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations)
Mon Oct 28 04:21:48 2002 UTC (21 years, 10 months ago) by cvsjoko
Branch: MAIN
Changes since 1.2: +2 -2 lines
+ bugfix; error occours when rpc-server is down

1 cvsjoko 1.1 <?php
2     // by Edd Dumbill (C) 1999-2001
3     // <edd@usefulinc.com>
4 cvsjoko 1.3 // $Id: RPC.php,v 1.2 2002/10/28 00:54:16 cvsjoko Exp $
5 cvsjoko 1.1
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 cvsjoko 1.2 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
16 cvsjoko 1.1 // 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 cvsjoko 1.2 $GLOBALS['XML_RPC_erruser']=800;
76 cvsjoko 1.1 // 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 cvsjoko 1.2 $i=0;
103 cvsjoko 1.1 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 cvsjoko 1.2 if ($i==0)
110     $op=$top[$i];
111 cvsjoko 1.1 else
112     $op.="&" . $top[$i];
113     }
114 cvsjoko 1.2
115 cvsjoko 1.1 $i++;
116     }
117     return $op;
118     }
119    
120    
121     function XML_RPC_lookup_entity($ent)
122     {
123     global $XML_RPC_entities;
124 cvsjoko 1.2
125     if ($XML_RPC_entities[strtolower($ent)])
126 cvsjoko 1.1 return $XML_RPC_entities[strtolower($ent)];
127 cvsjoko 1.2
128 cvsjoko 1.1 if (ereg("^#([0-9]+)$", $ent, $regs))
129     return chr($regs[1]);
130 cvsjoko 1.2
131 cvsjoko 1.1 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 cvsjoko 1.2
139 cvsjoko 1.1 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 cvsjoko 1.2 // this means if we get an empty array we'll
146 cvsjoko 1.1 // 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 cvsjoko 1.2 $XML_RPC_xh[$parser]['st'].="new XML_RPC_Value(";
160 cvsjoko 1.1 $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 cvsjoko 1.2
169 cvsjoko 1.1 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 cvsjoko 1.2
178 cvsjoko 1.1 if ($name=="DATETIME.ISO8601" || $name=="STRING") {
179 cvsjoko 1.2 $XML_RPC_xh[$parser]['qt']=1;
180    
181 cvsjoko 1.1 if ($name=="DATETIME.ISO8601")
182     $XML_RPC_xh[$parser]['vt']=$XML_RPC_DateTime;
183 cvsjoko 1.2
184 cvsjoko 1.1 } 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 cvsjoko 1.2
194 cvsjoko 1.1 case "MEMBER":
195     $XML_RPC_xh[$parser]['ac']="";
196     break;
197     default:
198     break;
199     }
200 cvsjoko 1.2
201 cvsjoko 1.1 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 cvsjoko 1.2
216     $XML_RPC_xh[$parser]['st'].=")";
217 cvsjoko 1.1 $XML_RPC_xh[$parser]['vt']=strtolower($name);
218     $XML_RPC_xh[$parser]['cm']--;
219     break;
220 cvsjoko 1.2
221 cvsjoko 1.1 case "NAME":
222     $XML_RPC_xh[$parser]['st'].= $XML_RPC_xh[$parser]['ac'] . "' => ";
223     break;
224 cvsjoko 1.2
225 cvsjoko 1.1 case "BOOLEAN":
226     // special case here: we translate boolean 1 or 0 into PHP
227     // constants true or false
228 cvsjoko 1.2 if ($XML_RPC_xh[$parser]['ac']=='1')
229 cvsjoko 1.1 $XML_RPC_xh[$parser]['ac']="true";
230 cvsjoko 1.2 else
231 cvsjoko 1.1 $XML_RPC_xh[$parser]['ac']="false";
232 cvsjoko 1.2
233 cvsjoko 1.1 $XML_RPC_xh[$parser]['vt']=strtolower($name);
234     // Drop through intentionally.
235 cvsjoko 1.2
236 cvsjoko 1.1 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 cvsjoko 1.2 $XML_RPC_xh[$parser]['st'].="\"". $XML_RPC_xh[$parser]['ac'] . "\"";
245 cvsjoko 1.1 } else if ($XML_RPC_xh[$parser]['qt']==2) {
246 cvsjoko 1.2 $XML_RPC_xh[$parser]['st'].="base64_decode('". $XML_RPC_xh[$parser]['ac'] . "')";
247 cvsjoko 1.1 } 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 cvsjoko 1.2 $XML_RPC_xh[$parser]['st'].="ERROR_NON_NUMERIC_FOUND";
257 cvsjoko 1.1 } else {
258     // it's ok, add it on
259     $XML_RPC_xh[$parser]['st'].=$XML_RPC_xh[$parser]['ac'];
260     }
261     }
262 cvsjoko 1.2
263 cvsjoko 1.1 $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 cvsjoko 1.2
267 cvsjoko 1.1 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 cvsjoko 1.2
272     $XML_RPC_xh[$parser]['st'].="\"". $XML_RPC_xh[$parser]['ac'] . "\"";
273 cvsjoko 1.1 }
274 cvsjoko 1.2
275 cvsjoko 1.1 // 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 cvsjoko 1.2
284 cvsjoko 1.1 case "MEMBER":
285     $XML_RPC_xh[$parser]['ac']=""; $XML_RPC_xh[$parser]['qt']=0;
286     break;
287 cvsjoko 1.2
288 cvsjoko 1.1 case "DATA":
289     $XML_RPC_xh[$parser]['ac']=""; $XML_RPC_xh[$parser]['qt']=0;
290     break;
291 cvsjoko 1.2
292 cvsjoko 1.1 case "PARAM":
293     $XML_RPC_xh[$parser]['params'][]=$XML_RPC_xh[$parser]['st'];
294     break;
295 cvsjoko 1.2
296 cvsjoko 1.1 case "METHODNAME":
297     $XML_RPC_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", "", $XML_RPC_xh[$parser]['ac']);
298     break;
299 cvsjoko 1.2
300 cvsjoko 1.1 case "BOOLEAN":
301     // special case here: we translate boolean 1 or 0 into PHP
302     // constants true or false
303 cvsjoko 1.2 if ($XML_RPC_xh[$parser]['ac']=='1')
304 cvsjoko 1.1 $XML_RPC_xh[$parser]['ac']="true";
305 cvsjoko 1.2 else
306 cvsjoko 1.1 $XML_RPC_xh[$parser]['ac']="false";
307 cvsjoko 1.2
308 cvsjoko 1.1 $XML_RPC_xh[$parser]['vt']=strtolower($name);
309     break;
310 cvsjoko 1.2
311 cvsjoko 1.1 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 cvsjoko 1.2 {
323 cvsjoko 1.1 global $XML_RPC_xh, $XML_RPC_backslash;
324    
325     //if (ereg("^[\n\r \t]+$", $data)) return;
326     // print "adding [${data}]\n";
327 cvsjoko 1.2
328 cvsjoko 1.1 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 cvsjoko 1.2
332     if ($XML_RPC_xh[$parser]['lv']==1) {
333 cvsjoko 1.1 // if we've found text and we're just in a <value> then
334     // turn quoting on, as this will be a string
335 cvsjoko 1.2 $XML_RPC_xh[$parser]['qt']=1;
336 cvsjoko 1.1 // and say we've found a value
337 cvsjoko 1.2 $XML_RPC_xh[$parser]['lv']=2;
338 cvsjoko 1.1 }
339 cvsjoko 1.2
340 cvsjoko 1.1 // 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 cvsjoko 1.2 if ($XML_RPC_xh[$parser]['lv']==1) {
354     $XML_RPC_xh[$parser]['qt']=1;
355     $XML_RPC_xh[$parser]['lv']=2;
356 cvsjoko 1.1 }
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 cvsjoko 1.2
375     function XML_RPC_Client($path, $server, $port = 80,
376     $proxy = '', $proxy_port = 8080,
377     $proxy_user = '', $proxy_pass = '')
378 cvsjoko 1.1 {
379     $this->port=$port;
380     $this->server=$server;
381     $this->path=$path;
382 cvsjoko 1.2 $this->proxy = $proxy;
383     $this->proxy_port = $proxy_port;
384     $this->proxy_user = $proxy_user;
385     $this->proxy_pass = $proxy_pass;
386 cvsjoko 1.1 }
387    
388     function setDebug($in)
389     {
390 cvsjoko 1.2 if ($in) {
391 cvsjoko 1.1 $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 cvsjoko 1.2 $timeout, $this->username,
409 cvsjoko 1.1 $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 cvsjoko 1.2 $fp=fsockopen($this->proxy, $this->proxy_port, $this->errno, $this->errstr);
422 cvsjoko 1.1 }
423 cvsjoko 1.2 }
424 cvsjoko 1.1 else {
425     if($timeout > 0) {
426     $fp=fsockopen($server, $port, $this->errno, $this->errstr, $timeout);
427     }
428     else {
429 cvsjoko 1.2 $fp=fsockopen($server, $port, $this->errno, $this->errstr);
430 cvsjoko 1.1 }
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 cvsjoko 1.2
440 cvsjoko 1.1 // Only create the payload if it was not created previously
441     if(empty($msg->payload)) $msg->createPayload();
442 cvsjoko 1.2
443 cvsjoko 1.1 // 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 cvsjoko 1.2
451    
452 cvsjoko 1.1 if($this->proxy) {
453     $op = "POST http://" . $this->server;
454 cvsjoko 1.2
455 cvsjoko 1.1 if($this->proxy_port) {
456     $op .= ":" . $this->port;
457     }
458     }
459     else {
460     $op = "POST ";
461     }
462 cvsjoko 1.2
463 cvsjoko 1.1 $op .= $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" .
464 cvsjoko 1.2 "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 cvsjoko 1.1 "Content-Type: text/xml\r\nContent-Length: " .
472     strlen($msg->payload) . "\r\n\r\n" .
473     $msg->payload;
474 cvsjoko 1.2
475 cvsjoko 1.1 // print($op);
476 cvsjoko 1.2
477 cvsjoko 1.3 if (!$fp || !fputs($fp, $op, strlen($op))) {
478 cvsjoko 1.1 $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 cvsjoko 1.2 function faultCode()
506     {
507     if (isset($this->fn))
508 cvsjoko 1.1 return $this->fn;
509     else
510     return 0;
511     }
512    
513     function faultString() { return $this->fs; }
514     function value() { return $this->xv; }
515    
516 cvsjoko 1.2 function serialize() {
517 cvsjoko 1.1 $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 cvsjoko 1.2 $rs.="<params>\n<param>\n" . $this->xv->serialize() .
535 cvsjoko 1.1 "</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 cvsjoko 1.2 for($i=0; $i<sizeof($pars); $i++)
555 cvsjoko 1.1 $this->addParam($pars[$i]);
556     }
557     }
558    
559     function xml_header()
560     {
561     return "<?xml version=\"1.0\"?>\n<methodCall>\n";
562     }
563 cvsjoko 1.2
564 cvsjoko 1.1 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 cvsjoko 1.2
619 cvsjoko 1.1 $parser = xml_parser_create($XML_RPC_defencoding);
620    
621     $XML_RPC_xh[$parser]=array();
622    
623 cvsjoko 1.2 $XML_RPC_xh[$parser]['st']="";
624     $XML_RPC_xh[$parser]['cm']=0;
625     $XML_RPC_xh[$parser]['isf']=0;
626 cvsjoko 1.1 $XML_RPC_xh[$parser]['ac']="";
627     $XML_RPC_xh[$parser]['qt']="";
628 cvsjoko 1.2
629 cvsjoko 1.1 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 cvsjoko 1.2 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 cvsjoko 1.1 // see if we got an HTTP 200 OK, else bomb
642     // but only do this if we're using the HTTP protocol.
643 cvsjoko 1.2 if (ereg("^HTTP",$data) &&
644 cvsjoko 1.1 !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 cvsjoko 1.2
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 cvsjoko 1.1 $hdrfnd=1;
660     }
661 cvsjoko 1.2
662 cvsjoko 1.1 if (!xml_parse($parser, $data, sizeof($data))) {
663     // thanks to Peter Kocks <peter.kocks@baygate.com>
664 cvsjoko 1.2 if((xml_get_current_line_number($parser)) == 1)
665 cvsjoko 1.1 $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 cvsjoko 1.2 print "<PRE>---EVALING---[" .
679     strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
680 cvsjoko 1.1 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 cvsjoko 1.2 $r=new XML_RPC_Response($v, $f->scalarval(),
694 cvsjoko 1.1 $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 cvsjoko 1.2
732 cvsjoko 1.1 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 cvsjoko 1.2
742 cvsjoko 1.1 if ($type==$XML_RPC_Boolean) {
743 cvsjoko 1.2 if (strcasecmp($val,"true")==0 ||
744     $val==1 ||
745     ($val==true &&
746 cvsjoko 1.1 strcasecmp($val,"false"))) {
747 cvsjoko 1.2
748 cvsjoko 1.1 $val=1;
749     } else {
750     $val=0;
751     }
752     }
753 cvsjoko 1.2
754 cvsjoko 1.1 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 cvsjoko 1.2 echo "<B>XML_RPC_Value</B>: already initialized as a [" .
772 cvsjoko 1.1 $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 cvsjoko 1.2 echo "<B>XML_RPC_Value</B>: already initialized as a [" .
785 cvsjoko 1.1 $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 cvsjoko 1.2
896 cvsjoko 1.1 function structeach()
897     {
898     return each($this->me["struct"]);
899     }
900 cvsjoko 1.2
901 cvsjoko 1.1 function getval() {
902     // UNSTABLE
903     global $XML_RPC_BOOLEAN, $XML_RPC_Base64;
904 cvsjoko 1.2
905 cvsjoko 1.1 reset($this->me);
906     list($a,$b)=each($this->me);
907 cvsjoko 1.2
908 cvsjoko 1.1 // 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 cvsjoko 1.2
930 cvsjoko 1.1 // end contrib
931     return $b;
932     }
933 cvsjoko 1.2
934 cvsjoko 1.1 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 cvsjoko 1.2 if ($a==$XML_RPC_I4)
948 cvsjoko 1.1 $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 cvsjoko 1.2 //
978     // these routines always assume localtime unless
979 cvsjoko 1.1 // $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 cvsjoko 1.2 if (function_exists("gmstrftime"))
985 cvsjoko 1.1 // 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 cvsjoko 1.2
993 cvsjoko 1.1 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 cvsjoko 1.2
1001 cvsjoko 1.1 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 cvsjoko 1.2 }
1007 cvsjoko 1.1
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 cvsjoko 1.2 return $arr;
1031 cvsjoko 1.1 }
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