EmptyKeyEncoding.php 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <?php
  2. namespace Elgg\Json;
  3. /**
  4. * Encode and decode JSON while converting empty string keys to a unique token.
  5. *
  6. * This gets around PHP's limitation of not allowing empty string object property names.
  7. * https://bugs.php.net/bug.php?id=46600
  8. *
  9. * @package Elgg.Core
  10. * @subpackage Json
  11. * @access private
  12. */
  13. class EmptyKeyEncoding {
  14. /**
  15. * @var string
  16. */
  17. protected $token;
  18. /**
  19. * Constructor
  20. *
  21. * @param string $empty_key Optional key to replace "" keys with in JSON decode
  22. */
  23. public function __construct($empty_key = '') {
  24. if (!$empty_key) {
  25. $empty_key = sha1(microtime(true) . mt_rand());
  26. }
  27. $this->token = $empty_key;
  28. }
  29. /**
  30. * Get the key that represents an empty string key in JSON
  31. *
  32. * @return string
  33. */
  34. public function getEmptyKey() {
  35. return $this->token;
  36. }
  37. /**
  38. * Decode JSON while converting empty keys to a unique token.
  39. *
  40. * @param string $json JSON string
  41. * @param bool $assoc Convert objects to assoc arrays?
  42. * @param int $depth Allowed recursion depth
  43. * @param int $options Bitmask json_decode options
  44. *
  45. * @return mixed
  46. * @see json_decode
  47. */
  48. public function decode($json, $assoc = false, $depth = 512, $options = 0) {
  49. // Replace empty keys with the unique token
  50. $json = preg_replace('~([^"\\\\])""\\s*\\:~', "$1\"{$this->token}\":", $json, -1, $count);
  51. return json_decode($json, $assoc, $depth, $options);
  52. }
  53. /**
  54. * Encode JSON while converting unique token keys to empty strings
  55. *
  56. * @param mixed $value Value to encode
  57. * @param int $options Encoding options
  58. * @param int $depth Allowed recursion depth. Do not set this before PHP 5.5
  59. *
  60. * @return string|false
  61. */
  62. public function encode($value, $options = 0, $depth = 512) {
  63. if ($depth == 512) {
  64. // PHP 5.4 and earlier will choke if depth is passed in
  65. $json = json_encode($value, $options);
  66. } else {
  67. $json = json_encode($value, $options, $depth);
  68. }
  69. // Replace unique tokens with empty strings
  70. if (is_string($json)) {
  71. $json = str_replace("\"{$this->token}\"", '""', $json);
  72. }
  73. return $json;
  74. }
  75. }