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}>"; |
|
|
|
|
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
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.