1 |
efrain |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
namespace PhpXmlRpc;
|
|
|
4 |
|
|
|
5 |
use PhpXmlRpc\Exception\StateErrorException;
|
|
|
6 |
use PhpXmlRpc\Exception\TypeErrorException;
|
|
|
7 |
use PhpXmlRpc\Exception\ValueErrorException;
|
|
|
8 |
use PhpXmlRpc\Traits\CharsetEncoderAware;
|
|
|
9 |
use PhpXmlRpc\Traits\DeprecationLogger;
|
|
|
10 |
|
|
|
11 |
/**
|
|
|
12 |
* This class enables the creation of values for XML-RPC, by encapsulating plain php values.
|
|
|
13 |
*
|
|
|
14 |
* @property Value[]|mixed $me deprecated - public access left in purely for BC. Access via scalarVal()/__construct()
|
|
|
15 |
* @property int $params $mytype - public access left in purely for BC. Access via kindOf()/__construct()
|
|
|
16 |
* @property string|null $_php_class deprecated - public access left in purely for BC.
|
|
|
17 |
*/
|
|
|
18 |
class Value implements \Countable, \IteratorAggregate, \ArrayAccess
|
|
|
19 |
{
|
|
|
20 |
use CharsetEncoderAware;
|
|
|
21 |
use DeprecationLogger;
|
|
|
22 |
|
|
|
23 |
public static $xmlrpcI4 = "i4";
|
|
|
24 |
public static $xmlrpcI8 = "i8";
|
|
|
25 |
public static $xmlrpcInt = "int";
|
|
|
26 |
public static $xmlrpcBoolean = "boolean";
|
|
|
27 |
public static $xmlrpcDouble = "double";
|
|
|
28 |
public static $xmlrpcString = "string";
|
|
|
29 |
public static $xmlrpcDateTime = "dateTime.iso8601";
|
|
|
30 |
public static $xmlrpcBase64 = "base64";
|
|
|
31 |
public static $xmlrpcArray = "array";
|
|
|
32 |
public static $xmlrpcStruct = "struct";
|
|
|
33 |
public static $xmlrpcValue = "undefined";
|
|
|
34 |
public static $xmlrpcNull = "null";
|
|
|
35 |
|
|
|
36 |
public static $xmlrpcTypes = array(
|
|
|
37 |
"i4" => 1,
|
|
|
38 |
"i8" => 1,
|
|
|
39 |
"int" => 1,
|
|
|
40 |
"boolean" => 1,
|
|
|
41 |
"double" => 1,
|
|
|
42 |
"string" => 1,
|
|
|
43 |
"dateTime.iso8601" => 1,
|
|
|
44 |
"base64" => 1,
|
|
|
45 |
"array" => 2,
|
|
|
46 |
"struct" => 3,
|
|
|
47 |
"null" => 1,
|
|
|
48 |
);
|
|
|
49 |
|
|
|
50 |
/** @var Value[]|mixed */
|
|
|
51 |
protected $me = array();
|
|
|
52 |
/**
|
|
|
53 |
* @var int 0 for undef, 1 for scalar, 2 for array, 3 for struct
|
|
|
54 |
*/
|
|
|
55 |
protected $mytype = 0;
|
|
|
56 |
/** @var string|null */
|
|
|
57 |
protected $_php_class = null;
|
|
|
58 |
|
|
|
59 |
/**
|
|
|
60 |
* Build an xml-rpc value.
|
|
|
61 |
*
|
|
|
62 |
* When no value or type is passed in, the value is left uninitialized, and the value can be added later.
|
|
|
63 |
*
|
|
|
64 |
* @param Value[]|mixed $val if passing in an array, all array elements should be PhpXmlRpc\Value themselves
|
|
|
65 |
* @param string $type any valid xml-rpc type name (lowercase): i4, int, boolean, string, double, dateTime.iso8601,
|
|
|
66 |
* base64, array, struct, null.
|
|
|
67 |
* If null, 'string' is assumed.
|
|
|
68 |
* You should refer to http://xmlrpc.com/spec.md for more information on what each of these mean.
|
|
|
69 |
*/
|
|
|
70 |
public function __construct($val = -1, $type = '')
|
|
|
71 |
{
|
|
|
72 |
// optimization creep - do not call addXX, do it all inline.
|
|
|
73 |
// downside: booleans will not be coerced anymore
|
|
|
74 |
if ($val !== -1 || $type != '') {
|
|
|
75 |
switch ($type) {
|
|
|
76 |
case '':
|
|
|
77 |
$this->mytype = 1;
|
|
|
78 |
$this->me['string'] = $val;
|
|
|
79 |
break;
|
|
|
80 |
case 'i4':
|
|
|
81 |
case 'i8':
|
|
|
82 |
case 'int':
|
|
|
83 |
case 'double':
|
|
|
84 |
case 'string':
|
|
|
85 |
case 'boolean':
|
|
|
86 |
case 'dateTime.iso8601':
|
|
|
87 |
case 'base64':
|
|
|
88 |
case 'null':
|
|
|
89 |
$this->mytype = 1;
|
|
|
90 |
$this->me[$type] = $val;
|
|
|
91 |
break;
|
|
|
92 |
case 'array':
|
|
|
93 |
$this->mytype = 2;
|
|
|
94 |
$this->me['array'] = $val;
|
|
|
95 |
break;
|
|
|
96 |
case 'struct':
|
|
|
97 |
$this->mytype = 3;
|
|
|
98 |
$this->me['struct'] = $val;
|
|
|
99 |
break;
|
|
|
100 |
default:
|
|
|
101 |
$this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a known type ($type)");
|
|
|
102 |
}
|
|
|
103 |
}
|
|
|
104 |
}
|
|
|
105 |
|
|
|
106 |
/**
|
|
|
107 |
* Add a single php value to an xml-rpc value.
|
|
|
108 |
*
|
|
|
109 |
* If the xml-rpc value is an array, the php value is added as its last element.
|
|
|
110 |
* If the xml-rpc value is empty (uninitialized), this method makes it a scalar value, and sets that value.
|
|
|
111 |
* Fails if the xml-rpc value is not an array (i.e. a struct or a scalar) and already initialized.
|
|
|
112 |
*
|
|
|
113 |
* @param mixed $val
|
|
|
114 |
* @param string $type allowed values: i4, i8, int, boolean, string, double, dateTime.iso8601, base64, null.
|
|
|
115 |
* @return int 1 or 0 on failure
|
|
|
116 |
*
|
|
|
117 |
* @todo arguably, as we have addArray to add elements to an Array value, and addStruct to add elements to a Struct
|
|
|
118 |
* value, we should not allow this method to add values to an Array. The 'scalar' in the method name refers to
|
|
|
119 |
* the expected state of the target object, not to the type of $val. Also, this works differently from
|
|
|
120 |
* addScalar/addStruct in that, when adding an element to an array, it wraps it into a new Value
|
|
|
121 |
* @todo rename?
|
|
|
122 |
*/
|
|
|
123 |
public function addScalar($val, $type = 'string')
|
|
|
124 |
{
|
|
|
125 |
$typeOf = null;
|
|
|
126 |
if (isset(static::$xmlrpcTypes[$type])) {
|
|
|
127 |
$typeOf = static::$xmlrpcTypes[$type];
|
|
|
128 |
}
|
|
|
129 |
|
|
|
130 |
if ($typeOf !== 1) {
|
|
|
131 |
$this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a scalar type ($type)");
|
|
|
132 |
return 0;
|
|
|
133 |
}
|
|
|
134 |
|
|
|
135 |
// coerce booleans into correct values
|
|
|
136 |
/// @todo we should either do it for datetimes, integers, i8 and doubles, too, or just plain remove this check,
|
|
|
137 |
/// implemented on booleans only...
|
|
|
138 |
if ($type == static::$xmlrpcBoolean) {
|
|
|
139 |
if (strcasecmp($val, 'true') == 0 || $val == 1 || ($val == true && strcasecmp($val, 'false'))) {
|
|
|
140 |
$val = true;
|
|
|
141 |
} else {
|
|
|
142 |
$val = false;
|
|
|
143 |
}
|
|
|
144 |
}
|
|
|
145 |
|
|
|
146 |
switch ($this->mytype) {
|
|
|
147 |
case 1:
|
|
|
148 |
$this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': scalar xmlrpc value can have only one value');
|
|
|
149 |
return 0;
|
|
|
150 |
case 3:
|
|
|
151 |
$this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': cannot add anonymous scalar to struct xmlrpc value');
|
|
|
152 |
return 0;
|
|
|
153 |
case 2:
|
|
|
154 |
// we're adding a scalar value to an array here
|
|
|
155 |
/// @todo should we try avoiding re-wrapping Value objects?
|
|
|
156 |
$class = get_class($this);
|
|
|
157 |
$this->me['array'][] = new $class($val, $type);
|
|
|
158 |
|
|
|
159 |
return 1;
|
|
|
160 |
default:
|
|
|
161 |
// a scalar, so set the value and remember we're scalar
|
|
|
162 |
$this->me[$type] = $val;
|
|
|
163 |
$this->mytype = $typeOf;
|
|
|
164 |
|
|
|
165 |
return 1;
|
|
|
166 |
}
|
|
|
167 |
}
|
|
|
168 |
|
|
|
169 |
/**
|
|
|
170 |
* Add an array of xml-rpc value objects to an xml-rpc value.
|
|
|
171 |
*
|
|
|
172 |
* If the xml-rpc value is an array, the elements are appended to the existing ones.
|
|
|
173 |
* If the xml-rpc value is empty (uninitialized), this method makes it an array value, and sets that value.
|
|
|
174 |
* Fails otherwise.
|
|
|
175 |
*
|
|
|
176 |
* @param Value[] $values
|
|
|
177 |
* @return int 1 or 0 on failure
|
|
|
178 |
*
|
|
|
179 |
* @todo add some checking for $values to be an array of xml-rpc values?
|
|
|
180 |
* @todo rename to addToArray?
|
|
|
181 |
*/
|
|
|
182 |
public function addArray($values)
|
|
|
183 |
{
|
|
|
184 |
if ($this->mytype == 0) {
|
|
|
185 |
$this->mytype = static::$xmlrpcTypes['array'];
|
|
|
186 |
$this->me['array'] = $values;
|
|
|
187 |
|
|
|
188 |
return 1;
|
|
|
189 |
} elseif ($this->mytype == 2) {
|
|
|
190 |
// we're adding to an array here
|
|
|
191 |
$this->me['array'] = array_merge($this->me['array'], $values);
|
|
|
192 |
|
|
|
193 |
return 1;
|
|
|
194 |
} else {
|
|
|
195 |
$this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']');
|
|
|
196 |
return 0;
|
|
|
197 |
}
|
|
|
198 |
}
|
|
|
199 |
|
|
|
200 |
/**
|
|
|
201 |
* Merges an array of named xml-rpc value objects into an xml-rpc value.
|
|
|
202 |
*
|
|
|
203 |
* If the xml-rpc value is a struct, the elements are merged with the existing ones (overwriting existing ones).
|
|
|
204 |
* If the xml-rpc value is empty (uninitialized), this method makes it a struct value, and sets that value.
|
|
|
205 |
* Fails otherwise.
|
|
|
206 |
*
|
|
|
207 |
* @param Value[] $values
|
|
|
208 |
* @return int 1 or 0 on failure
|
|
|
209 |
*
|
|
|
210 |
* @todo add some checking for $values to be an array of xml-rpc values?
|
|
|
211 |
* @todo rename to addToStruct?
|
|
|
212 |
*/
|
|
|
213 |
public function addStruct($values)
|
|
|
214 |
{
|
|
|
215 |
if ($this->mytype == 0) {
|
|
|
216 |
$this->mytype = static::$xmlrpcTypes['struct'];
|
|
|
217 |
$this->me['struct'] = $values;
|
|
|
218 |
|
|
|
219 |
return 1;
|
|
|
220 |
} elseif ($this->mytype == 3) {
|
|
|
221 |
// we're adding to a struct here
|
|
|
222 |
$this->me['struct'] = array_merge($this->me['struct'], $values);
|
|
|
223 |
|
|
|
224 |
return 1;
|
|
|
225 |
} else {
|
|
|
226 |
$this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': already initialized as a [' . $this->kindOf() . ']');
|
|
|
227 |
return 0;
|
|
|
228 |
}
|
|
|
229 |
}
|
|
|
230 |
|
|
|
231 |
/**
|
|
|
232 |
* Returns a string describing the base type of the value.
|
|
|
233 |
*
|
|
|
234 |
* @return string either "struct", "array", "scalar" or "undef"
|
|
|
235 |
*/
|
|
|
236 |
public function kindOf()
|
|
|
237 |
{
|
|
|
238 |
switch ($this->mytype) {
|
|
|
239 |
case 3:
|
|
|
240 |
return 'struct';
|
|
|
241 |
case 2:
|
|
|
242 |
return 'array';
|
|
|
243 |
case 1:
|
|
|
244 |
return 'scalar';
|
|
|
245 |
default:
|
|
|
246 |
return 'undef';
|
|
|
247 |
}
|
|
|
248 |
}
|
|
|
249 |
|
|
|
250 |
|
|
|
251 |
/**
|
|
|
252 |
* Returns the value of a scalar xml-rpc value (base 64 decoding is automatically handled here)
|
|
|
253 |
*
|
|
|
254 |
* @return mixed
|
|
|
255 |
*/
|
|
|
256 |
public function scalarVal()
|
|
|
257 |
{
|
|
|
258 |
$b = reset($this->me);
|
|
|
259 |
|
|
|
260 |
return $b;
|
|
|
261 |
}
|
|
|
262 |
|
|
|
263 |
/**
|
|
|
264 |
* Returns the type of the xml-rpc value.
|
|
|
265 |
*
|
|
|
266 |
* @return string For integers, 'int' is always returned in place of 'i4'. 'i8' is considered a separate type and
|
|
|
267 |
* returned as such
|
|
|
268 |
*/
|
|
|
269 |
public function scalarTyp()
|
|
|
270 |
{
|
|
|
271 |
reset($this->me);
|
|
|
272 |
$a = key($this->me);
|
|
|
273 |
if ($a == static::$xmlrpcI4) {
|
|
|
274 |
$a = static::$xmlrpcInt;
|
|
|
275 |
}
|
|
|
276 |
|
|
|
277 |
return $a;
|
|
|
278 |
}
|
|
|
279 |
|
|
|
280 |
/**
|
|
|
281 |
* Returns the xml representation of the value. XML prologue not included.
|
|
|
282 |
*
|
|
|
283 |
* @param string $charsetEncoding the charset to be used for serialization. If null, US-ASCII is assumed
|
|
|
284 |
* @return string
|
|
|
285 |
*/
|
|
|
286 |
public function serialize($charsetEncoding = '')
|
|
|
287 |
{
|
|
|
288 |
$val = reset($this->me);
|
|
|
289 |
$typ = key($this->me);
|
|
|
290 |
|
|
|
291 |
return '<value>' . $this->serializeData($typ, $val, $charsetEncoding) . "</value>\n";
|
|
|
292 |
}
|
|
|
293 |
|
|
|
294 |
/**
|
|
|
295 |
* @param string $typ
|
|
|
296 |
* @param Value[]|mixed $val
|
|
|
297 |
* @param string $charsetEncoding
|
|
|
298 |
* @return string
|
|
|
299 |
*
|
|
|
300 |
* @deprecated this should be folded back into serialize()
|
|
|
301 |
*/
|
|
|
302 |
protected function serializeData($typ, $val, $charsetEncoding = '')
|
|
|
303 |
{
|
|
|
304 |
$this->logDeprecationUnlessCalledBy('serialize');
|
|
|
305 |
|
|
|
306 |
if (!isset(static::$xmlrpcTypes[$typ])) {
|
|
|
307 |
return '';
|
|
|
308 |
}
|
|
|
309 |
|
|
|
310 |
switch (static::$xmlrpcTypes[$typ]) {
|
|
|
311 |
case 1:
|
|
|
312 |
switch ($typ) {
|
|
|
313 |
case static::$xmlrpcBase64:
|
|
|
314 |
$rs = "<{$typ}>" . base64_encode($val) . "</{$typ}>";
|
|
|
315 |
break;
|
|
|
316 |
case static::$xmlrpcBoolean:
|
|
|
317 |
$rs = "<{$typ}>" . ($val ? '1' : '0') . "</{$typ}>";
|
|
|
318 |
break;
|
|
|
319 |
case static::$xmlrpcString:
|
|
|
320 |
// Do NOT use htmlentities, since it will produce named html entities, which are invalid xml
|
|
|
321 |
$rs = "<{$typ}>" . $this->getCharsetEncoder()->encodeEntities($val, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</{$typ}>";
|
|
|
322 |
break;
|
|
|
323 |
case static::$xmlrpcInt:
|
|
|
324 |
case static::$xmlrpcI4:
|
|
|
325 |
case static::$xmlrpcI8:
|
|
|
326 |
$rs = "<{$typ}>" . (int)$val . "</{$typ}>";
|
|
|
327 |
break;
|
|
|
328 |
case static::$xmlrpcDouble:
|
|
|
329 |
// avoid using standard conversion of float to string because it is locale-dependent,
|
|
|
330 |
// and also because the xml-rpc spec forbids exponential notation.
|
|
|
331 |
// sprintf('%F') could be most likely ok, but it fails e.g. on 2e-14.
|
|
|
332 |
// The code below tries its best at keeping max precision while avoiding exp notation,
|
|
|
333 |
// but there is of course no limit in the number of decimal places to be used...
|
|
|
334 |
$rs = "<{$typ}>" . preg_replace('/\\.?0+$/', '', number_format((double)$val, PhpXmlRpc::$xmlpc_double_precision, '.', '')) . "</{$typ}>";
|
|
|
335 |
break;
|
|
|
336 |
case static::$xmlrpcDateTime:
|
|
|
337 |
if (is_string($val)) {
|
|
|
338 |
$rs = "<{$typ}>{$val}</{$typ}>";
|
|
|
339 |
// DateTimeInterface is not present in php 5.4...
|
|
|
340 |
} elseif (is_a($val, 'DateTimeInterface') || is_a($val, 'DateTime')) {
|
|
|
341 |
$rs = "<{$typ}>" . $val->format('Ymd\TH:i:s') . "</{$typ}>";
|
|
|
342 |
} elseif (is_int($val)) {
|
|
|
343 |
$rs = "<{$typ}>" . date('Ymd\TH:i:s', $val) . "</{$typ}>";
|
|
|
344 |
} else {
|
|
|
345 |
// not really a good idea here: but what should we output anyway? left for backward compat...
|
|
|
346 |
$rs = "<{$typ}>{$val}</{$typ}>";
|
|
|
347 |
}
|
|
|
348 |
break;
|
|
|
349 |
case static::$xmlrpcNull:
|
|
|
350 |
if (PhpXmlRpc::$xmlrpc_null_apache_encoding) {
|
|
|
351 |
$rs = "<ex:nil/>";
|
|
|
352 |
} else {
|
|
|
353 |
$rs = "<nil/>";
|
|
|
354 |
}
|
|
|
355 |
break;
|
|
|
356 |
default:
|
|
|
357 |
// no standard type value should arrive here, but provide a possibility
|
|
|
358 |
// for xml-rpc values of unknown type...
|
|
|
359 |
$rs = "<{$typ}>{$val}</{$typ}>";
|
|
|
360 |
}
|
|
|
361 |
break;
|
|
|
362 |
case 3:
|
|
|
363 |
// struct
|
|
|
364 |
if ($this->_php_class) {
|
|
|
365 |
$rs = '<struct php_class="' . $this->_php_class . "\">\n";
|
|
|
366 |
} else {
|
|
|
367 |
$rs = "<struct>\n";
|
|
|
368 |
}
|
|
|
369 |
$charsetEncoder = $this->getCharsetEncoder();
|
|
|
370 |
/** @var Value $val2 */
|
|
|
371 |
foreach ($val as $key2 => $val2) {
|
|
|
372 |
$rs .= '<member><name>' . $charsetEncoder->encodeEntities($key2, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</name>\n";
|
|
|
373 |
$rs .= $val2->serialize($charsetEncoding);
|
|
|
374 |
$rs .= "</member>\n";
|
|
|
375 |
}
|
|
|
376 |
$rs .= '</struct>';
|
|
|
377 |
break;
|
|
|
378 |
case 2:
|
|
|
379 |
// array
|
|
|
380 |
$rs = "<array>\n<data>\n";
|
|
|
381 |
/** @var Value $element */
|
|
|
382 |
foreach ($val as $element) {
|
|
|
383 |
$rs .= $element->serialize($charsetEncoding);
|
|
|
384 |
}
|
|
|
385 |
$rs .= "</data>\n</array>";
|
|
|
386 |
break;
|
|
|
387 |
default:
|
|
|
388 |
/// @todo log a warning?
|
|
|
389 |
$rs = '';
|
|
|
390 |
break;
|
|
|
391 |
}
|
|
|
392 |
|
|
|
393 |
return $rs;
|
|
|
394 |
}
|
|
|
395 |
|
|
|
396 |
/**
|
|
|
397 |
* Returns the number of members in an xml-rpc value:
|
|
|
398 |
* - 0 for uninitialized values
|
|
|
399 |
* - 1 for scalar values
|
|
|
400 |
* - the number of elements for struct and array values
|
|
|
401 |
*
|
|
|
402 |
* @return integer
|
|
|
403 |
*/
|
|
|
404 |
#[\ReturnTypeWillChange]
|
|
|
405 |
public function count()
|
|
|
406 |
{
|
|
|
407 |
switch ($this->mytype) {
|
|
|
408 |
case 3:
|
|
|
409 |
return count($this->me['struct']);
|
|
|
410 |
case 2:
|
|
|
411 |
return count($this->me['array']);
|
|
|
412 |
case 1:
|
|
|
413 |
return 1;
|
|
|
414 |
default:
|
|
|
415 |
return 0;
|
|
|
416 |
}
|
|
|
417 |
}
|
|
|
418 |
|
|
|
419 |
/**
|
|
|
420 |
* Implements the IteratorAggregate interface
|
|
|
421 |
* @internal required to be public to implement an Interface
|
|
|
422 |
*
|
|
|
423 |
* @return \ArrayIterator
|
|
|
424 |
*/
|
|
|
425 |
#[\ReturnTypeWillChange]
|
|
|
426 |
public function getIterator()
|
|
|
427 |
{
|
|
|
428 |
switch ($this->mytype) {
|
|
|
429 |
case 3:
|
|
|
430 |
return new \ArrayIterator($this->me['struct']);
|
|
|
431 |
case 2:
|
|
|
432 |
return new \ArrayIterator($this->me['array']);
|
|
|
433 |
case 1:
|
|
|
434 |
return new \ArrayIterator($this->me);
|
|
|
435 |
default:
|
|
|
436 |
return new \ArrayIterator();
|
|
|
437 |
}
|
|
|
438 |
}
|
|
|
439 |
|
|
|
440 |
/**
|
|
|
441 |
* @internal required to be public to implement an Interface
|
|
|
442 |
*
|
|
|
443 |
* @param mixed $offset
|
|
|
444 |
* @param mixed $value
|
|
|
445 |
* @return void
|
|
|
446 |
*
|
|
|
447 |
* @throws ValueErrorException|TypeErrorException
|
|
|
448 |
*/
|
|
|
449 |
#[\ReturnTypeWillChange]
|
|
|
450 |
public function offsetSet($offset, $value)
|
|
|
451 |
{
|
|
|
452 |
switch ($this->mytype) {
|
|
|
453 |
case 3:
|
|
|
454 |
if (!($value instanceof Value)) {
|
|
|
455 |
throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Struct');
|
|
|
456 |
}
|
|
|
457 |
if (is_null($offset)) {
|
|
|
458 |
// disallow struct members with empty names
|
|
|
459 |
throw new ValueErrorException('It is not possible to add anonymous members to an XML-RPC Struct');
|
|
|
460 |
} else {
|
|
|
461 |
$this->me['struct'][$offset] = $value;
|
|
|
462 |
}
|
|
|
463 |
return;
|
|
|
464 |
case 2:
|
|
|
465 |
if (!($value instanceof Value)) {
|
|
|
466 |
throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Array');
|
|
|
467 |
}
|
|
|
468 |
if (is_null($offset)) {
|
|
|
469 |
$this->me['array'][] = $value;
|
|
|
470 |
} else {
|
|
|
471 |
// nb: we are not checking that $offset is above the existing array range...
|
|
|
472 |
$this->me['array'][$offset] = $value;
|
|
|
473 |
}
|
|
|
474 |
return;
|
|
|
475 |
case 1:
|
|
|
476 |
/// @todo: should we handle usage of i4 to retrieve int (in both set/unset/isset)? After all we consider
|
|
|
477 |
/// 'int' to be the preferred form, as evidenced in scalarTyp()
|
|
|
478 |
reset($this->me);
|
|
|
479 |
$type = key($this->me);
|
|
|
480 |
if ($type != $offset && ($type != 'i4' || $offset != 'int')) {
|
|
|
481 |
throw new ValueErrorException('...');
|
|
|
482 |
}
|
|
|
483 |
$this->me[$type] = $value;
|
|
|
484 |
return;
|
|
|
485 |
default:
|
|
|
486 |
// it would be nice to allow empty values to be turned into non-empty ones this way, but we miss info to do so
|
|
|
487 |
throw new ValueErrorException("XML-RPC Value is of type 'undef' and its value can not be set using array index");
|
|
|
488 |
}
|
|
|
489 |
}
|
|
|
490 |
|
|
|
491 |
/**
|
|
|
492 |
* @internal required to be public to implement an Interface
|
|
|
493 |
*
|
|
|
494 |
* @param mixed $offset
|
|
|
495 |
* @return bool
|
|
|
496 |
*/
|
|
|
497 |
#[\ReturnTypeWillChange]
|
|
|
498 |
public function offsetExists($offset)
|
|
|
499 |
{
|
|
|
500 |
switch ($this->mytype) {
|
|
|
501 |
case 3:
|
|
|
502 |
return isset($this->me['struct'][$offset]);
|
|
|
503 |
case 2:
|
|
|
504 |
return isset($this->me['array'][$offset]);
|
|
|
505 |
case 1:
|
|
|
506 |
// handle i4 vs int
|
|
|
507 |
if ($offset == 'i4') {
|
|
|
508 |
// to be consistent with set and unset, we disallow usage of i4 to check for int
|
|
|
509 |
reset($this->me);
|
|
|
510 |
return $offset == key($this->me);
|
|
|
511 |
} else {
|
|
|
512 |
return $offset == $this->scalarTyp();
|
|
|
513 |
}
|
|
|
514 |
default:
|
|
|
515 |
return false;
|
|
|
516 |
}
|
|
|
517 |
}
|
|
|
518 |
|
|
|
519 |
/**
|
|
|
520 |
* @internal required to be public to implement an Interface
|
|
|
521 |
*
|
|
|
522 |
* @param mixed $offset
|
|
|
523 |
* @return void
|
|
|
524 |
*
|
|
|
525 |
* @throws ValueErrorException|StateErrorException
|
|
|
526 |
*/
|
|
|
527 |
#[\ReturnTypeWillChange]
|
|
|
528 |
public function offsetUnset($offset)
|
|
|
529 |
{
|
|
|
530 |
switch ($this->mytype) {
|
|
|
531 |
case 3:
|
|
|
532 |
unset($this->me['struct'][$offset]);
|
|
|
533 |
return;
|
|
|
534 |
case 2:
|
|
|
535 |
unset($this->me['array'][$offset]);
|
|
|
536 |
return;
|
|
|
537 |
case 1:
|
|
|
538 |
// can not remove value from a scalar
|
|
|
539 |
/// @todo feature creep - allow this to move back the value to 'undef' state?
|
|
|
540 |
throw new StateErrorException("XML-RPC Value is of type 'scalar' and its value can not be unset using array index");
|
|
|
541 |
default:
|
|
|
542 |
throw new StateErrorException("XML-RPC Value is of type 'undef' and its value can not be unset using array index");
|
|
|
543 |
}
|
|
|
544 |
}
|
|
|
545 |
|
|
|
546 |
/**
|
|
|
547 |
* @internal required to be public to implement an Interface
|
|
|
548 |
*
|
|
|
549 |
* @param mixed $offset
|
|
|
550 |
* @return mixed|Value|null
|
|
|
551 |
* @throws StateErrorException
|
|
|
552 |
*/
|
|
|
553 |
#[\ReturnTypeWillChange]
|
|
|
554 |
public function offsetGet($offset)
|
|
|
555 |
{
|
|
|
556 |
switch ($this->mytype) {
|
|
|
557 |
case 3:
|
|
|
558 |
return isset($this->me['struct'][$offset]) ? $this->me['struct'][$offset] : null;
|
|
|
559 |
case 2:
|
|
|
560 |
return isset($this->me['array'][$offset]) ? $this->me['array'][$offset] : null;
|
|
|
561 |
case 1:
|
|
|
562 |
/// @todo what to return on bad type: null or exception?
|
|
|
563 |
$value = reset($this->me);
|
|
|
564 |
$type = key($this->me);
|
|
|
565 |
return $type == $offset ? $value : (($type == 'i4' && $offset == 'int') ? $value : null);
|
|
|
566 |
default:
|
|
|
567 |
// return null or exception?
|
|
|
568 |
throw new StateErrorException("XML-RPC Value is of type 'undef' and can not be accessed using array index");
|
|
|
569 |
}
|
|
|
570 |
}
|
|
|
571 |
|
|
|
572 |
// *** BC layer ***
|
|
|
573 |
|
|
|
574 |
/**
|
|
|
575 |
* Checks whether a struct member with a given name is present.
|
|
|
576 |
*
|
|
|
577 |
* Works only on xml-rpc values of type struct.
|
|
|
578 |
*
|
|
|
579 |
* @param string $key the name of the struct member to be looked up
|
|
|
580 |
* @return boolean
|
|
|
581 |
*
|
|
|
582 |
* @deprecated use array access, e.g. isset($val[$key])
|
|
|
583 |
*/
|
|
|
584 |
public function structMemExists($key)
|
|
|
585 |
{
|
|
|
586 |
$this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
|
|
|
587 |
|
|
|
588 |
return array_key_exists($key, $this->me['struct']);
|
|
|
589 |
}
|
|
|
590 |
|
|
|
591 |
/**
|
|
|
592 |
* Returns the value of a given struct member (an xml-rpc value object in itself).
|
|
|
593 |
* Will raise a php warning if struct member of given name does not exist.
|
|
|
594 |
*
|
|
|
595 |
* @param string $key the name of the struct member to be looked up
|
|
|
596 |
* @return Value
|
|
|
597 |
*
|
|
|
598 |
* @deprecated use array access, e.g. $val[$key]
|
|
|
599 |
*/
|
|
|
600 |
public function structMem($key)
|
|
|
601 |
{
|
|
|
602 |
$this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
|
|
|
603 |
|
|
|
604 |
return $this->me['struct'][$key];
|
|
|
605 |
}
|
|
|
606 |
|
|
|
607 |
/**
|
|
|
608 |
* Reset internal pointer for xml-rpc values of type struct.
|
|
|
609 |
* @return void
|
|
|
610 |
*
|
|
|
611 |
* @deprecated iterate directly over the object using foreach instead
|
|
|
612 |
*/
|
|
|
613 |
public function structReset()
|
|
|
614 |
{
|
|
|
615 |
$this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
|
|
|
616 |
|
|
|
617 |
reset($this->me['struct']);
|
|
|
618 |
}
|
|
|
619 |
|
|
|
620 |
/**
|
|
|
621 |
* Return next member element for xml-rpc values of type struct.
|
|
|
622 |
*
|
|
|
623 |
* @return array having the same format as PHP's `each` method
|
|
|
624 |
*
|
|
|
625 |
* @deprecated iterate directly over the object using foreach instead
|
|
|
626 |
*/
|
|
|
627 |
public function structEach()
|
|
|
628 |
{
|
|
|
629 |
$this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
|
|
|
630 |
|
|
|
631 |
$key = key($this->me['struct']);
|
|
|
632 |
$value = current($this->me['struct']);
|
|
|
633 |
next($this->me['struct']);
|
|
|
634 |
return array(1 => $value, 'value' => $value, 0 => $key, 'key' => $key);
|
|
|
635 |
}
|
|
|
636 |
|
|
|
637 |
/**
|
|
|
638 |
* Returns the n-th member of an xml-rpc value of array type.
|
|
|
639 |
*
|
|
|
640 |
* @param integer $key the index of the value to be retrieved (zero based)
|
|
|
641 |
*
|
|
|
642 |
* @return Value
|
|
|
643 |
*
|
|
|
644 |
* @deprecated use array access, e.g. $val[$key]
|
|
|
645 |
*/
|
|
|
646 |
public function arrayMem($key)
|
|
|
647 |
{
|
|
|
648 |
$this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
|
|
|
649 |
|
|
|
650 |
return $this->me['array'][$key];
|
|
|
651 |
}
|
|
|
652 |
|
|
|
653 |
/**
|
|
|
654 |
* Returns the number of members in an xml-rpc value of array type.
|
|
|
655 |
*
|
|
|
656 |
* @return integer
|
|
|
657 |
*
|
|
|
658 |
* @deprecated use count() instead
|
|
|
659 |
*/
|
|
|
660 |
public function arraySize()
|
|
|
661 |
{
|
|
|
662 |
$this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
|
|
|
663 |
|
|
|
664 |
return count($this->me['array']);
|
|
|
665 |
}
|
|
|
666 |
|
|
|
667 |
/**
|
|
|
668 |
* Returns the number of members in an xml-rpc value of struct type.
|
|
|
669 |
*
|
|
|
670 |
* @return integer
|
|
|
671 |
*
|
|
|
672 |
* @deprecated use count() instead
|
|
|
673 |
*/
|
|
|
674 |
public function structSize()
|
|
|
675 |
{
|
|
|
676 |
$this->logDeprecation('Method ' . __METHOD__ . ' is deprecated');
|
|
|
677 |
|
|
|
678 |
return count($this->me['struct']);
|
|
|
679 |
}
|
|
|
680 |
|
|
|
681 |
// we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
|
|
|
682 |
public function &__get($name)
|
|
|
683 |
{
|
|
|
684 |
switch ($name) {
|
|
|
685 |
case 'me':
|
|
|
686 |
case 'mytype':
|
|
|
687 |
case '_php_class':
|
|
|
688 |
$this->logDeprecation('Getting property Value::' . $name . ' is deprecated');
|
|
|
689 |
return $this->$name;
|
|
|
690 |
default:
|
|
|
691 |
/// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
|
|
|
692 |
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
|
|
|
693 |
trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
|
|
|
694 |
$result = null;
|
|
|
695 |
return $result;
|
|
|
696 |
}
|
|
|
697 |
}
|
|
|
698 |
|
|
|
699 |
public function __set($name, $value)
|
|
|
700 |
{
|
|
|
701 |
switch ($name) {
|
|
|
702 |
case 'me':
|
|
|
703 |
case 'mytype':
|
|
|
704 |
case '_php_class':
|
|
|
705 |
$this->logDeprecation('Setting property Value::' . $name . ' is deprecated');
|
|
|
706 |
$this->$name = $value;
|
|
|
707 |
break;
|
|
|
708 |
default:
|
|
|
709 |
/// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
|
|
|
710 |
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
|
|
|
711 |
trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
|
|
|
712 |
}
|
|
|
713 |
}
|
|
|
714 |
|
|
|
715 |
public function __isset($name)
|
|
|
716 |
{
|
|
|
717 |
switch ($name) {
|
|
|
718 |
case 'me':
|
|
|
719 |
case 'mytype':
|
|
|
720 |
case '_php_class':
|
|
|
721 |
$this->logDeprecation('Checking property Value::' . $name . ' is deprecated');
|
|
|
722 |
return isset($this->$name);
|
|
|
723 |
default:
|
|
|
724 |
return false;
|
|
|
725 |
}
|
|
|
726 |
}
|
|
|
727 |
|
|
|
728 |
public function __unset($name)
|
|
|
729 |
{
|
|
|
730 |
switch ($name) {
|
|
|
731 |
case 'me':
|
|
|
732 |
case 'mytype':
|
|
|
733 |
case '_php_class':
|
|
|
734 |
$this->logDeprecation('Unsetting property Value::' . $name . ' is deprecated');
|
|
|
735 |
unset($this->$name);
|
|
|
736 |
break;
|
|
|
737 |
default:
|
|
|
738 |
/// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
|
|
|
739 |
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
|
|
|
740 |
trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
|
|
|
741 |
}
|
|
|
742 |
}
|
|
|
743 |
}
|