]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/XMLRPC/xmlrpc_emu.inc
Remove svn:keywords
[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    var $path;
155    var $server;
156    var $port;
157    var $errno;
158    var $errstring;
159    var $debug=0;
160    var $username="";
161    var $password="";
162
163    // constructor
164    function xmlrpc_client($path, $server, $port=80) {
165       $this->port=$port; $this->server=$server; $this->path=$path;
166    }
167
168    // public. for debugging info.
169    function setDebug($in) {
170       if ($in) {
171          $this->debug=1;
172       } else {
173          $this->debug=0;
174       }
175    }
176
177    // public. for http authentication.
178    function setCredentials($u, $p) {
179       $this->username=$u;
180       $this->password=$p;
181    }
182
183    // public.  sent request to server.
184    function send($msg, $timeout=0, $pause=0, $secure=false) {
185       // where msg is an xmlrpcmsg
186       $msg->debug=$this->debug;
187
188
189       if ($pause) {
190          sleep($pause);
191       }
192
193       return $this->sendPayloadHTTP10($msg, $this->server, $this->port, $timeout, $this->username, $this->password);
194
195    }
196
197    // private. performs http post request
198    function sendPayloadHTTP10($msg, $server, $port, $timeout=0, $username="", $password="", $secure=false) {
199       // Only create the payload if it was not created previously
200       if (empty($msg->payload)) {
201          $msg->createPayload();
202       }
203
204       $response_buf = xu_query_http_post($msg->payload, $server, $this->path, $port, 
205                                          $this->debug, $timeout, $username, $password, $secure);
206
207       $resp=$msg->parseResponse($response_buf);
208
209       return $resp;
210    }
211
212 } // end class xmlrpc_client
213
214 /******************************************
215 * a class to represent an xmlrpc response *
216 ******************************************/
217 class xmlrpcresp {
218    var $xv;
219    var $fn;
220    var $fs;
221    var $hdrs;
222
223    // constructor.
224    function xmlrpcresp($val, $fcode=0, $fstr="") {
225       if ($fcode!=0) {
226          $this->fn=$fcode;
227          $this->fs=$fstr;
228       } else {
229          $this->xv=$val;
230       }
231    }
232
233    // public. get methods
234    function faultCode() { return $this->fn;}
235    function faultString() { return $this->fs;}
236    function value() { return $this->xv;}
237
238    // public. serialize self as xml string.
239    function serialize() {
240       /* check if fault */
241       if ($this->fn) {
242          $result = xmlrpc_encode_request(null, xu_fault_code($this->fn, $this->fs));
243       } else {
244          $php_vals = val_to_php($this->xv);
245
246          // null for methodname indicates response type.
247          $result = xmlrpc_encode_request(null, $php_vals);
248       }
249
250       return $result;
251    }
252 }
253
254 /*****************************************
255 * a class to represent an xmlrpc message *
256 *****************************************/
257 class xmlrpcmsg {
258    var $payload;
259    var $methodname;
260    var $params=array();
261    var $debug=0;
262
263    // constructor
264    function xmlrpcmsg($meth, $pars=0) {
265       $this->methodname=$meth;
266       if (is_array($pars) && sizeof($pars)>0) {
267          for ($i=0; $i<sizeof($pars); $i++)
268             $this->addParam($pars[$i]);
269       }
270    }
271
272    // unused. xmlrpc-epi does this automagically
273    function xml_header() {
274       return "xml_header not supported";
275    }
276
277    // unused. not necessary
278    function xml_footer() {
279       return "xml_footer not supported";
280    }
281
282    // private. performs the actual message serialization.
283    function createPayload() {
284       $php_params_val = array();
285       foreach($this->params as $param) {
286          $php_params_val[] = val_to_php($param);
287       }
288       $this->payload = xmlrpc_encode_request($this->methodname, $php_params_val);
289    }
290
291    // public. returns name of method
292    function method($meth="") {
293       if ($meth!="") {
294          $this->methodname=$meth;
295       }
296       return $this->methodname;
297    }
298
299    // public. serialization message as xml
300    function serialize() {
301       $this->createPayload();
302       return $this->payload;
303    }
304
305    // public. add/retrieve/count message params
306    function addParam($par) { $this->params[]=$par;}
307    function getParam($i) { return $this->params[$i];}
308    function getNumParams() { return sizeof($this->params);}
309
310    // public. in case we are given a file handle
311    function parseResponseFile($fp) {
312       $ipd="";
313
314       while ($data=fread($fp, 32768)) {
315          $ipd.=$data;
316       }
317       return $this->parseResponse($ipd);
318    }
319
320    // public. parse xml, return as xmlrpcresp.
321    function parseResponse($data="") {
322       $php_val = xmlrpc_decode($data);
323
324       /* check for fault */
325       if (is_array($php_val) && isset($php_val[0][faultCode])) {
326          $fc = $php_val[0][faultCode];
327          $fs = $php_val[0][faultString];
328       } else {
329          $rpc_val = php_to_val($php_val);
330       }
331
332
333       return new xmlrpcresp($rpc_val, $fc, $fs);
334    }
335
336 }
337
338 /***************************************
339 * a class to represent an xmlrpc value *
340 ***************************************/
341 class xmlrpcval {
342    var $me=array();
343    var $mytype=0;
344
345    // constructor
346    function xmlrpcval($val=-1, $type="") {
347       global $xmlrpcTypes;
348       $this->me=array();
349       $this->mytype=0;
350       if ($val!=-1 || $type!="") {
351          if ($type=="") $type="string";
352          if ($xmlrpcTypes[$type]==1) {
353             $this->addScalar($val,$type);
354          } else if ($xmlrpcTypes[$type]==2)
355             $this->addArray($val);
356          else if ($xmlrpcTypes[$type]==3)
357             $this->addStruct($val);
358       }
359    }
360
361    // public. add a php scalar value.
362    function addScalar($val, $type="string") {
363       global $xmlrpcTypes, $xmlrpcBoolean;
364
365       if ($this->mytype==1) {
366          echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";
367          return 0;
368       }
369       $typeof=$xmlrpcTypes[$type];
370       if ($typeof!=1) {
371          echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";
372          return 0;
373       }
374
375       if ($type==$xmlrpcBoolean) {
376          if (strcasecmp($val,"true")==0 || $val==1 || $val==true) {
377             $val=1;
378          } else {
379             $val=0;
380          }
381       }
382
383       if ($this->mytype==2) {
384          // we're adding to an array here
385          $ar=$this->me["array"];
386          $ar[]=new xmlrpcval($val, $type);
387          $this->me["array"]=$ar;
388       } else {
389          // a scalar, so set the value and remember we're scalar
390          $this->me[$type]=$val;
391          $this->mytype=$typeof;
392       }
393       return 1;
394    }
395
396    // public. add a php array
397    function addArray($vals) {
398       global $xmlrpcTypes;
399       if ($this->mytype!=0) {
400          echo "<B>xmlrpcval</B>: already initialized as a [" . 
401          $this->kindOf() . "]<BR>";
402          return 0;
403       }
404       $this->mytype=$xmlrpcTypes["array"];
405       $this->me["array"]=$vals;
406       return 1;
407    }
408
409    // public. add a php keyed array as a struct.
410    function addStruct($vals) {
411       global $xmlrpcTypes;
412       if ($this->mytype!=0) {
413          echo "<B>xmlrpcval</B>: already initialized as a [" . 
414          $this->kindOf() . "]<BR>";
415          return 0;
416       }
417       $this->mytype=$xmlrpcTypes["struct"];
418       $this->me["struct"]=$vals;
419       return 1;
420    }
421
422    // public. write myself out as html.
423    function dump($ar) {
424       foreach($ar as $key => $val) {
425          echo "$key => $val<br>";
426          if ($key == 'array') {
427             foreach($val as $key2 => $val2) {
428                echo "-- $key2 => $val2";
429             }
430          }
431       }
432    }
433
434    // public. kind of value. 
435    // (not 1 to 1 mapping with xmlrpc types or php types)
436    function kindOf() {
437       switch ($this->mytype) {
438       case 3:
439          return "struct";
440          break;
441       case 2:
442          return "array";
443          break;
444       case 1:
445          return "scalar";
446          break;
447       default:
448          return "undef";
449       }
450    }
451
452    // unused.
453    function serializedata($typ, $val) {
454       return "serializedata not supported";
455    }
456
457    // public. serialize self as xml.
458    function serialize() {
459       return $this->serializeval($this);
460    }
461
462    // public. serialize any xmlrpcval object as xml.
463    function serializeval($o) {
464       $php_val = val_to_php($o);
465       $result_xml = xmlrpc_encode($php_val);
466
467       return $result_xml;
468    }
469
470    // public.  get struct members.
471    function structmem($m) {
472       $nv=$this->me["struct"][$m];
473       return $nv;
474    }
475
476    // public. reset struct to first item.
477    function structreset() {
478       reset($this->me["struct"]);
479    }
480
481    // public. get key/val pair of next struct item.
482    function structeach() {
483       return each($this->me["struct"]);
484    }
485
486    // public. get php type scalar value.
487    function scalarval() {
488       global $xmlrpcBoolean, $xmlrpcBase64;
489       reset($this->me);
490       list($a,$b)=each($this->me);
491       return $b;
492    }
493
494    // public. get xmlrpc type of value.
495    function scalartyp() {
496       global $xmlrpcI4, $xmlrpcInt;
497       reset($this->me);
498       list($a,$b)=each($this->me);
499       if ($a==$xmlrpcI4)
500          $a=$xmlrpcInt;
501       return $a;
502    }
503
504    // public. get array member.
505    function arraymem($m) {
506       $nv=$this->me["array"][$m];
507       return $nv;
508    }
509
510    // public. get array size
511    function arraysize() {
512       reset($this->me);
513       list($a,$b)=each($this->me);
514       return sizeof($b);
515    }
516 }
517
518 // date helpers
519
520 /*****************************************************************
521 * These stubs need to be implemented in the C extension library. *
522 * When they are, these calls will be commented out. -danda       *
523 *****************************************************************/
524
525 function iso8601_encode($timet, $utc=0) {
526    // return an ISO8601 encoded string
527    // really, timezones ought to be supported
528    // but the XML-RPC spec says:
529    //
530    // "Don't assume a timezone. It should be specified by the server in its
531    // documentation what assumptions it makes about timezones."
532    // 
533    // these routines always assume localtime unless 
534    // $utc is set to 1, in which case UTC is assumed
535    // and an adjustment for locale is made when encoding
536    if (!$utc) {
537       $t=strftime("%Y%m%dT%H:%M:%S", $timet);
538    } else {
539       if (function_exists("gmstrftime"))
540          // gmstrftime doesn't exist in some versions
541          // of PHP
542          $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
543       else {
544          $t=strftime("%Y%m%dT%H:%M:%S", $timet-date("Z"));
545       }
546    }
547    return $t;
548 }
549
550 function iso8601_decode($idate, $utc=0) {
551    // return a timet in the localtime, or UTC
552    $t=0;
553    if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",
554             $idate, $regs)) {
555       if ($utc) {
556          $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
557       } else {
558          $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
559       }
560    }
561    return $t;
562 }
563
564 /****************************************************************
565 * xmlrpc_decode takes a message in PHP xmlrpc object format and *
566 * tranlates it into native PHP types.                           *
567 ****************************************************************/
568 function val_to_php($xmlrpc_val) {
569    global $epiTypeMap;
570    global $phpTypeMap;
571
572    $kind = $xmlrpc_val->kindOf();
573
574    if ($kind == "scalar") {
575       $type = $xmlrpc_val->scalartyp();
576       $php_val = $xmlrpc_val->scalarval();
577       $php_type = $phpTypeMap[$type];
578
579       // value is stored in object as a string. we want
580       // its native type.
581       settype($php_val, $php_type);
582
583       // magic to let xmlprc-epi engine know about base64 and datetime types.
584       $epi_type = $epiTypeMap[$type];
585       if($epi_type) {
586          xmlrpc_set_type($php_val, $epi_type);
587          // php_val may now be an object, if epi_type = base64 or datetime.
588       }
589       
590       return $php_val;
591    }
592    // generate php indexed array. recurse for sub-values.
593    else if ($kind == "array") {
594       $size = $xmlrpc_val->arraysize();
595       $arr = array();
596
597       for ($i = 0; $i < $size; $i++) {
598          $arr[] = val_to_php($xmlrpc_val->arraymem($i));
599       }
600       return $arr; 
601    } 
602    // generate php keyed array. recurse for sub-values.
603    else if ($kind == "struct") {
604       $xmlrpc_val->structreset();
605       $arr = array();
606
607       while (list($key,$value)=$xmlrpc_val->structeach()) {
608          $arr[$key] = val_to_php($value);
609       }
610       return $arr;
611    }
612 }
613
614 /****************************************************************
615 * php_to_val takes native php types and encodes them into       *
616 * xmlrpc PHP object format.                                     *
617 ****************************************************************/
618 function php_to_val($php_val) {
619    global $xmlrpcInt;
620    global $xmlrpcDouble;
621    global $xmlrpcString;
622    global $xmlrpcArray;
623    global $xmlrpcStruct;
624    global $xmlrpcBoolean;
625    global $xmlrpcDateTime;
626    global $xmlrpcBase64;
627
628    // get the xmlrpc type of value.
629    $type = xmlrpc_get_type($php_val);
630    $xmlrpc_val = new xmlrpcval;
631
632    switch ($type) {
633    case "array":
634    case "vector":         //unused
635       $arr = array();
636       foreach($php_val as $v) {
637          $arr[] = php_to_val($v);
638       }
639       $xmlrpc_val->addArray($arr);
640       break;
641    case "object":         //unused
642    case "struct":
643       foreach($php_val as $k => $v) {
644          $arr[$k] = php_to_val($v);
645       }
646       $xmlrpc_val->addStruct($arr);
647       break;
648    case "integer":        //unused
649    case "int":
650       $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
651       break;
652    case "boolean":
653       $xmlrpc_val->addScalar($php_val, $xmlprcBoolean);
654       break;
655    case "double":
656       $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
657       break;
658    case "string":
659       $xmlrpc_val->addScalar($php_val, $xmlrpcString);
660       break;
661    case "datetime":
662       $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcDateTime);
663       break;
664    case "base64":
665       $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcBase64);
666       break;
667    case "unknown type":
668    default:
669       $xmlrpc_val = false;
670       break;
671    }
672    return $xmlrpc_val;
673 }
674
675 ?>