| 1 |
lars |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
|
|
|
4 |
|
|
|
5 |
// LICENSE AGREEMENT. If folded, press za here to unfold and read license {{{
|
|
|
6 |
|
|
|
7 |
/**
|
|
|
8 |
* +-----------------------------------------------------------------------------+
|
|
|
9 |
* | Copyright (c) 2004-2006 Sergio Goncalves Carvalho |
|
|
|
10 |
* +-----------------------------------------------------------------------------+
|
|
|
11 |
* | This file is part of XML_RPC2. |
|
|
|
12 |
* | |
|
|
|
13 |
* | XML_RPC2 is free software; you can redistribute it and/or modify |
|
|
|
14 |
* | it under the terms of the GNU Lesser General Public License as published by |
|
|
|
15 |
* | the Free Software Foundation; either version 2.1 of the License, or |
|
|
|
16 |
* | (at your option) any later version. |
|
|
|
17 |
* | |
|
|
|
18 |
* | XML_RPC2 is distributed in the hope that it will be useful, |
|
|
|
19 |
* | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
20 |
* | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
21 |
* | GNU Lesser General Public License for more details. |
|
|
|
22 |
* | |
|
|
|
23 |
* | You should have received a copy of the GNU Lesser General Public License |
|
|
|
24 |
* | along with XML_RPC2; if not, write to the Free Software |
|
|
|
25 |
* | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
|
|
|
26 |
* | 02111-1307 USA |
|
|
|
27 |
* +-----------------------------------------------------------------------------+
|
|
|
28 |
* | Author: Sergio Carvalho <sergio.carvalho@portugalmail.com> |
|
|
|
29 |
* +-----------------------------------------------------------------------------+
|
|
|
30 |
*
|
|
|
31 |
* @category XML
|
|
|
32 |
* @package XML_RPC2
|
|
|
33 |
* @author Sergio Carvalho <sergio.carvalho@portugalmail.com>
|
|
|
34 |
* @copyright 2004-2005 Sergio Carvalho
|
|
|
35 |
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
|
|
|
36 |
* @version CVS: $Id: Value.php 308633 2011-02-24 18:54:23Z sergiosgc $
|
|
|
37 |
* @link http://pear.php.net/package/XML_RPC2
|
|
|
38 |
*/
|
|
|
39 |
|
|
|
40 |
// }}}
|
|
|
41 |
|
|
|
42 |
// dependencies {{{
|
|
|
43 |
require_once 'XML/RPC2/Exception.php';
|
|
|
44 |
require_once 'XML/RPC2/Value.php';
|
|
|
45 |
// }}}
|
|
|
46 |
|
|
|
47 |
/**
|
|
|
48 |
* XML_RPC value abstract class. All XML_RPC value classes inherit from XML_RPC2_Value
|
|
|
49 |
*
|
|
|
50 |
* @category XML
|
|
|
51 |
* @package XML_RPC2
|
|
|
52 |
* @author Sergio Carvalho <sergio.carvalho@portugalmail.com>
|
|
|
53 |
* @copyright 2004-2005 Sergio Carvalho
|
|
|
54 |
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
|
|
|
55 |
* @link http://pear.php.net/package/XML_RPC2
|
|
|
56 |
*/
|
|
|
57 |
abstract class XML_RPC2_Backend_Php_Value extends XML_RPC2_Value
|
|
|
58 |
{
|
|
|
59 |
// {{{ properties
|
|
|
60 |
|
|
|
61 |
/**
|
|
|
62 |
* native value
|
|
|
63 |
*
|
|
|
64 |
* @var mixed
|
|
|
65 |
*/
|
|
|
66 |
private $_nativeValue = null;
|
|
|
67 |
|
|
|
68 |
// }}}
|
|
|
69 |
// {{{ getNativeValue()
|
|
|
70 |
|
|
|
71 |
/**
|
|
|
72 |
* nativeValue property getter
|
|
|
73 |
*
|
|
|
74 |
* @return mixed The current nativeValue
|
|
|
75 |
*/
|
|
|
76 |
public function getNativeValue()
|
|
|
77 |
{
|
|
|
78 |
return $this->_nativeValue;
|
|
|
79 |
}
|
|
|
80 |
|
|
|
81 |
// }}}
|
|
|
82 |
// {{{ setNativeValue()
|
|
|
83 |
|
|
|
84 |
/**
|
|
|
85 |
* nativeValue setter
|
|
|
86 |
*
|
|
|
87 |
* @param mixed $value
|
|
|
88 |
*/
|
|
|
89 |
protected function setNativeValue($value)
|
|
|
90 |
{
|
|
|
91 |
$this->_nativeValue = $value;
|
|
|
92 |
}
|
|
|
93 |
|
|
|
94 |
// }}}
|
|
|
95 |
// {{{ createFromNative()
|
|
|
96 |
|
|
|
97 |
/**
|
|
|
98 |
* Choose a XML_RPC2_Value subclass appropriate for the
|
|
|
99 |
* given value and create it.
|
|
|
100 |
*
|
|
|
101 |
* This method tries to find the most adequate XML-RPC datatype to hold
|
|
|
102 |
* a given PHP native type. Note that distinguishing some datatypes may be
|
|
|
103 |
* difficult:
|
|
|
104 |
* - Timestamps are represented by PHP integers, so an XML_RPC2_Value_Datetime is never returned
|
|
|
105 |
* - Indexed arrays and associative arrays are the same native PHP type. In this case:
|
|
|
106 |
* a) The array's indexes start at 0 or 1 and increase monotonically with step 1, or
|
|
|
107 |
* b) they do not
|
|
|
108 |
* in the first case, an XML_RPC2_Value_Array is returned. In the second, a XML_RPC2_Value_Struct is returned.
|
|
|
109 |
* - PHP Objects are serialized and represented in an XML_RPC2_Value_Base64
|
|
|
110 |
* - Integers fitting in a 32bit integer are encoded as regular xml-rpc integers
|
|
|
111 |
* - Integers larger than 32bit are encoded using the i8 xml-rpc extension
|
|
|
112 |
*
|
|
|
113 |
* Whenever native object automatic detection proves inaccurate, use XML_RPC2_Value::createFromNative providing
|
|
|
114 |
* a valid explicit type as second argument
|
|
|
115 |
*
|
|
|
116 |
* the appropriate XML_RPC2_Value child class instead.
|
|
|
117 |
*
|
|
|
118 |
* @param mixed The native value
|
|
|
119 |
* @param string The xml-rpc target encoding type, as per the xmlrpc spec (optional)
|
|
|
120 |
* @throws XML_RPC2_InvalidTypeEncodeException When the native value has a type that can't be translated to XML_RPC
|
|
|
121 |
* @return A new XML_RPC2_Value instance
|
|
|
122 |
* @see XML_RPC_Client::__call
|
|
|
123 |
* @see XML_RPC_Server
|
|
|
124 |
*/
|
|
|
125 |
public static function createFromNative($nativeValue, $explicitType = null)
|
|
|
126 |
{
|
|
|
127 |
if (is_null($explicitType)) {
|
|
|
128 |
switch (gettype($nativeValue)) {
|
|
|
129 |
case 'boolean':
|
|
|
130 |
$explicitType = 'boolean';
|
|
|
131 |
break;
|
|
|
132 |
case 'integer':
|
|
|
133 |
$explicitType = 'int';
|
|
|
134 |
break;
|
|
|
135 |
case 'double':
|
|
|
136 |
$explicitType = 'double';
|
|
|
137 |
break;
|
|
|
138 |
case 'string':
|
|
|
139 |
$explicitType = 'string';
|
|
|
140 |
break;
|
|
|
141 |
case 'array':
|
|
|
142 |
$explicitType = 'array';
|
|
|
143 |
$keys = array_keys($nativeValue);
|
|
|
144 |
if (count($keys) > 0) {
|
|
|
145 |
if ($keys[0] !== 0 && ($keys[0] !== 1)) $explicitType = 'struct';
|
|
|
146 |
$i=0;
|
|
|
147 |
do {
|
|
|
148 |
$previous = $keys[$i];
|
|
|
149 |
$i++;
|
|
|
150 |
if (array_key_exists($i, $keys) && ($keys[$i] !== $keys[$i - 1] + 1)) $explicitType = 'struct';
|
|
|
151 |
} while (array_key_exists($i, $keys) && $explicitType == 'array');
|
|
|
152 |
}
|
|
|
153 |
break;
|
|
|
154 |
case 'object':
|
|
|
155 |
if ((strtolower(get_class($nativeValue)) == 'stdclass') && (isset($nativeValue->xmlrpc_type))) {
|
|
|
156 |
// In this case, we have a "stdclass native value" (emulate xmlrpcext)
|
|
|
157 |
// the type 'base64' or 'datetime' is given by xmlrpc_type public property
|
|
|
158 |
$explicitType = $nativeValue->xmlrpc_type;
|
|
|
159 |
} else {
|
|
|
160 |
$nativeValue = serialize($nativeValue);
|
|
|
161 |
$explicitType = 'base64';
|
|
|
162 |
}
|
|
|
163 |
break;
|
|
|
164 |
case 'resource':
|
|
|
165 |
case 'NULL':
|
|
|
166 |
case 'unknown type':
|
|
|
167 |
throw new XML_RPC2_InvalidTypeEncodeException(sprintf('Impossible to encode value \'%s\' from type \'%s\'. No analogous type in XML_RPC.',
|
|
|
168 |
(string) $nativeValue,
|
|
|
169 |
gettype($nativeValue)));
|
|
|
170 |
default:
|
|
|
171 |
throw new XML_RPC2_InvalidTypeEncodeException(sprintf('Unexpected PHP native type returned by gettype: \'%s\', for value \'%s\'',
|
|
|
172 |
gettype($nativeValue),
|
|
|
173 |
(string) $nativeValue));
|
|
|
174 |
}
|
|
|
175 |
}
|
|
|
176 |
$explicitType = ucfirst(strtolower($explicitType));
|
|
|
177 |
switch ($explicitType) {
|
|
|
178 |
case 'I8':
|
|
|
179 |
require_once 'XML/RPC2/Backend/Php/Value/Scalar.php';
|
|
|
180 |
return XML_RPC2_Backend_Php_Value_Scalar::createFromNative($nativeValue, 'Integer64');
|
|
|
181 |
break;
|
|
|
182 |
case 'I4':
|
|
|
183 |
case 'Int':
|
|
|
184 |
case 'Boolean':
|
|
|
185 |
case 'Double':
|
|
|
186 |
case 'String':
|
|
|
187 |
case 'Nil':
|
|
|
188 |
require_once 'XML/RPC2/Backend/Php/Value/Scalar.php';
|
|
|
189 |
return XML_RPC2_Backend_Php_Value_Scalar::createFromNative($nativeValue);
|
|
|
190 |
break;
|
|
|
191 |
case 'Datetime.iso8601':
|
|
|
192 |
case 'Datetime':
|
|
|
193 |
require_once 'XML/RPC2/Backend/Php/Value/Datetime.php';
|
|
|
194 |
return new XML_RPC2_Backend_Php_Value_Datetime($nativeValue);
|
|
|
195 |
break;
|
|
|
196 |
case 'Base64':
|
|
|
197 |
require_once 'XML/RPC2/Backend/Php/Value/Base64.php';
|
|
|
198 |
return new XML_RPC2_Backend_Php_Value_Base64($nativeValue);
|
|
|
199 |
break;
|
|
|
200 |
case 'Array':
|
|
|
201 |
require_once 'XML/RPC2/Backend/Php/Value/Array.php';
|
|
|
202 |
return new XML_RPC2_Backend_Php_Value_Array($nativeValue);
|
|
|
203 |
break;
|
|
|
204 |
case 'Struct':
|
|
|
205 |
require_once 'XML/RPC2/Backend/Php/Value/Struct.php';
|
|
|
206 |
return new XML_RPC2_Backend_Php_Value_Struct($nativeValue);
|
|
|
207 |
break;
|
|
|
208 |
default:
|
|
|
209 |
throw new XML_RPC2_InvalidTypeEncodeException(sprintf('Unexpected explicit encoding type \'%s\'', $explicitType));
|
|
|
210 |
}
|
|
|
211 |
}
|
|
|
212 |
|
|
|
213 |
// }}}
|
|
|
214 |
// {{{ createFromDecode()
|
|
|
215 |
|
|
|
216 |
/**
|
|
|
217 |
* Decode an encoded value and build the applicable XML_RPC2_Value subclass
|
|
|
218 |
*
|
|
|
219 |
* @param SimpleXMLElement The encoded XML-RPC value
|
|
|
220 |
* @return mixed the corresponding XML_RPC2_Value object
|
|
|
221 |
*/
|
|
|
222 |
public static function createFromDecode($simpleXML)
|
|
|
223 |
{
|
|
|
224 |
// TODO Remove reparsing of XML fragment, when SimpleXML proves more solid. Currently it segfaults when
|
|
|
225 |
// xpath is used both in an element and in one of its children
|
|
|
226 |
$simpleXML = simplexml_load_string($simpleXML->asXML());
|
|
|
227 |
|
|
|
228 |
$valueType = $simpleXML->xpath('./*');
|
|
|
229 |
if (count($valueType) == 1) { // Usually we must check the node name
|
|
|
230 |
$nodename = dom_import_simplexml($valueType[0])->nodeName;
|
|
|
231 |
switch ($nodename) {
|
|
|
232 |
case 'i8':
|
|
|
233 |
$nativeType = 'Integer64';
|
|
|
234 |
break;
|
|
|
235 |
case 'i4':
|
|
|
236 |
case 'int':
|
|
|
237 |
$nativeType = 'Integer';
|
|
|
238 |
break;
|
|
|
239 |
case 'boolean':
|
|
|
240 |
$nativeType = 'Boolean';
|
|
|
241 |
break;
|
|
|
242 |
case 'double':
|
|
|
243 |
$nativeType = 'Double';
|
|
|
244 |
break;
|
|
|
245 |
case 'string':
|
|
|
246 |
$nativeType = 'String';
|
|
|
247 |
break;
|
|
|
248 |
case 'dateTime.iso8601':
|
|
|
249 |
$nativeType = 'Datetime';
|
|
|
250 |
break;
|
|
|
251 |
case 'base64':
|
|
|
252 |
$nativeType = 'Base64';
|
|
|
253 |
break;
|
|
|
254 |
case 'array':
|
|
|
255 |
$nativeType = 'Array';
|
|
|
256 |
break;
|
|
|
257 |
case 'struct':
|
|
|
258 |
$nativeType = 'Struct';
|
|
|
259 |
break;
|
|
|
260 |
case 'nil':
|
|
|
261 |
$nativeType = 'Nil';
|
|
|
262 |
break;
|
|
|
263 |
default:
|
|
|
264 |
throw new XML_RPC2_DecodeException(sprintf('Unable to decode XML-RPC value. Value type is not recognized \'%s\'', $nodename));
|
|
|
265 |
}
|
|
|
266 |
} elseif (count($valueType) == 0) { // Default type is string
|
|
|
267 |
$nodename = null;
|
|
|
268 |
$nativeType = 'String';
|
|
|
269 |
} else {
|
|
|
270 |
throw new XML_RPC2_DecodeException(sprintf('Unable to decode XML-RPC value. Value presented %s type nodes: %s.', count($valueType), $simpleXML->asXML()));
|
|
|
271 |
}
|
|
|
272 |
require_once(sprintf('XML/RPC2/Backend/Php/Value/%s.php', $nativeType));
|
|
|
273 |
$nativeType = 'XML_RPC2_Backend_Php_Value_' . $nativeType;
|
|
|
274 |
return self::createFromNative(@call_user_func(array($nativeType, 'decode'), $simpleXML), $nodename);
|
|
|
275 |
}
|
|
|
276 |
|
|
|
277 |
// }}}
|
|
|
278 |
// {{{ encode()
|
|
|
279 |
|
|
|
280 |
/**
|
|
|
281 |
* Encode the instance into XML, for transport
|
|
|
282 |
*
|
|
|
283 |
* @return string The encoded XML-RPC value,
|
|
|
284 |
*/
|
|
|
285 |
// Declaration commented because of: http://pear.php.net/bugs/bug.php?id=8499
|
|
|
286 |
// public abstract function encode();
|
|
|
287 |
|
|
|
288 |
// }}}
|
|
|
289 |
// {{{ decode()
|
|
|
290 |
|
|
|
291 |
/**
|
|
|
292 |
* decode. Decode transport XML and set the instance value accordingly
|
|
|
293 |
*
|
|
|
294 |
* @param mixed The encoded XML-RPC value,
|
|
|
295 |
*/
|
|
|
296 |
// Declaration commented because of: http://pear.php.net/bugs/bug.php?id=8499
|
|
|
297 |
// public static abstract function decode($xml);
|
|
|
298 |
|
|
|
299 |
// }}}
|
|
|
300 |
}
|
|
|
301 |
|
|
|
302 |
?>
|