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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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

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