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";
87 $xmlrpcArray = "array";
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
146 $xmlrpcerruser = 800;
149 /************************************************
150 * xmlrpc client class. basically a wrapper for *
152 ************************************************/
165 function xmlrpc_client($path, $server, $port = 80)
168 $this->server = $server;
172 // public. for debugging info.
173 function setDebug($in)
182 // public. for http authentication.
183 function setCredentials($u, $p)
185 $this->username = $u;
186 $this->password = $p;
189 // public. sent request to server.
190 function send($msg, $timeout = 0, $pause = 0, $secure = false)
192 // where msg is an xmlrpcmsg
193 $msg->debug = $this->debug;
200 return $this->sendPayloadHTTP10($msg, $this->server, $this->port, $timeout, $this->username, $this->password);
204 // private. performs http post request
205 function sendPayloadHTTP10($msg, $server, $port, $timeout = 0, $username = "", $password = "", $secure = false)
207 // Only create the payload if it was not created previously
208 if (empty($msg->payload)) {
209 $msg->createPayload();
212 $response_buf = xu_query_http_post($msg->payload, $server, $this->path, $port,
213 $this->debug, $timeout, $username, $password, $secure);
215 $resp = $msg->parseResponse($response_buf);
220 } // end class xmlrpc_client
222 /******************************************
223 * a class to represent an xmlrpc response *
224 ******************************************/
233 function xmlrpcresp($val, $fcode = 0, $fstr = "")
243 // public. get methods
249 function faultString()
259 // public. serialize self as xml string.
264 $result = xmlrpc_encode_request(null, xu_fault_code($this->fn, $this->fs));
266 $php_vals = val_to_php($this->xv);
268 // null for methodname indicates response type.
269 $result = xmlrpc_encode_request(null, $php_vals);
276 /*****************************************
277 * a class to represent an xmlrpc message *
278 *****************************************/
283 var $params = array();
287 function xmlrpcmsg($meth, $pars = 0)
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]);
296 // unused. xmlrpc-epi does this automagically
297 function xml_header()
299 return "xml_header not supported";
302 // unused. not necessary
303 function xml_footer()
305 return "xml_footer not supported";
308 // private. performs the actual message serialization.
309 function createPayload()
311 $php_params_val = array();
312 foreach ($this->params as $param) {
313 $php_params_val[] = val_to_php($param);
315 $this->payload = xmlrpc_encode_request($this->methodname, $php_params_val);
318 // public. returns name of method
319 function method($meth = "")
322 $this->methodname = $meth;
324 return $this->methodname;
327 // public. serialization message as xml
330 $this->createPayload();
331 return $this->payload;
334 // public. add/retrieve/count message params
335 function addParam($par)
337 $this->params[] = $par;
340 function getParam($i)
342 return $this->params[$i];
345 function getNumParams()
347 return sizeof($this->params);
350 // public. in case we are given a file handle
351 function parseResponseFile($fp)
355 while ($data = fread($fp, 32768)) {
358 return $this->parseResponse($ipd);
361 // public. parse xml, return as xmlrpcresp.
362 function parseResponse($data = "")
364 $php_val = xmlrpc_decode($data);
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];
371 $rpc_val = php_to_val($php_val);
375 return new xmlrpcresp($rpc_val, $fc, $fs);
380 /***************************************
381 * a class to represent an xmlrpc value *
382 ***************************************/
389 function xmlrpcval($val = -1, $type = "")
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);
405 // public. add a php scalar value.
406 function addScalar($val, $type = "string")
408 global $xmlrpcTypes, $xmlrpcBoolean;
410 if ($this->mytype == 1) {
411 echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";
414 $typeof = $xmlrpcTypes[$type];
416 echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";
420 if ($type == $xmlrpcBoolean) {
421 if (strcasecmp($val, "true") == 0 || $val == 1 || $val == true) {
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;
434 // a scalar, so set the value and remember we're scalar
435 $this->me[$type] = $val;
436 $this->mytype = $typeof;
441 // public. add a php array
442 function addArray($vals)
445 if ($this->mytype != 0) {
446 echo "<B>xmlrpcval</B>: already initialized as a [" .
447 $this->kindOf() . "]<BR>";
450 $this->mytype = $xmlrpcTypes["array"];
451 $this->me["array"] = $vals;
455 // public. add a php keyed array as a struct.
456 function addStruct($vals)
459 if ($this->mytype != 0) {
460 echo "<B>xmlrpcval</B>: already initialized as a [" .
461 $this->kindOf() . "]<BR>";
464 $this->mytype = $xmlrpcTypes["struct"];
465 $this->me["struct"] = $vals;
469 // public. write myself out as html.
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";
482 // public. kind of value.
483 // (not 1 to 1 mapping with xmlrpc types or php types)
486 switch ($this->mytype) {
502 function serializedata($typ, $val)
504 return "serializedata not supported";
507 // public. serialize self as xml.
510 return $this->serializeval($this);
513 // public. serialize any xmlrpcval object as xml.
514 function serializeval($o)
516 $php_val = val_to_php($o);
517 $result_xml = xmlrpc_encode($php_val);
522 // public. get struct members.
523 function structmem($m)
525 $nv = $this->me["struct"][$m];
529 // public. reset struct to first item.
530 function structreset()
532 reset($this->me["struct"]);
535 // public. get key/val pair of next struct item.
536 function structeach()
538 return each($this->me["struct"]);
541 // public. get php type scalar value.
544 global $xmlrpcBoolean, $xmlrpcBase64;
546 list($a, $b) = each($this->me);
550 // public. get xmlrpc type of value.
553 global $xmlrpcI4, $xmlrpcInt;
555 list($a, $b) = each($this->me);
561 // public. get array member.
562 function arraymem($m)
564 $nv = $this->me["array"][$m];
568 // public. get array size
572 list($a, $b) = each($this->me);
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 *****************************************************************/
584 function iso8601_encode($timet, $utc = 0)
586 // return an ISO8601 encoded string
587 // really, timezones ought to be supported
588 // but the XML-RPC spec says:
590 // "Don't assume a timezone. It should be specified by the server in its
591 // documentation what assumptions it makes about timezones."
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
597 $t = strftime("%Y%m%dT%H:%M:%S", $timet);
599 if (function_exists("gmstrftime"))
600 // gmstrftime doesn't exist in some versions
602 $t = gmstrftime("%Y%m%dT%H:%M:%S", $timet);
604 $t = strftime("%Y%m%dT%H:%M:%S", $timet - date("Z"));
610 function iso8601_decode($idate, $utc = 0)
612 // return a timet in the localtime, or UTC
614 if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",
618 $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
620 $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
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)
635 $kind = $xmlrpc_val->kindOf();
637 if ($kind == "scalar") {
638 $type = $xmlrpc_val->scalartyp();
639 $php_val = $xmlrpc_val->scalarval();
640 $php_type = $phpTypeMap[$type];
642 // value is stored in object as a string. we want
644 settype($php_val, $php_type);
646 // magic to let xmlprc-epi engine know about base64 and datetime types.
647 $epi_type = $epiTypeMap[$type];
649 xmlrpc_set_type($php_val, $epi_type);
650 // php_val may now be an object, if epi_type = base64 or datetime.
654 } // generate php indexed array. recurse for sub-values.
655 else if ($kind == "array") {
656 $size = $xmlrpc_val->arraysize();
659 for ($i = 0; $i < $size; $i++) {
660 $arr[] = val_to_php($xmlrpc_val->arraymem($i));
663 } // generate php keyed array. recurse for sub-values.
664 else if ($kind == "struct") {
665 $xmlrpc_val->structreset();
668 while (list($key, $value) = $xmlrpc_val->structeach()) {
669 $arr[$key] = val_to_php($value);
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)
682 global $xmlrpcDouble;
683 global $xmlrpcString;
685 global $xmlrpcStruct;
686 global $xmlrpcBoolean;
687 global $xmlrpcDateTime;
688 global $xmlrpcBase64;
690 // get the xmlrpc type of value.
691 $type = xmlrpc_get_type($php_val);
692 $xmlrpc_val = new xmlrpcval;
696 case "vector": //unused
698 foreach ($php_val as $v) {
699 $arr[] = php_to_val($v);
701 $xmlrpc_val->addArray($arr);
703 case "object": //unused
705 foreach ($php_val as $k => $v) {
706 $arr[$k] = php_to_val($v);
708 $xmlrpc_val->addStruct($arr);
710 case "integer": //unused
712 $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
715 $xmlrpc_val->addScalar($php_val, $xmlprcBoolean);
718 $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
721 $xmlrpc_val->addScalar($php_val, $xmlrpcString);
724 $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcDateTime);
727 $xmlrpc_val->addScalar($php_val->scalar, $xmlrpcBase64);