4 xmlrpc_emu.inc -- xmlrpc.inc wrapper.
6 08/30/01 - last modified by Dan Libby <dan@libby.com>
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
14 To use in your existing application, simply change:
16 include("xmlrpc.inc");
20 include("xmlrpc_emu.inc");
23 - This file requires that xmlrpc-epi C extension be installed.
24 See http://xmlrpc-epi.sourceforge.net/
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.
30 - Certain methods are not implemented and will typically return
35 // by Edd Dumbill (C) 1999-2001
36 // <edd@usefulinc.com>
39 // Copyright (c) 1999,2000,2001 Edd Dumbill.
40 // All rights reserved.
42 // Redistribution and use in source and binary forms, with or without
43 // modification, are permitted provided that the following conditions
46 // * Redistributions of source code must retain the above copyright
47 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
71 // Requires: transport.php
73 // change path as necessary. or set before including this file.
74 if(!$xmlrpc_util_path) {
75 $xmlrpc_util_path = "./utils/";
77 include_once("$xmlrpc_util_path/utils.php");
79 // xmlrpc types. seems like these should be defines instead of globals.
82 $xmlrpcBoolean="boolean";
83 $xmlrpcDouble="double";
84 $xmlrpcString="string";
85 $xmlrpcDateTime="dateTime.iso8601";
86 $xmlrpcBase64="base64";
88 $xmlrpcStruct="struct";
90 // map local types to xmlrpc-epi-php types.
91 $epiTypeMap = array($xmlrpcI4 => "int",
93 $xmlrpcBoolean => "boolean",
94 $xmlrpcString => "string",
95 $xmlrpcDouble => "double",
96 $xmlrpcDateTime => "datetime",
97 $xmlrpcBase64 => "base64",
98 $xmlrpcArray => "array",
99 $xmlrpcStruct => "struct");
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");
112 $xmlrpcTypes=array($xmlrpcI4 => 1,
117 $xmlrpcDateTime => 1,
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";
140 $xmlrpc_defencoding="UTF-8";
142 $xmlrpcName="XML-RPC for PHP (xmlrpc-epi wrapper version)";
143 $xmlrpcVersion="1.0";
145 // let user errors start at 800
149 /************************************************
150 * xmlrpc client class. basically a wrapper for *
152 ************************************************/
153 class xmlrpc_client {
164 function xmlrpc_client($path, $server, $port=80) {
165 $this->port=$port; $this->server=$server; $this->path=$path;
168 // public. for debugging info.
169 function setDebug($in) {
177 // public. for http authentication.
178 function setCredentials($u, $p) {
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;
193 return $this->sendPayloadHTTP10($msg, $this->server, $this->port, $timeout, $this->username, $this->password);
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();
204 $response_buf = xu_query_http_post($msg->payload, $server, $this->path, $port,
205 $this->debug, $timeout, $username, $password, $secure);
207 $resp=$msg->parseResponse($response_buf);
212 } // end class xmlrpc_client
214 /******************************************
215 * a class to represent an xmlrpc response *
216 ******************************************/
224 function xmlrpcresp($val, $fcode=0, $fstr="") {
233 // public. get methods
234 function faultCode() { return $this->fn;}
235 function faultString() { return $this->fs;}
236 function value() { return $this->xv;}
238 // public. serialize self as xml string.
239 function serialize() {
242 $result = xmlrpc_encode_request(null, xu_fault_code($this->fn, $this->fs));
244 $php_vals = val_to_php($this->xv);
246 // null for methodname indicates response type.
247 $result = xmlrpc_encode_request(null, $php_vals);
254 /*****************************************
255 * a class to represent an xmlrpc message *
256 *****************************************/
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]);
272 // unused. xmlrpc-epi does this automagically
273 function xml_header() {
274 return "xml_header not supported";
277 // unused. not necessary
278 function xml_footer() {
279 return "xml_footer not supported";
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);
288 $this->payload = xmlrpc_encode_request($this->methodname, $php_params_val);
291 // public. returns name of method
292 function method($meth="") {
294 $this->methodname=$meth;
296 return $this->methodname;
299 // public. serialization message as xml
300 function serialize() {
301 $this->createPayload();
302 return $this->payload;
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);}
310 // public. in case we are given a file handle
311 function parseResponseFile($fp) {
314 while ($data=fread($fp, 32768)) {
317 return $this->parseResponse($ipd);
320 // public. parse xml, return as xmlrpcresp.
321 function parseResponse($data="") {
322 $php_val = xmlrpc_decode($data);
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];
329 $rpc_val = php_to_val($php_val);
333 return new xmlrpcresp($rpc_val, $fc, $fs);
338 /***************************************
339 * a class to represent an xmlrpc value *
340 ***************************************/
346 function xmlrpcval($val=-1, $type="") {
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);
361 // public. add a php scalar value.
362 function addScalar($val, $type="string") {
363 global $xmlrpcTypes, $xmlrpcBoolean;
365 if ($this->mytype==1) {
366 echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";
369 $typeof=$xmlrpcTypes[$type];
371 echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";
375 if ($type==$xmlrpcBoolean) {
376 if (strcasecmp($val,"true")==0 || $val==1 || $val==true) {
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;
389 // a scalar, so set the value and remember we're scalar
390 $this->me[$type]=$val;
391 $this->mytype=$typeof;
396 // public. add a php array
397 function addArray($vals) {
399 if ($this->mytype!=0) {
400 echo "<B>xmlrpcval</B>: already initialized as a [" .
401 $this->kindOf() . "]<BR>";
404 $this->mytype=$xmlrpcTypes["array"];
405 $this->me["array"]=$vals;
409 // public. add a php keyed array as a struct.
410 function addStruct($vals) {
412 if ($this->mytype!=0) {
413 echo "<B>xmlrpcval</B>: already initialized as a [" .
414 $this->kindOf() . "]<BR>";
417 $this->mytype=$xmlrpcTypes["struct"];
418 $this->me["struct"]=$vals;
422 // public. write myself out as html.
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";
434 // public. kind of value.
435 // (not 1 to 1 mapping with xmlrpc types or php types)
437 switch ($this->mytype) {
453 function serializedata($typ, $val) {
454 return "serializedata not supported";
457 // public. serialize self as xml.
458 function serialize() {
459 return $this->serializeval($this);
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);
470 // public. get struct members.
471 function structmem($m) {
472 $nv=$this->me["struct"][$m];
476 // public. reset struct to first item.
477 function structreset() {
478 reset($this->me["struct"]);
481 // public. get key/val pair of next struct item.
482 function structeach() {
483 return each($this->me["struct"]);
486 // public. get php type scalar value.
487 function scalarval() {
488 global $xmlrpcBoolean, $xmlrpcBase64;
490 list($a,$b)=each($this->me);
494 // public. get xmlrpc type of value.
495 function scalartyp() {
496 global $xmlrpcI4, $xmlrpcInt;
498 list($a,$b)=each($this->me);
504 // public. get array member.
505 function arraymem($m) {
506 $nv=$this->me["array"][$m];
510 // public. get array size
511 function arraysize() {
513 list($a,$b)=each($this->me);
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 *****************************************************************/
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:
530 // "Don't assume a timezone. It should be specified by the server in its
531 // documentation what assumptions it makes about timezones."
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
537 $t=strftime("%Y%m%dT%H:%M:%S", $timet);
539 if (function_exists("gmstrftime"))
540 // gmstrftime doesn't exist in some versions
542 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
544 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date("Z"));
550 function iso8601_decode($idate, $utc=0) {
551 // return a timet in the localtime, or UTC
553 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",
556 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
558 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
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) {
572 $kind = $xmlrpc_val->kindOf();
574 if ($kind == "scalar") {
575 $type = $xmlrpc_val->scalartyp();
576 $php_val = $xmlrpc_val->scalarval();
577 $php_type = $phpTypeMap[$type];
579 // value is stored in object as a string. we want
581 settype($php_val, $php_type);
583 // magic to let xmlprc-epi engine know about base64 and datetime types.
584 $epi_type = $epiTypeMap[$type];
586 xmlrpc_set_type($php_val, $epi_type);
587 // php_val may now be an object, if epi_type = base64 or datetime.
592 // generate php indexed array. recurse for sub-values.
593 else if ($kind == "array") {
594 $size = $xmlrpc_val->arraysize();
597 for ($i = 0; $i < $size; $i++) {
598 $arr[] = val_to_php($xmlrpc_val->arraymem($i));
602 // generate php keyed array. recurse for sub-values.
603 else if ($kind == "struct") {
604 $xmlrpc_val->structreset();
607 while (list($key,$value)=$xmlrpc_val->structeach()) {
608 $arr[$key] = val_to_php($value);
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) {
620 global $xmlrpcDouble;
621 global $xmlrpcString;
623 global $xmlrpcStruct;
624 global $xmlrpcBoolean;
625 global $xmlrpcDateTime;
626 global $xmlrpcBase64;
628 // get the xmlrpc type of value.
629 $type = xmlrpc_get_type($php_val);
630 $xmlrpc_val = new xmlrpcval;
634 case "vector": //unused
636 foreach($php_val as $v) {
637 $arr[] = php_to_val($v);
639 $xmlrpc_val->addArray($arr);
641 case "object": //unused
643 foreach($php_val as $k => $v) {
644 $arr[$k] = php_to_val($v);
646 $xmlrpc_val->addStruct($arr);
648 case "integer": //unused
650 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
653 $xmlrpc_val->addScalar($php_val, $xmlprcBoolean);
656 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
659 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
662 $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcDateTime);
665 $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcBase64);