PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/zendframework/zend-json/src/Json.php

https://gitlab.com/dzakiafif/cokelatklasik
PHP | 383 lines | 196 code | 35 blank | 152 comment | 47 complexity | 9ce5281c1f64a2176f3a2cb65c9fe604 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Json;
  10. use SimpleXMLElement;
  11. use Zend\Json\Exception\RecursionException;
  12. use Zend\Json\Exception\RuntimeException;
  13. use ZendXml\Security as XmlSecurity;
  14. /**
  15. * Class for encoding to and decoding from JSON.
  16. */
  17. class Json
  18. {
  19. /**
  20. * How objects should be encoded -- arrays or as stdClass. TYPE_ARRAY is 1
  21. * so that it is a boolean true value, allowing it to be used with
  22. * ext/json's functions.
  23. */
  24. const TYPE_ARRAY = 1;
  25. const TYPE_OBJECT = 0;
  26. /**
  27. * To check the allowed nesting depth of the XML tree during xml2json conversion.
  28. *
  29. * @var int
  30. */
  31. public static $maxRecursionDepthAllowed=25;
  32. /**
  33. * @var bool
  34. */
  35. public static $useBuiltinEncoderDecoder = false;
  36. /**
  37. * Decodes the given $encodedValue string which is
  38. * encoded in the JSON format
  39. *
  40. * Uses ext/json's json_decode if available.
  41. *
  42. * @param string $encodedValue Encoded in JSON format
  43. * @param int $objectDecodeType Optional; flag indicating how to decode
  44. * objects. See {@link Zend\Json\Decoder::decode()} for details.
  45. * @return mixed
  46. * @throws RuntimeException
  47. */
  48. public static function decode($encodedValue, $objectDecodeType = self::TYPE_OBJECT)
  49. {
  50. $encodedValue = (string) $encodedValue;
  51. if (function_exists('json_decode') && static::$useBuiltinEncoderDecoder !== true) {
  52. $decode = json_decode($encodedValue, $objectDecodeType);
  53. switch (json_last_error()) {
  54. case JSON_ERROR_NONE:
  55. break;
  56. case JSON_ERROR_DEPTH:
  57. throw new RuntimeException('Decoding failed: Maximum stack depth exceeded');
  58. case JSON_ERROR_CTRL_CHAR:
  59. throw new RuntimeException('Decoding failed: Unexpected control character found');
  60. case JSON_ERROR_SYNTAX:
  61. throw new RuntimeException('Decoding failed: Syntax error');
  62. default:
  63. throw new RuntimeException('Decoding failed');
  64. }
  65. return $decode;
  66. }
  67. return Decoder::decode($encodedValue, $objectDecodeType);
  68. }
  69. /**
  70. * Encode the mixed $valueToEncode into the JSON format
  71. *
  72. * Encodes using ext/json's json_encode() if available.
  73. *
  74. * NOTE: Object should not contain cycles; the JSON format
  75. * does not allow object reference.
  76. *
  77. * NOTE: Only public variables will be encoded
  78. *
  79. * NOTE: Encoding native javascript expressions are possible using Zend\Json\Expr.
  80. * You can enable this by setting $options['enableJsonExprFinder'] = true
  81. *
  82. * @see Zend\Json\Expr
  83. *
  84. * @param mixed $valueToEncode
  85. * @param bool $cycleCheck Optional; whether or not to check for object recursion; off by default
  86. * @param array $options Additional options used during encoding
  87. * @return string JSON encoded object
  88. */
  89. public static function encode($valueToEncode, $cycleCheck = false, $options = array())
  90. {
  91. if (is_object($valueToEncode)) {
  92. if (method_exists($valueToEncode, 'toJson')) {
  93. return $valueToEncode->toJson();
  94. } elseif (method_exists($valueToEncode, 'toArray')) {
  95. return static::encode($valueToEncode->toArray(), $cycleCheck, $options);
  96. }
  97. }
  98. // Pre-encoding look for Zend\Json\Expr objects and replacing by tmp ids
  99. $javascriptExpressions = array();
  100. if (isset($options['enableJsonExprFinder'])
  101. && ($options['enableJsonExprFinder'] == true)
  102. ) {
  103. $valueToEncode = static::_recursiveJsonExprFinder($valueToEncode, $javascriptExpressions);
  104. }
  105. // Encoding
  106. if (function_exists('json_encode') && static::$useBuiltinEncoderDecoder !== true) {
  107. $encodedResult = json_encode(
  108. $valueToEncode,
  109. JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
  110. );
  111. } else {
  112. $encodedResult = Encoder::encode($valueToEncode, $cycleCheck, $options);
  113. }
  114. //only do post-processing to revert back the Zend\Json\Expr if any.
  115. if (count($javascriptExpressions) > 0) {
  116. $count = count($javascriptExpressions);
  117. for ($i = 0; $i < $count; $i++) {
  118. $magicKey = $javascriptExpressions[$i]['magicKey'];
  119. $value = $javascriptExpressions[$i]['value'];
  120. $encodedResult = str_replace(
  121. //instead of replacing "key:magicKey", we replace directly magicKey by value because "key" never changes.
  122. '"' . $magicKey . '"',
  123. $value,
  124. $encodedResult
  125. );
  126. }
  127. }
  128. return $encodedResult;
  129. }
  130. /**
  131. * Check & Replace Zend\Json\Expr for tmp ids in the valueToEncode
  132. *
  133. * Check if the value is a Zend\Json\Expr, and if replace its value
  134. * with a magic key and save the javascript expression in an array.
  135. *
  136. * NOTE this method is recursive.
  137. *
  138. * NOTE: This method is used internally by the encode method.
  139. *
  140. * @see encode
  141. * @param mixed $value a string - object property to be encoded
  142. * @param array $javascriptExpressions
  143. * @param null|string|int $currentKey
  144. * @return mixed
  145. */
  146. protected static function _recursiveJsonExprFinder(
  147. &$value, array &$javascriptExpressions, $currentKey = null
  148. ) {
  149. if ($value instanceof Expr) {
  150. // TODO: Optimize with ascii keys, if performance is bad
  151. $magicKey = "____" . $currentKey . "_" . (count($javascriptExpressions));
  152. $javascriptExpressions[] = array(
  153. //if currentKey is integer, encodeUnicodeString call is not required.
  154. "magicKey" => (is_int($currentKey)) ? $magicKey : Encoder::encodeUnicodeString($magicKey),
  155. "value" => $value->__toString(),
  156. );
  157. $value = $magicKey;
  158. } elseif (is_array($value)) {
  159. foreach ($value as $k => $v) {
  160. $value[$k] = static::_recursiveJsonExprFinder($value[$k], $javascriptExpressions, $k);
  161. }
  162. } elseif (is_object($value)) {
  163. foreach ($value as $k => $v) {
  164. $value->$k = static::_recursiveJsonExprFinder($value->$k, $javascriptExpressions, $k);
  165. }
  166. }
  167. return $value;
  168. }
  169. /**
  170. * Return the value of an XML attribute text or the text between
  171. * the XML tags
  172. *
  173. * In order to allow Zend\Json\Expr from xml, we check if the node
  174. * matches the pattern that try to detect if it is a new Zend\Json\Expr
  175. * if it matches, we return a new Zend\Json\Expr instead of a text node
  176. *
  177. * @param SimpleXMLElement $simpleXmlElementObject
  178. * @return Expr|string
  179. */
  180. protected static function _getXmlValue($simpleXmlElementObject)
  181. {
  182. $pattern = '/^[\s]*new Zend[_\\]Json[_\\]Expr[\s]*\([\s]*[\"\']{1}(.*)[\"\']{1}[\s]*\)[\s]*$/';
  183. $matchings = array();
  184. $match = preg_match($pattern, $simpleXmlElementObject, $matchings);
  185. if ($match) {
  186. return new Expr($matchings[1]);
  187. }
  188. return (trim(strval($simpleXmlElementObject)));
  189. }
  190. /**
  191. * _processXml - Contains the logic for xml2json
  192. *
  193. * The logic in this function is a recursive one.
  194. *
  195. * The main caller of this function (i.e. fromXml) needs to provide
  196. * only the first two parameters i.e. the SimpleXMLElement object and
  197. * the flag for ignoring or not ignoring XML attributes. The third parameter
  198. * will be used internally within this function during the recursive calls.
  199. *
  200. * This function converts the SimpleXMLElement object into a PHP array by
  201. * calling a recursive (protected static) function in this class. Once all
  202. * the XML elements are stored in the PHP array, it is returned to the caller.
  203. *
  204. * @param SimpleXMLElement $simpleXmlElementObject
  205. * @param bool $ignoreXmlAttributes
  206. * @param integer $recursionDepth
  207. * @throws Exception\RecursionException if the XML tree is deeper than the allowed limit.
  208. * @return array
  209. */
  210. protected static function _processXml($simpleXmlElementObject, $ignoreXmlAttributes, $recursionDepth = 0)
  211. {
  212. // Keep an eye on how deeply we are involved in recursion.
  213. if ($recursionDepth > static::$maxRecursionDepthAllowed) {
  214. // XML tree is too deep. Exit now by throwing an exception.
  215. throw new RecursionException(
  216. "Function _processXml exceeded the allowed recursion depth of "
  217. . static::$maxRecursionDepthAllowed
  218. );
  219. }
  220. $children = $simpleXmlElementObject->children();
  221. $name = $simpleXmlElementObject->getName();
  222. $value = static::_getXmlValue($simpleXmlElementObject);
  223. $attributes = (array) $simpleXmlElementObject->attributes();
  224. if (!count($children)) {
  225. if (!empty($attributes) && !$ignoreXmlAttributes) {
  226. foreach ($attributes['@attributes'] as $k => $v) {
  227. $attributes['@attributes'][$k] = static::_getXmlValue($v);
  228. }
  229. if (!empty($value)) {
  230. $attributes['@text'] = $value;
  231. }
  232. return array($name => $attributes);
  233. }
  234. return array($name => $value);
  235. }
  236. $childArray = array();
  237. foreach ($children as $child) {
  238. $childname = $child->getName();
  239. $element = static::_processXml($child, $ignoreXmlAttributes, $recursionDepth + 1);
  240. if (array_key_exists($childname, $childArray)) {
  241. if (empty($subChild[$childname])) {
  242. $childArray[$childname] = array($childArray[$childname]);
  243. $subChild[$childname] = true;
  244. }
  245. $childArray[$childname][] = $element[$childname];
  246. } else {
  247. $childArray[$childname] = $element[$childname];
  248. }
  249. }
  250. if (!empty($attributes) && !$ignoreXmlAttributes) {
  251. foreach ($attributes['@attributes'] as $k => $v) {
  252. $attributes['@attributes'][$k] = static::_getXmlValue($v);
  253. }
  254. $childArray['@attributes'] = $attributes['@attributes'];
  255. }
  256. if (!empty($value)) {
  257. $childArray['@text'] = $value;
  258. }
  259. return array($name => $childArray);
  260. }
  261. /**
  262. * fromXml - Converts XML to JSON
  263. *
  264. * Converts a XML formatted string into a JSON formatted string.
  265. * The value returned will be a string in JSON format.
  266. *
  267. * The caller of this function needs to provide only the first parameter,
  268. * which is an XML formatted String. The second parameter is optional, which
  269. * lets the user to select if the XML attributes in the input XML string
  270. * should be included or ignored in xml2json conversion.
  271. *
  272. * This function converts the XML formatted string into a PHP array by
  273. * calling a recursive (protected static) function in this class. Then, it
  274. * converts that PHP array into JSON by calling the "encode" static function.
  275. *
  276. * NOTE: Encoding native javascript expressions via Zend\Json\Expr is not possible.
  277. *
  278. * @static
  279. * @access public
  280. * @param string $xmlStringContents XML String to be converted
  281. * @param bool $ignoreXmlAttributes Include or exclude XML attributes in
  282. * the xml2json conversion process.
  283. * @return mixed - JSON formatted string on success
  284. * @throws \Zend\Json\Exception\RuntimeException if the input not a XML formatted string
  285. */
  286. public static function fromXml($xmlStringContents, $ignoreXmlAttributes = true)
  287. {
  288. // Load the XML formatted string into a Simple XML Element object.
  289. $simpleXmlElementObject = XmlSecurity::scan($xmlStringContents);
  290. // If it is not a valid XML content, throw an exception.
  291. if (!$simpleXmlElementObject) {
  292. throw new RuntimeException('Function fromXml was called with an invalid XML formatted string.');
  293. } // End of if ($simpleXmlElementObject == null)
  294. $resultArray = null;
  295. // Call the recursive function to convert the XML into a PHP array.
  296. $resultArray = static::_processXml($simpleXmlElementObject, $ignoreXmlAttributes);
  297. // Convert the PHP array to JSON using Zend\Json\Json encode method.
  298. // It is just that simple.
  299. $jsonStringOutput = static::encode($resultArray);
  300. return($jsonStringOutput);
  301. }
  302. /**
  303. * Pretty-print JSON string
  304. *
  305. * Use 'indent' option to select indentation string - by default it's a tab
  306. *
  307. * @param string $json Original JSON string
  308. * @param array $options Encoding options
  309. * @return string
  310. */
  311. public static function prettyPrint($json, $options = array())
  312. {
  313. $tokens = preg_split('|([\{\}\]\[,])|', $json, -1, PREG_SPLIT_DELIM_CAPTURE);
  314. $result = "";
  315. $indent = 0;
  316. $ind = "\t";
  317. if (isset($options['indent'])) {
  318. $ind = $options['indent'];
  319. }
  320. $inLiteral = false;
  321. foreach ($tokens as $token) {
  322. if ($token == "") continue;
  323. $prefix = str_repeat($ind, $indent);
  324. if (!$inLiteral && ($token == "{" || $token == "[")) {
  325. $indent++;
  326. if ($result != "" && $result[strlen($result)-1] == "\n") {
  327. $result .= $prefix;
  328. }
  329. $result .= "$token\n";
  330. } elseif (!$inLiteral && ($token == "}" || $token == "]")) {
  331. $indent--;
  332. $prefix = str_repeat($ind, $indent);
  333. $result .= "\n$prefix$token";
  334. } elseif (!$inLiteral && $token == ",") {
  335. $result .= "$token\n";
  336. } else {
  337. $result .= ($inLiteral ? '' : $prefix) . $token;
  338. // Count # of unescaped double-quotes in token, subtract # of
  339. // escaped double-quotes and if the result is odd then we are
  340. // inside a string literal
  341. if ((substr_count($token, "\"")-substr_count($token, "\\\"")) % 2 != 0) {
  342. $inLiteral = !$inLiteral;
  343. }
  344. }
  345. }
  346. return $result;
  347. }
  348. }