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 // $Id: xmlrpc_emu.inc,v 1.2 2007-01-21 23:28:51 rurban Exp $
42 // Copyright (c) 1999,2000,2001 Edd Dumbill.
43 // All rights reserved.
45 // Redistribution and use in source and binary forms, with or without
46 // modification, are permitted provided that the following conditions
49 // * Redistributions of source code must retain the above copyright
50 // notice, this list of conditions and the following disclaimer.
52 // * Redistributions in binary form must reproduce the above
53 // copyright notice, this list of conditions and the following
54 // disclaimer in the documentation and/or other materials provided
55 // with the distribution.
57 // * Neither the name of the "PHP for XML-RPC" nor the names of its
58 // contributors may be used to endorse or promote products derived
59 // from this software without specific prior written permission.
61 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
62 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
63 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
64 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
65 // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
66 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
67 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
68 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
70 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
71 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
72 // OF THE POSSIBILITY OF SUCH DAMAGE.
74 // Requires: transport.php
76 // change path as necessary. or set before including this file.
77 if(!$xmlrpc_util_path) {
78 $xmlrpc_util_path = "./utils/";
80 include_once("$xmlrpc_util_path/utils.php");
82 // xmlrpc types. seems like these should be defines instead of globals.
85 $xmlrpcBoolean="boolean";
86 $xmlrpcDouble="double";
87 $xmlrpcString="string";
88 $xmlrpcDateTime="dateTime.iso8601";
89 $xmlrpcBase64="base64";
91 $xmlrpcStruct="struct";
93 // map local types to xmlrpc-epi-php types.
94 $epiTypeMap = array($xmlrpcI4 => "int",
96 $xmlrpcBoolean => "boolean",
97 $xmlrpcString => "string",
98 $xmlrpcDouble => "double",
99 $xmlrpcDateTime => "datetime",
100 $xmlrpcBase64 => "base64",
101 $xmlrpcArray => "array",
102 $xmlrpcStruct => "struct");
104 // map local types to php types
105 $phpTypeMap = array($xmlrpcI4 => "integer",
106 $xmlrpcInt => "integer",
107 $xmlrpcBoolean => "boolean",
108 $xmlrpcString => "string",
109 $xmlrpcDouble => "double",
110 $xmlrpcDateTime => "string",
111 $xmlrpcBase64 => "string",
112 $xmlrpcArray => "array",
113 $xmlrpcStruct => "array");
115 $xmlrpcTypes=array($xmlrpcI4 => 1,
120 $xmlrpcDateTime => 1,
125 // some error definitions
126 $xmlrpcerr["unknown_method"]=1;
127 $xmlrpcstr["unknown_method"]="Unknown method";
128 $xmlrpcerr["invalid_return"]=2;
129 $xmlrpcstr["invalid_return"]="Invalid return payload: enabling debugging to examine incoming payload";
130 $xmlrpcerr["incorrect_params"]=3;
131 $xmlrpcstr["incorrect_params"]="Incorrect parameters passed to method";
132 $xmlrpcerr["introspect_unknown"]=4;
133 $xmlrpcstr["introspect_unknown"]="Can't introspect: method unknown";
134 $xmlrpcerr["http_error"]=5;
135 $xmlrpcstr["http_error"]="Didn't receive 200 OK from remote server.";
136 $xmlrpcerr["no_data"]=6;
137 $xmlrpcstr["no_data"]="No data received from server.";
138 $xmlrpcerr["no_ssl"]=7;
139 $xmlrpcstr["no_ssl"]="No SSL support compiled in.";
140 $xmlrpcerr["curl_fail"]=8;
141 $xmlrpcstr["curl_fail"]="CURL error";
143 $xmlrpc_defencoding="UTF-8";
145 $xmlrpcName="XML-RPC for PHP (xmlrpc-epi wrapper version)";
146 $xmlrpcVersion="1.0";
148 // let user errors start at 800
152 /************************************************
153 * xmlrpc client class. basically a wrapper for *
155 ************************************************/
156 class xmlrpc_client {
167 function xmlrpc_client($path, $server, $port=80) {
168 $this->port=$port; $this->server=$server; $this->path=$path;
171 // public. for debugging info.
172 function setDebug($in) {
180 // public. for http authentication.
181 function setCredentials($u, $p) {
186 // public. sent request to server.
187 function send($msg, $timeout=0, $pause=0, $secure=false) {
188 // where msg is an xmlrpcmsg
189 $msg->debug=$this->debug;
196 return $this->sendPayloadHTTP10($msg, $this->server, $this->port, $timeout, $this->username, $this->password);
200 // private. performs http post request
201 function sendPayloadHTTP10($msg, $server, $port, $timeout=0, $username="", $password="", $secure=false) {
202 // Only create the payload if it was not created previously
203 if (empty($msg->payload)) {
204 $msg->createPayload();
207 $response_buf = xu_query_http_post($msg->payload, $server, $this->path, $port,
208 $this->debug, $timeout, $username, $password, $secure);
210 $resp=$msg->parseResponse($response_buf);
215 } // end class xmlrpc_client
217 /******************************************
218 * a class to represent an xmlrpc response *
219 ******************************************/
227 function xmlrpcresp($val, $fcode=0, $fstr="") {
236 // public. get methods
237 function faultCode() { return $this->fn;}
238 function faultString() { return $this->fs;}
239 function value() { return $this->xv;}
241 // public. serialize self as xml string.
242 function serialize() {
245 $result = xmlrpc_encode_request(null, xu_fault_code($this->fn, $this->fs));
247 $php_vals = val_to_php($this->xv);
249 // null for methodname indicates response type.
250 $result = xmlrpc_encode_request(null, $php_vals);
257 /*****************************************
258 * a class to represent an xmlrpc message *
259 *****************************************/
267 function xmlrpcmsg($meth, $pars=0) {
268 $this->methodname=$meth;
269 if (is_array($pars) && sizeof($pars)>0) {
270 for ($i=0; $i<sizeof($pars); $i++)
271 $this->addParam($pars[$i]);
275 // unused. xmlrpc-epi does this automagically
276 function xml_header() {
277 return "xml_header not supported";
280 // unused. not necessary
281 function xml_footer() {
282 return "xml_footer not supported";
285 // private. performs the actual message serialization.
286 function createPayload() {
287 $php_params_val = array();
288 foreach($this->params as $param) {
289 $php_params_val[] = val_to_php($param);
291 $this->payload = xmlrpc_encode_request($this->methodname, $php_params_val);
294 // public. returns name of method
295 function method($meth="") {
297 $this->methodname=$meth;
299 return $this->methodname;
302 // public. serialization message as xml
303 function serialize() {
304 $this->createPayload();
305 return $this->payload;
308 // public. add/retrieve/count message params
309 function addParam($par) { $this->params[]=$par;}
310 function getParam($i) { return $this->params[$i];}
311 function getNumParams() { return sizeof($this->params);}
313 // public. in case we are given a file handle
314 function parseResponseFile($fp) {
317 while ($data=fread($fp, 32768)) {
320 return $this->parseResponse($ipd);
323 // public. parse xml, return as xmlrpcresp.
324 function parseResponse($data="") {
325 $php_val = xmlrpc_decode($data);
327 /* check for fault */
328 if (is_array($php_val) && isset($php_val[0][faultCode])) {
329 $fc = $php_val[0][faultCode];
330 $fs = $php_val[0][faultString];
332 $rpc_val = php_to_val($php_val);
336 return new xmlrpcresp($rpc_val, $fc, $fs);
341 /***************************************
342 * a class to represent an xmlrpc value *
343 ***************************************/
349 function xmlrpcval($val=-1, $type="") {
353 if ($val!=-1 || $type!="") {
354 if ($type=="") $type="string";
355 if ($xmlrpcTypes[$type]==1) {
356 $this->addScalar($val,$type);
357 } else if ($xmlrpcTypes[$type]==2)
358 $this->addArray($val);
359 else if ($xmlrpcTypes[$type]==3)
360 $this->addStruct($val);
364 // public. add a php scalar value.
365 function addScalar($val, $type="string") {
366 global $xmlrpcTypes, $xmlrpcBoolean;
368 if ($this->mytype==1) {
369 echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";
372 $typeof=$xmlrpcTypes[$type];
374 echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";
378 if ($type==$xmlrpcBoolean) {
379 if (strcasecmp($val,"true")==0 || $val==1 || $val==true) {
386 if ($this->mytype==2) {
387 // we're adding to an array here
388 $ar=$this->me["array"];
389 $ar[]=new xmlrpcval($val, $type);
390 $this->me["array"]=$ar;
392 // a scalar, so set the value and remember we're scalar
393 $this->me[$type]=$val;
394 $this->mytype=$typeof;
399 // public. add a php array
400 function addArray($vals) {
402 if ($this->mytype!=0) {
403 echo "<B>xmlrpcval</B>: already initialized as a [" .
404 $this->kindOf() . "]<BR>";
407 $this->mytype=$xmlrpcTypes["array"];
408 $this->me["array"]=$vals;
412 // public. add a php keyed array as a struct.
413 function addStruct($vals) {
415 if ($this->mytype!=0) {
416 echo "<B>xmlrpcval</B>: already initialized as a [" .
417 $this->kindOf() . "]<BR>";
420 $this->mytype=$xmlrpcTypes["struct"];
421 $this->me["struct"]=$vals;
425 // public. write myself out as html.
427 foreach($ar as $key => $val) {
428 echo "$key => $val<br>";
429 if ($key == 'array') {
430 foreach($val as $key2 => $val2) {
431 echo "-- $key2 => $val2";
437 // public. kind of value.
438 // (not 1 to 1 mapping with xmlrpc types or php types)
440 switch ($this->mytype) {
456 function serializedata($typ, $val) {
457 return "serializedata not supported";
460 // public. serialize self as xml.
461 function serialize() {
462 return $this->serializeval($this);
465 // public. serialize any xmlrpcval object as xml.
466 function serializeval($o) {
467 $php_val = val_to_php($o);
468 $result_xml = xmlrpc_encode($php_val);
473 // public. get struct members.
474 function structmem($m) {
475 $nv=$this->me["struct"][$m];
479 // public. reset struct to first item.
480 function structreset() {
481 reset($this->me["struct"]);
484 // public. get key/val pair of next struct item.
485 function structeach() {
486 return each($this->me["struct"]);
489 // public. get php type scalar value.
490 function scalarval() {
491 global $xmlrpcBoolean, $xmlrpcBase64;
493 list($a,$b)=each($this->me);
497 // public. get xmlrpc type of value.
498 function scalartyp() {
499 global $xmlrpcI4, $xmlrpcInt;
501 list($a,$b)=each($this->me);
507 // public. get array member.
508 function arraymem($m) {
509 $nv=$this->me["array"][$m];
513 // public. get array size
514 function arraysize() {
516 list($a,$b)=each($this->me);
523 /*****************************************************************
524 * These stubs need to be implemented in the C extension library. *
525 * When they are, these calls will be commented out. -danda *
526 *****************************************************************/
528 function iso8601_encode($timet, $utc=0) {
529 // return an ISO8601 encoded string
530 // really, timezones ought to be supported
531 // but the XML-RPC spec says:
533 // "Don't assume a timezone. It should be specified by the server in its
534 // documentation what assumptions it makes about timezones."
536 // these routines always assume localtime unless
537 // $utc is set to 1, in which case UTC is assumed
538 // and an adjustment for locale is made when encoding
540 $t=strftime("%Y%m%dT%H:%M:%S", $timet);
542 if (function_exists("gmstrftime"))
543 // gmstrftime doesn't exist in some versions
545 $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
547 $t=strftime("%Y%m%dT%H:%M:%S", $timet-date("Z"));
553 function iso8601_decode($idate, $utc=0) {
554 // return a timet in the localtime, or UTC
556 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",
559 $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
561 $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
567 /****************************************************************
568 * xmlrpc_decode takes a message in PHP xmlrpc object format and *
569 * tranlates it into native PHP types. *
570 ****************************************************************/
571 function val_to_php($xmlrpc_val) {
575 $kind = $xmlrpc_val->kindOf();
577 if ($kind == "scalar") {
578 $type = $xmlrpc_val->scalartyp();
579 $php_val = $xmlrpc_val->scalarval();
580 $php_type = $phpTypeMap[$type];
582 // value is stored in object as a string. we want
584 settype($php_val, $php_type);
586 // magic to let xmlprc-epi engine know about base64 and datetime types.
587 $epi_type = $epiTypeMap[$type];
589 xmlrpc_set_type($php_val, $epi_type);
590 // php_val may now be an object, if epi_type = base64 or datetime.
595 // generate php indexed array. recurse for sub-values.
596 else if ($kind == "array") {
597 $size = $xmlrpc_val->arraysize();
600 for ($i = 0; $i < $size; $i++) {
601 $arr[] = val_to_php($xmlrpc_val->arraymem($i));
605 // generate php keyed array. recurse for sub-values.
606 else if ($kind == "struct") {
607 $xmlrpc_val->structreset();
610 while (list($key,$value)=$xmlrpc_val->structeach()) {
611 $arr[$key] = val_to_php($value);
617 /****************************************************************
618 * php_to_val takes native php types and encodes them into *
619 * xmlrpc PHP object format. *
620 ****************************************************************/
621 function php_to_val($php_val) {
623 global $xmlrpcDouble;
624 global $xmlrpcString;
626 global $xmlrpcStruct;
627 global $xmlrpcBoolean;
628 global $xmlrpcDateTime;
629 global $xmlrpcBase64;
631 // get the xmlrpc type of value.
632 $type = xmlrpc_get_type($php_val);
633 $xmlrpc_val = new xmlrpcval;
637 case "vector": //unused
639 foreach($php_val as $v) {
640 $arr[] = php_to_val($v);
642 $xmlrpc_val->addArray($arr);
644 case "object": //unused
646 foreach($php_val as $k => $v) {
647 $arr[$k] = php_to_val($v);
649 $xmlrpc_val->addStruct($arr);
651 case "integer": //unused
653 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
656 $xmlrpc_val->addScalar($php_val, $xmlprcBoolean);
659 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
662 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
665 $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcDateTime);
668 $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcBase64);