]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/XMLRPC/xmlrpc_emu.inc
Reformat code
[SourceForge/phpwiki.git] / lib / XMLRPC / xmlrpc_emu.inc
1 <?php
2
3 /*
4 xmlrpc_emu.inc -- xmlrpc.inc wrapper.
5
6 08/30/01 - last modified by Dan Libby <dan@libby.com>
7
8 This code provides API compatibility with Edd Dumbill's php xmlrpc
9 library (http://phpxmlrpc.sourceforge.net/) but uses the xmlrpc-epi 
10 engine for the actual xml processing.  It is intended to provide a 
11 smooth transition path for those who would like to be able to use either
12 implementation.
13
14 To use in your existing application, simply change:
15
16 include("xmlrpc.inc");
17
18 to:
19
20 include("xmlrpc_emu.inc");
21
22 Notes:
23 - This file requires that xmlrpc-epi C extension be installed.
24   See http://xmlrpc-epi.sourceforge.net/
25
26 - xmlrpc_decode, xmlrpc_encode are present in both the xmlrpc-epi
27   C extension and the usefulinc implementation, and conflict.
28   They have been enhanced and renamed to val_to_php, php_to_val.
29
30 - Certain methods are not implemented and will typically return
31   a message saying so.
32
33 */
34
35 // by Edd Dumbill (C) 1999-2001
36 // <edd@usefulinc.com>
37 //
38
39 // Copyright (c) 1999,2000,2001 Edd Dumbill.
40 // All rights reserved.
41 //
42 // Redistribution and use in source and binary forms, with or without
43 // modification, are permitted provided that the following conditions
44 // are met:
45 //
46 //    * Redistributions of source code must retain the above copyright
47 //      notice, this list of conditions and the following disclaimer.
48 //
49 //    * Redistributions in binary form must reproduce the above
50 //      copyright notice, this list of conditions and the following
51 //      disclaimer in the documentation and/or other materials provided
52 //      with the distribution.
53 //
54 //    * Neither the name of the "PHP for XML-RPC" nor the names of its
55 //      contributors may be used to endorse or promote products derived
56 //      from this software without specific prior written permission.
57 //
58 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
59 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
60 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
61 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
62 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
63 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
64 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
65 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
67 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
69 // OF THE POSSIBILITY OF SUCH DAMAGE.
70
71 // Requires: transport.php
72
73 // change path as necessary. or set before including this file.
74 if (!$xmlrpc_util_path) {
75     $xmlrpc_util_path = "./utils/";
76 }
77 include_once("$xmlrpc_util_path/utils.php");
78
79 // xmlrpc types.  seems like these should be defines instead of globals.
80 $xmlrpcI4 = "i4";
81 $xmlrpcInt = "int";
82 $xmlrpcBoolean = "boolean";
83 $xmlrpcDouble = "double";
84 $xmlrpcString = "string";
85 $xmlrpcDateTime = "dateTime.iso8601";
86 $xmlrpcBase64 = "base64";
87 $xmlrpcArray = "array";
88 $xmlrpcStruct = "struct";
89
90 // map local types to xmlrpc-epi-php types.
91 $epiTypeMap = array($xmlrpcI4 => "int",
92     $xmlrpcInt => "int",
93     $xmlrpcBoolean => "boolean",
94     $xmlrpcString => "string",
95     $xmlrpcDouble => "double",
96     $xmlrpcDateTime => "datetime",
97     $xmlrpcBase64 => "base64",
98     $xmlrpcArray => "array",
99     $xmlrpcStruct => "struct");
100
101 // map local types to php types
102 $phpTypeMap = array($xmlrpcI4 => "integer",
103     $xmlrpcInt => "integer",
104     $xmlrpcBoolean => "boolean",
105     $xmlrpcString => "string",
106     $xmlrpcDouble => "double",
107     $xmlrpcDateTime => "string",
108     $xmlrpcBase64 => "string",
109     $xmlrpcArray => "array",
110     $xmlrpcStruct => "array");
111
112 $xmlrpcTypes = array($xmlrpcI4 => 1,
113     $xmlrpcInt => 1,
114     $xmlrpcBoolean => 1,
115     $xmlrpcString => 1,
116     $xmlrpcDouble => 1,
117     $xmlrpcDateTime => 1,
118     $xmlrpcBase64 => 1,
119     $xmlrpcArray => 2,
120     $xmlrpcStruct => 3);
121
122 // some error definitions
123 $xmlrpcerr["unknown_method"] = 1;
124 $xmlrpcstr["unknown_method"] = "Unknown method";
125 $xmlrpcerr["invalid_return"] = 2;
126 $xmlrpcstr["invalid_return"] = "Invalid return payload: enabling debugging to examine incoming payload";
127 $xmlrpcerr["incorrect_params"] = 3;
128 $xmlrpcstr["incorrect_params"] = "Incorrect parameters passed to method";
129 $xmlrpcerr["introspect_unknown"] = 4;
130 $xmlrpcstr["introspect_unknown"] = "Can't introspect: method unknown";
131 $xmlrpcerr["http_error"] = 5;
132 $xmlrpcstr["http_error"] = "Didn't receive 200 OK from remote server.";
133 $xmlrpcerr["no_data"] = 6;
134 $xmlrpcstr["no_data"] = "No data received from server.";
135 $xmlrpcerr["no_ssl"] = 7;
136 $xmlrpcstr["no_ssl"] = "No SSL support compiled in.";
137 $xmlrpcerr["curl_fail"] = 8;
138 $xmlrpcstr["curl_fail"] = "CURL error";
139
140 $xmlrpc_defencoding = "UTF-8";
141
142 $xmlrpcName = "XML-RPC for PHP (xmlrpc-epi wrapper version)";
143 $xmlrpcVersion = "1.0";
144
145 // let user errors start at 800
146 $xmlrpcerruser = 800;
147
148
149 /************************************************
150  * xmlrpc client class.  basically a wrapper for *
151  * xu_rpc_http().                                *
152  ************************************************/
153 class xmlrpc_client
154 {
155     var $path;
156     var $server;
157     var $port;
158     var $errno;
159     var $errstring;
160     var $debug = 0;
161     var $username = "";
162     var $password = "";
163
164     // constructor
165     function xmlrpc_client($path, $server, $port = 80)
166     {
167         $this->port = $port;
168         $this->server = $server;
169         $this->path = $path;
170     }
171
172     // public. for debugging info.
173     function setDebug($in)
174     {
175         if ($in) {
176             $this->debug = 1;
177         } else {
178             $this->debug = 0;
179         }
180     }
181
182     // public. for http authentication.
183     function setCredentials($u, $p)
184     {
185         $this->username = $u;
186         $this->password = $p;
187     }
188
189     // public.  sent request to server.
190     function send($msg, $timeout = 0, $pause = 0, $secure = false)
191     {
192         // where msg is an xmlrpcmsg
193         $msg->debug = $this->debug;
194
195
196         if ($pause) {
197             sleep($pause);
198         }
199
200         return $this->sendPayloadHTTP10($msg, $this->server, $this->port, $timeout, $this->username, $this->password);
201
202     }
203
204     // private. performs http post request
205     function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, $username = "", $password = "", $secure = false)
206     {
207         // Only create the payload if it was not created previously
208         if (empty($msg->payload)) {
209             $msg->createPayload();
210         }
211
212         $response_buf = xu_query_http_post($msg->payload, $server, $this->path, $port,
213             $this->debug, $timeout, $username, $password, $secure);
214
215         $resp = $msg->parseResponse($response_buf);
216
217         return $resp;
218     }
219
220 } // end class xmlrpc_client
221
222 /******************************************
223  * a class to represent an xmlrpc response *
224  ******************************************/
225 class xmlrpcresp
226 {
227     var $xv;
228     var $fn;
229     var $fs;
230     var $hdrs;
231
232     // constructor.
233     function xmlrpcresp($val, $fcode = 0, $fstr = "")
234     {
235         if ($fcode != 0) {
236             $this->fn = $fcode;
237             $this->fs = $fstr;
238         } else {
239             $this->xv = $val;
240         }
241     }
242
243     // public. get methods
244     function faultCode()
245     {
246         return $this->fn;
247     }
248
249     function faultString()
250     {
251         return $this->fs;
252     }
253
254     function value()
255     {
256         return $this->xv;
257     }
258
259     // public. serialize self as xml string.
260     function serialize()
261     {
262         /* check if fault */
263         if ($this->fn) {
264             $result = xmlrpc_encode_request(null, xu_fault_code($this->fn, $this->fs));
265         } else {
266             $php_vals = val_to_php($this->xv);
267
268             // null for methodname indicates response type.
269             $result = xmlrpc_encode_request(null, $php_vals);
270         }
271
272         return $result;
273     }
274 }
275
276 /*****************************************
277  * a class to represent an xmlrpc message *
278  *****************************************/
279 class xmlrpcmsg
280 {
281     var $payload;
282     var $methodname;
283     var $params = array();
284     var $debug = 0;
285
286     // constructor
287     function xmlrpcmsg($meth, $pars = 0)
288     {
289         $this->methodname = $meth;
290         if (is_array($pars) && sizeof($pars) > 0) {
291             for ($i = 0; $i < sizeof($pars); $i++)
292                 $this->addParam($pars[$i]);
293         }
294     }
295
296     // unused. xmlrpc-epi does this automagically
297     function xml_header()
298     {
299         return "xml_header not supported";
300     }
301
302     // unused. not necessary
303     function xml_footer()
304     {
305         return "xml_footer not supported";
306     }
307
308     // private. performs the actual message serialization.
309     function createPayload()
310     {
311         $php_params_val = array();
312         foreach ($this->params as $param) {
313             $php_params_val[] = val_to_php($param);
314         }
315         $this->payload = xmlrpc_encode_request($this->methodname, $php_params_val);
316     }
317
318     // public. returns name of method
319     function method($meth = "")
320     {
321         if ($meth != "") {
322             $this->methodname = $meth;
323         }
324         return $this->methodname;
325     }
326
327     // public. serialization message as xml
328     function serialize()
329     {
330         $this->createPayload();
331         return $this->payload;
332     }
333
334     // public. add/retrieve/count message params
335     function addParam($par)
336     {
337         $this->params[] = $par;
338     }
339
340     function getParam($i)
341     {
342         return $this->params[$i];
343     }
344
345     function getNumParams()
346     {
347         return sizeof($this->params);
348     }
349
350     // public. in case we are given a file handle
351     function parseResponseFile($fp)
352     {
353         $ipd = "";
354
355         while ($data = fread($fp, 32768)) {
356             $ipd .= $data;
357         }
358         return $this->parseResponse($ipd);
359     }
360
361     // public. parse xml, return as xmlrpcresp.
362     function parseResponse($data = "")
363     {
364         $php_val = xmlrpc_decode($data);
365
366         /* check for fault */
367         if (is_array($php_val) && isset($php_val[0][faultCode])) {
368             $fc = $php_val[0][faultCode];
369             $fs = $php_val[0][faultString];
370         } else {
371             $rpc_val = php_to_val($php_val);
372         }
373
374
375         return new xmlrpcresp($rpc_val, $fc, $fs);
376     }
377
378 }
379
380 /***************************************
381  * a class to represent an xmlrpc value *
382  ***************************************/
383 class xmlrpcval
384 {
385     var $me = array();
386     var $mytype = 0;
387
388     // constructor
389     function xmlrpcval($val = -1, $type = "")
390     {
391         global $xmlrpcTypes;
392         $this->me = array();
393         $this->mytype = 0;
394         if ($val != -1 || $type != "") {
395             if ($type == "") $type = "string";
396             if ($xmlrpcTypes[$type] == 1) {
397                 $this->addScalar($val, $type);
398             } else if ($xmlrpcTypes[$type] == 2)
399                 $this->addArray($val);
400             else if ($xmlrpcTypes[$type] == 3)
401                 $this->addStruct($val);
402         }
403     }
404
405     // public. add a php scalar value.
406     function addScalar($val, $type = "string")
407     {
408         global $xmlrpcTypes, $xmlrpcBoolean;
409
410         if ($this->mytype == 1) {
411             echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";
412             return 0;
413         }
414         $typeof = $xmlrpcTypes[$type];
415         if ($typeof != 1) {
416             echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";
417             return 0;
418         }
419
420         if ($type == $xmlrpcBoolean) {
421             if (strcasecmp($val, "true") == 0 || $val == 1 || $val == true) {
422                 $val = 1;
423             } else {
424                 $val = 0;
425             }
426         }
427
428         if ($this->mytype == 2) {
429             // we're adding to an array here
430             $ar = $this->me["array"];
431             $ar[] = new xmlrpcval($val, $type);
432             $this->me["array"] = $ar;
433         } else {
434             // a scalar, so set the value and remember we're scalar
435             $this->me[$type] = $val;
436             $this->mytype = $typeof;
437         }
438         return 1;
439     }
440
441     // public. add a php array
442     function addArray($vals)
443     {
444         global $xmlrpcTypes;
445         if ($this->mytype != 0) {
446             echo "<B>xmlrpcval</B>: already initialized as a [" .
447                 $this->kindOf() . "]<BR>";
448             return 0;
449         }
450         $this->mytype = $xmlrpcTypes["array"];
451         $this->me["array"] = $vals;
452         return 1;
453     }
454
455     // public. add a php keyed array as a struct.
456     function addStruct($vals)
457     {
458         global $xmlrpcTypes;
459         if ($this->mytype != 0) {
460             echo "<B>xmlrpcval</B>: already initialized as a [" .
461                 $this->kindOf() . "]<BR>";
462             return 0;
463         }
464         $this->mytype = $xmlrpcTypes["struct"];
465         $this->me["struct"] = $vals;
466         return 1;
467     }
468
469     // public. write myself out as html.
470     function dump($ar)
471     {
472         foreach ($ar as $key => $val) {
473             echo "$key => $val<br>";
474             if ($key == 'array') {
475                 foreach ($val as $key2 => $val2) {
476                     echo "-- $key2 => $val2";
477                 }
478             }
479         }
480     }
481
482     // public. kind of value.
483     // (not 1 to 1 mapping with xmlrpc types or php types)
484     function kindOf()
485     {
486         switch ($this->mytype) {
487             case 3:
488                 return "struct";
489                 break;
490             case 2:
491                 return "array";
492                 break;
493             case 1:
494                 return "scalar";
495                 break;
496             default:
497                 return "undef";
498         }
499     }
500
501     // unused.
502     function serializedata($typ, $val)
503     {
504         return "serializedata not supported";
505     }
506
507     // public. serialize self as xml.
508     function serialize()
509     {
510         return $this->serializeval($this);
511     }
512
513     // public. serialize any xmlrpcval object as xml.
514     function serializeval($o)
515     {
516         $php_val = val_to_php($o);
517         $result_xml = xmlrpc_encode($php_val);
518
519         return $result_xml;
520     }
521
522     // public.  get struct members.
523     function structmem($m)
524     {
525         $nv = $this->me["struct"][$m];
526         return $nv;
527     }
528
529     // public. reset struct to first item.
530     function structreset()
531     {
532         reset($this->me["struct"]);
533     }
534
535     // public. get key/val pair of next struct item.
536     function structeach()
537     {
538         return each($this->me["struct"]);
539     }
540
541     // public. get php type scalar value.
542     function scalarval()
543     {
544         global $xmlrpcBoolean, $xmlrpcBase64;
545         reset($this->me);
546         list($a, $b) = each($this->me);
547         return $b;
548     }
549
550     // public. get xmlrpc type of value.
551     function scalartyp()
552     {
553         global $xmlrpcI4, $xmlrpcInt;
554         reset($this->me);
555         list($a, $b) = each($this->me);
556         if ($a == $xmlrpcI4)
557             $a = $xmlrpcInt;
558         return $a;
559     }
560
561     // public. get array member.
562     function arraymem($m)
563     {
564         $nv = $this->me["array"][$m];
565         return $nv;
566     }
567
568     // public. get array size
569     function arraysize()
570     {
571         reset($this->me);
572         list($a, $b) = each($this->me);
573         return sizeof($b);
574     }
575 }
576
577 // date helpers
578
579 /*****************************************************************
580  * These stubs need to be implemented in the C extension library. *
581  * When they are, these calls will be commented out. -danda       *
582  *****************************************************************/
583
584 function iso8601_encode($timet, $utc = 0)
585 {
586     // return an ISO8601 encoded string
587     // really, timezones ought to be supported
588     // but the XML-RPC spec says:
589     //
590     // "Don't assume a timezone. It should be specified by the server in its
591     // documentation what assumptions it makes about timezones."
592     //
593     // these routines always assume localtime unless
594     // $utc is set to 1, in which case UTC is assumed
595     // and an adjustment for locale is made when encoding
596     if (!$utc) {
597         $t = strftime("%Y%m%dT%H:%M:%S", $timet);
598     } else {
599         if (function_exists("gmstrftime"))
600             // gmstrftime doesn't exist in some versions
601             // of PHP
602             $t = gmstrftime("%Y%m%dT%H:%M:%S", $timet);
603         else {
604             $t = strftime("%Y%m%dT%H:%M:%S", $timet - date("Z"));
605         }
606     }
607     return $t;
608 }
609
610 function iso8601_decode($idate, $utc = 0)
611 {
612     // return a timet in the localtime, or UTC
613     $t = 0;
614     if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",
615         $idate, $regs)
616     ) {
617         if ($utc) {
618             $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
619         } else {
620             $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
621         }
622     }
623     return $t;
624 }
625
626 /****************************************************************
627  * xmlrpc_decode takes a message in PHP xmlrpc object format and *
628  * tranlates it into native PHP types.                           *
629  ****************************************************************/
630 function val_to_php($xmlrpc_val)
631 {
632     global $epiTypeMap;
633     global $phpTypeMap;
634
635     $kind = $xmlrpc_val->kindOf();
636
637     if ($kind == "scalar") {
638         $type = $xmlrpc_val->scalartyp();
639         $php_val = $xmlrpc_val->scalarval();
640         $php_type = $phpTypeMap[$type];
641
642         // value is stored in object as a string. we want
643         // its native type.
644         settype($php_val, $php_type);
645
646         // magic to let xmlprc-epi engine know about base64 and datetime types.
647         $epi_type = $epiTypeMap[$type];
648         if ($epi_type) {
649             xmlrpc_set_type($php_val, $epi_type);
650             // php_val may now be an object, if epi_type = base64 or datetime.
651         }
652
653         return $php_val;
654     } // generate php indexed array. recurse for sub-values.
655     else if ($kind == "array") {
656         $size = $xmlrpc_val->arraysize();
657         $arr = array();
658
659         for ($i = 0; $i < $size; $i++) {
660             $arr[] = val_to_php($xmlrpc_val->arraymem($i));
661         }
662         return $arr;
663     } // generate php keyed array. recurse for sub-values.
664     else if ($kind == "struct") {
665         $xmlrpc_val->structreset();
666         $arr = array();
667
668         while (list($key, $value) = $xmlrpc_val->structeach()) {
669             $arr[$key] = val_to_php($value);
670         }
671         return $arr;
672     }
673 }
674
675 /****************************************************************
676  * php_to_val takes native php types and encodes them into       *
677  * xmlrpc PHP object format.                                     *
678  ****************************************************************/
679 function php_to_val($php_val)
680 {
681     global $xmlrpcInt;
682     global $xmlrpcDouble;
683     global $xmlrpcString;
684     global $xmlrpcArray;
685     global $xmlrpcStruct;
686     global $xmlrpcBoolean;
687     global $xmlrpcDateTime;
688     global $xmlrpcBase64;
689
690     // get the xmlrpc type of value.
691     $type = xmlrpc_get_type($php_val);
692     $xmlrpc_val = new xmlrpcval;
693
694     switch ($type) {
695         case "array":
696         case "vector": //unused
697             $arr = array();
698             foreach ($php_val as $v) {
699                 $arr[] = php_to_val($v);
700             }
701             $xmlrpc_val->addArray($arr);
702             break;
703         case "object": //unused
704         case "struct":
705             foreach ($php_val as $k => $v) {
706                 $arr[$k] = php_to_val($v);
707             }
708             $xmlrpc_val->addStruct($arr);
709             break;
710         case "integer": //unused
711         case "int":
712             $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
713             break;
714         case "boolean":
715             $xmlrpc_val->addScalar($php_val, $xmlprcBoolean);
716             break;
717         case "double":
718             $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
719             break;
720         case "string":
721             $xmlrpc_val->addScalar($php_val, $xmlrpcString);
722             break;
723         case "datetime":
724             $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcDateTime);
725             break;
726         case "base64":
727             $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcBase64);
728             break;
729         case "unknown type":
730         default:
731             $xmlrpc_val = false;
732             break;
733     }
734     return $xmlrpc_val;
735 }