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 | 1 | */ |
|
55 | protected $mytype = 0; |
||
56 | 1 | /** @var string|null */ |
|
57 | 1 | protected $_php_class = null; |
|
58 | |||
59 | 1 | /** |
|
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 | 594 | * 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 | 594 | */ |
|
70 | 435 | public function __construct($val = -1, $type = '') |
|
71 | { |
||
72 | 594 | // 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 | 746 | break; |
|
92 | case 'array': |
||
93 | $this->mytype = 2; |
||
94 | $this->me['array'] = $val; |
||
95 | 746 | break; |
|
96 | 745 | case 'struct': |
|
97 | 745 | $this->mytype = 3; |
|
98 | 251 | $this->me['struct'] = $val; |
|
99 | 251 | break; |
|
100 | 251 | default: |
|
101 | 743 | $this->getLogger()->error("XML-RPC: " . __METHOD__ . ": not a known type ($type)"); |
|
102 | 743 | } |
|
103 | 743 | } |
|
104 | 698 | } |
|
105 | 677 | ||
106 | 469 | /** |
|
107 | 448 | * Add a single php value to an xml-rpc value. |
|
108 | 425 | * |
|
109 | 404 | * If the xml-rpc value is an array, the php value is added as its last element. |
|
110 | 717 | * If the xml-rpc value is empty (uninitialized), this method makes it a scalar value, and sets that value. |
|
111 | 717 | * Fails if the xml-rpc value is not an array (i.e. a struct or a scalar) and already initialized. |
|
112 | 717 | * |
|
113 | 403 | * @param mixed $val |
|
114 | 241 | * @param string $type allowed values: i4, i8, int, boolean, string, double, dateTime.iso8601, base64, null. |
|
115 | 241 | * @return int 1 or 0 on failure |
|
116 | 241 | * |
|
117 | 295 | * @todo arguably, as we have addArray to add elements to an Array value, and addStruct to add elements to a Struct |
|
118 | 295 | * value, we should not allow this method to add values to an Array. The 'scalar' in the method name refers to |
|
119 | 295 | * the expected state of the target object, not to the type of $val. Also, this works differently from |
|
120 | 295 | * 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 | 746 | $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 | 1 | if (strcasecmp($val, 'true') == 0 || $val == 1 || ($val == true && strcasecmp($val, 'false'))) { |
|
140 | $val = true; |
||
141 | 1 | } else { |
|
142 | 1 | $val = false; |
|
143 | 1 | } |
|
144 | } |
||
145 | |||
146 | 1 | 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 | 1 | // 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 | 1 | $this->me[$type] = $val; |
|
163 | 1 | $this->mytype = $typeOf; |
|
164 | |||
165 | return 1; |
||
166 | 1 | } |
|
167 | 1 | } |
|
168 | 1 | ||
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 | 1 | return 0; |
|
197 | } |
||
198 | 1 | } |
|
199 | |||
200 | /** |
||
201 | * Merges an array of named xml-rpc value objects into an xml-rpc value. |
||
202 | * |
||
203 | 1 | * 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 | 1 | * Fails otherwise. |
|
206 | * |
||
207 | 1 | * @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 | 1 | return 0; |
|
228 | } |
||
229 | 1 | } |
|
230 | |||
231 | /** |
||
232 | * Returns a string describing the base type of the value. |
||
233 | * |
||
234 | 1 | * @return string either "struct", "array", "scalar" or "undef" |
|
235 | */ |
||
236 | 1 | public function kindOf() |
|
237 | { |
||
238 | 1 | 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 | 627 | ||
251 | /** |
||
252 | 627 | * Returns the value of a scalar xml-rpc value (base 64 decoding is automatically handled here) |
|
253 | 627 | * |
|
254 | 150 | * @return mixed |
|
255 | 606 | */ |
|
256 | 214 | public function scalarVal() |
|
257 | 583 | { |
|
258 | 583 | $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 | 705 | { |
|
271 | reset($this->me); |
||
272 | 705 | $a = key($this->me); |
|
273 | if ($a == static::$xmlrpcI4) { |
||
274 | 705 | $a = static::$xmlrpcInt; |
|
275 | 2 | } |
|
276 | |||
277 | return $a; |
||
278 | 705 | } |
|
279 | 705 | ||
280 | /** |
||
281 | 684 | * Returns the xml representation of the value. XML prologue not included. |
|
282 | 23 | * |
|
283 | 23 | * @param string $charsetEncoding the charset to be used for serialization. If null, US-ASCII is assumed |
|
284 | 684 | * @return string |
|
285 | 46 | */ |
|
286 | 46 | public function serialize($charsetEncoding = '') |
|
287 | 663 | { |
|
288 | $val = reset($this->me); |
||
289 | 573 | $typ = key($this->me); |
|
290 | 573 | ||
291 | 474 | return '<value>' . $this->serializeData($typ, $val, $charsetEncoding) . "</value>\n"; |
|
292 | 68 | } |
|
293 | 68 | ||
294 | 430 | /** |
|
295 | 430 | * @param string $typ |
|
296 | 68 | * @param Value[]|mixed $val |
|
297 | * @param string $charsetEncoding |
||
298 | * @return string |
||
299 | * |
||
300 | * @deprecated this should be folded back into serialize() |
||
301 | */ |
||
302 | 24 | protected function serializeData($typ, $val, $charsetEncoding = '') |
|
303 | 24 | { |
|
304 | 47 | $this->logDeprecationUnlessCalledBy('serialize'); |
|
305 | 25 | ||
306 | 24 | if (!isset(static::$xmlrpcTypes[$typ])) { |
|
307 | 23 | return ''; |
|
308 | 22 | } |
|
309 | 23 | ||
310 | 23 | switch (static::$xmlrpcTypes[$typ]) { |
|
311 | case 1: |
||
312 | switch ($typ) { |
||
313 | case static::$xmlrpcBase64: |
||
314 | $rs = "<{$typ}>" . base64_encode($val) . "</{$typ}>"; |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
315 | 25 | break; |
|
316 | 23 | case static::$xmlrpcBoolean: |
|
317 | 23 | $rs = "<{$typ}>" . ($val ? '1' : '0') . "</{$typ}>"; |
|
318 | 23 | break; |
|
319 | case static::$xmlrpcString: |
||
320 | 1 | // 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 | 23 | break; |
|
323 | case static::$xmlrpcInt: |
||
324 | case static::$xmlrpcI4: |
||
325 | case static::$xmlrpcI8: |
||
326 | $rs = "<{$typ}>" . (int)$val . "</{$typ}>"; |
||
327 | break; |
||
328 | 684 | case static::$xmlrpcDouble: |
|
329 | 218 | // 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 | 133 | // sprintf('%F') could be most likely ok, but it fails e.g. on 2e-14. |
|
332 | 1 | // 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 | 133 | $rs = "<{$typ}>" . preg_replace('/\\.?0+$/', '', number_format((double)$val, PhpXmlRpc::$xmlpc_double_precision, '.', '')) . "</{$typ}>"; |
|
335 | break; |
||
336 | 133 | case static::$xmlrpcDateTime: |
|
337 | if (is_string($val)) { |
||
338 | 133 | $rs = "<{$typ}>{$val}</{$typ}>"; |
|
339 | 112 | // DateTimeInterface is not present in php 5.4... |
|
340 | } elseif (is_a($val, 'DateTimeInterface') || is_a($val, 'DateTime')) { |
||
341 | 112 | $rs = "<{$typ}>" . $val->format('Ymd\TH:i:s') . "</{$typ}>"; |
|
342 | 112 | } elseif (is_int($val)) { |
|
343 | $rs = "<{$typ}>" . date('Ymd\TH:i:s', $val) . "</{$typ}>"; |
||
344 | 133 | } else { |
|
345 | 133 | // not really a good idea here: but what should we output anyway? left for backward compat... |
|
346 | 154 | $rs = "<{$typ}>{$val}</{$typ}>"; |
|
347 | } |
||
348 | 154 | break; |
|
349 | case static::$xmlrpcNull: |
||
350 | 154 | if (PhpXmlRpc::$xmlrpc_null_apache_encoding) { |
|
351 | $rs = "<ex:nil/>"; |
||
352 | 154 | } else { |
|
353 | $rs = "<nil/>"; |
||
354 | 154 | } |
|
355 | 154 | 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 | 705 | } |
|
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 | 705 | /** @var Value $val2 */ |
|
371 | foreach ($val as $key2 => $val2) { |
||
372 | 705 | $rs .= '<member><name>' . $charsetEncoder->encodeEntities($key2, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</name>\n"; |
|
373 | 705 | $rs .= $val2->serialize($charsetEncoding); |
|
374 | $rs .= "</member>\n"; |
||
375 | 705 | } |
|
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 | 2 | $rs = ''; |
|
390 | break; |
||
391 | } |
||
392 | |||
393 | 2 | 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 | 29 | { |
|
407 | switch ($this->mytype) { |
||
408 | case 3: |
||
409 | return count($this->me['struct']); |
||
410 | 29 | 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 | 660 | * @param mixed $value |
|
445 | * @return void |
||
446 | 660 | * @throws ValueErrorException|TypeErrorException |
|
447 | */ |
||
448 | 660 | #[\ReturnTypeWillChange] |
|
449 | public function offsetSet($offset, $value) |
||
450 | { |
||
451 | switch ($this->mytype) { |
||
452 | case 3: |
||
453 | if (!($value instanceof Value)) { |
||
454 | throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Struct'); |
||
455 | } |
||
456 | if (is_null($offset)) { |
||
457 | // disallow struct members with empty names |
||
458 | 454 | throw new ValueErrorException('It is not possible to add anonymous members to an XML-RPC Struct'); |
|
459 | } else { |
||
460 | 454 | $this->me['struct'][$offset] = $value; |
|
461 | 454 | } |
|
462 | 454 | return; |
|
463 | case 2: |
||
464 | if (!($value instanceof Value)) { |
||
465 | throw new TypeErrorException('It is only possible to add Value objects to an XML-RPC Array'); |
||
466 | 454 | } |
|
467 | if (is_null($offset)) { |
||
468 | $this->me['array'][] = $value; |
||
469 | } else { |
||
470 | // nb: we are not checking that $offset is above the existing array range... |
||
471 | $this->me['array'][$offset] = $value; |
||
472 | } |
||
473 | return; |
||
474 | case 1: |
||
475 | /// @todo: should we handle usage of i4 to retrieve int (in both set/unset/isset)? After all we consider |
||
476 | /// 'int' to be the preferred form, as evidenced in scalarTyp() |
||
477 | reset($this->me); |
||
478 | 43 | $type = key($this->me); |
|
479 | if ($type != $offset && ($type != 'i4' || $offset != 'int')) { |
||
480 | throw new ValueErrorException('...'); |
||
481 | } |
||
482 | 43 | $this->me[$type] = $value; |
|
483 | return; |
||
484 | default: |
||
485 | // it would be nice to allow empty values to be turned into non-empty ones this way, but we miss info to do so |
||
486 | throw new ValueErrorException("XML-RPC Value is of type 'undef' and its value can not be set using array index"); |
||
487 | } |
||
488 | } |
||
489 | |||
490 | /** |
||
491 | * @internal required to be public to implement an Interface |
||
492 | 44 | * |
|
493 | * @param mixed $offset |
||
494 | * @return bool |
||
495 | */ |
||
496 | 44 | #[\ReturnTypeWillChange] |
|
497 | public function offsetExists($offset) |
||
498 | { |
||
499 | switch ($this->mytype) { |
||
500 | case 3: |
||
501 | return isset($this->me['struct'][$offset]); |
||
502 | case 2: |
||
503 | return isset($this->me['array'][$offset]); |
||
504 | case 1: |
||
505 | // handle i4 vs int |
||
506 | 23 | if ($offset == 'i4') { |
|
507 | // to be consistent with set and unset, we disallow usage of i4 to check for int |
||
508 | reset($this->me); |
||
509 | return $offset == key($this->me); |
||
510 | 23 | } else { |
|
511 | return $offset == $this->scalarTyp(); |
||
512 | } |
||
513 | default: |
||
514 | return false; |
||
515 | } |
||
516 | } |
||
517 | |||
518 | /** |
||
519 | * @internal required to be public to implement an Interface |
||
520 | * |
||
521 | * @param mixed $offset |
||
522 | 25 | * @return void |
|
523 | * @throws ValueErrorException|StateErrorException |
||
524 | 25 | */ |
|
525 | 25 | #[\ReturnTypeWillChange] |
|
526 | public function offsetUnset($offset) |
||
527 | 25 | { |
|
528 | 25 | switch ($this->mytype) { |
|
529 | case 3: |
||
530 | unset($this->me['struct'][$offset]); |
||
531 | return; |
||
532 | case 2: |
||
533 | unset($this->me['array'][$offset]); |
||
534 | return; |
||
535 | case 1: |
||
536 | // can not remove value from a scalar |
||
537 | /// @todo feature creep - allow this to move back the value to 'undef' state? |
||
538 | throw new StateErrorException("XML-RPC Value is of type 'scalar' and its value can not be unset using array index"); |
||
539 | default: |
||
540 | throw new StateErrorException("XML-RPC Value is of type 'undef' and its value can not be unset using array index"); |
||
541 | } |
||
542 | } |
||
543 | 258 | ||
544 | /** |
||
545 | 258 | * @internal required to be public to implement an Interface |
|
546 | 258 | * |
|
547 | 65 | * @param mixed $offset |
|
548 | 215 | * @return mixed|Value|null |
|
549 | 215 | * @throws StateErrorException |
|
550 | */ |
||
551 | #[\ReturnTypeWillChange] |
||
552 | public function offsetGet($offset) |
||
553 | { |
||
554 | switch ($this->mytype) { |
||
555 | case 3: |
||
556 | return isset($this->me['struct'][$offset]) ? $this->me['struct'][$offset] : null; |
||
557 | case 2: |
||
558 | return isset($this->me['array'][$offset]) ? $this->me['array'][$offset] : null; |
||
559 | case 1: |
||
560 | /// @todo what to return on bad type: null or exception? |
||
561 | $value = reset($this->me); |
||
562 | $type = key($this->me); |
||
563 | return $type == $offset ? $value : (($type == 'i4' && $offset == 'int') ? $value : null); |
||
564 | 22 | default: |
|
565 | // return null or exception? |
||
566 | 22 | throw new StateErrorException("XML-RPC Value is of type 'undef' and can not be accessed using array index"); |
|
567 | 22 | } |
|
568 | } |
||
569 | |||
570 | // *** BC layer *** |
||
571 | |||
572 | /** |
||
573 | * Checks whether a struct member with a given name is present. |
||
574 | * |
||
575 | * Works only on xml-rpc values of type struct. |
||
576 | * |
||
577 | * @param string $key the name of the struct member to be looked up |
||
578 | 22 | * @return boolean |
|
579 | 22 | * |
|
580 | * @deprecated use array access, e.g. isset($val[$key]) |
||
581 | */ |
||
582 | 22 | public function structMemExists($key) |
|
583 | 22 | { |
|
584 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||
585 | |||
586 | return array_key_exists($key, $this->me['struct']); |
||
587 | } |
||
588 | 22 | ||
589 | /** |
||
590 | * Returns the value of a given struct member (an xml-rpc value object in itself). |
||
591 | * Will raise a php warning if struct member of given name does not exist. |
||
592 | * |
||
593 | * @param string $key the name of the struct member to be looked up |
||
594 | * @return Value |
||
595 | * |
||
596 | * @deprecated use array access, e.g. $val[$key] |
||
597 | */ |
||
598 | public function structMem($key) |
||
599 | { |
||
600 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||
601 | |||
602 | return $this->me['struct'][$key]; |
||
603 | } |
||
604 | |||
605 | /** |
||
606 | * Reset internal pointer for xml-rpc values of type struct. |
||
607 | * @return void |
||
608 | * |
||
609 | * @deprecated iterate directly over the object using foreach instead |
||
610 | */ |
||
611 | public function structReset() |
||
612 | { |
||
613 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||
614 | |||
615 | reset($this->me['struct']); |
||
616 | } |
||
617 | |||
618 | /** |
||
619 | * Return next member element for xml-rpc values of type struct. |
||
620 | * |
||
621 | * @return array having the same format as PHP's `each` method |
||
622 | * |
||
623 | * @deprecated iterate directly over the object using foreach instead |
||
624 | */ |
||
625 | public function structEach() |
||
626 | { |
||
627 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||
628 | |||
629 | $key = key($this->me['struct']); |
||
630 | $value = current($this->me['struct']); |
||
631 | next($this->me['struct']); |
||
632 | return array(1 => $value, 'value' => $value, 0 => $key, 'key' => $key); |
||
633 | } |
||
634 | |||
635 | /** |
||
636 | * Returns the n-th member of an xml-rpc value of array type. |
||
637 | * |
||
638 | * @param integer $key the index of the value to be retrieved (zero based) |
||
639 | * |
||
640 | * @return Value |
||
641 | * |
||
642 | * @deprecated use array access, e.g. $val[$key] |
||
643 | */ |
||
644 | public function arrayMem($key) |
||
645 | { |
||
646 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||
647 | |||
648 | return $this->me['array'][$key]; |
||
649 | } |
||
650 | |||
651 | /** |
||
652 | * Returns the number of members in an xml-rpc value of array type. |
||
653 | * |
||
654 | * @return integer |
||
655 | 175 | * |
|
656 | * @deprecated use count() instead |
||
657 | 175 | */ |
|
658 | 175 | public function arraySize() |
|
659 | 173 | { |
|
660 | 24 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
|
661 | 24 | ||
662 | return count($this->me['array']); |
||
663 | } |
||
664 | |||
665 | /** |
||
666 | * Returns the number of members in an xml-rpc value of struct type. |
||
667 | * |
||
668 | * @return integer |
||
669 | * |
||
670 | * @deprecated use count() instead |
||
671 | */ |
||
672 | public function structSize() |
||
673 | { |
||
674 | $this->logDeprecation('Method ' . __METHOD__ . ' is deprecated'); |
||
675 | |||
676 | return count($this->me['struct']); |
||
677 | } |
||
678 | |||
679 | // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];` |
||
680 | public function &__get($name) |
||
681 | { |
||
682 | switch ($name) { |
||
683 | case 'me': |
||
684 | case 'mytype': |
||
685 | case '_php_class': |
||
686 | $this->logDeprecation('Getting property Value::' . $name . ' is deprecated'); |
||
687 | return $this->$name; |
||
688 | default: |
||
689 | /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... |
||
690 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); |
||
691 | trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); |
||
692 | $result = null; |
||
693 | return $result; |
||
694 | } |
||
695 | } |
||
696 | |||
697 | public function __set($name, $value) |
||
698 | { |
||
699 | switch ($name) { |
||
700 | case 'me': |
||
701 | case 'mytype': |
||
702 | case '_php_class': |
||
703 | $this->logDeprecation('Setting property Value::' . $name . ' is deprecated'); |
||
704 | $this->$name = $value; |
||
705 | break; |
||
706 | default: |
||
707 | /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... |
||
708 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); |
||
709 | trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); |
||
710 | } |
||
711 | } |
||
712 | |||
713 | public function __isset($name) |
||
714 | { |
||
715 | switch ($name) { |
||
716 | case 'me': |
||
717 | case 'mytype': |
||
718 | case '_php_class': |
||
719 | $this->logDeprecation('Checking property Value::' . $name . ' is deprecated'); |
||
720 | return isset($this->$name); |
||
721 | default: |
||
722 | return false; |
||
723 | } |
||
724 | } |
||
725 | |||
726 | public function __unset($name) |
||
727 | { |
||
728 | switch ($name) { |
||
729 | case 'me': |
||
730 | case 'mytype': |
||
731 | case '_php_class': |
||
732 | $this->logDeprecation('Unsetting property Value::' . $name . ' is deprecated'); |
||
733 | unset($this->$name); |
||
734 | break; |
||
735 | default: |
||
736 | /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout... |
||
737 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); |
||
738 | trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING); |
||
739 | } |
||
740 | } |
||
741 | } |
||
742 |