gggeek /
phpxmlrpc
| 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[(string)$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
Loading history...
|
|||
| 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((float)$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 |