1<?php
2
3/**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7
8declare(strict_types=1);
9
10namespace Nette\Utils;
11
12use Nette;
13
14
15/**
16 * JSON encoder and decoder.
17 */
18final class Json
19{
20	use Nette\StaticClass;
21
22	/** @deprecated use Json::decode(..., forceArrays: true) */
23	public const FORCE_ARRAY = JSON_OBJECT_AS_ARRAY;
24
25	/** @deprecated use Json::encode(..., pretty: true) */
26	public const PRETTY = JSON_PRETTY_PRINT;
27
28	/** @deprecated use Json::encode(..., asciiSafe: true) */
29	public const ESCAPE_UNICODE = 1 << 19;
30
31
32	/**
33	 * Converts value to JSON format. Use $pretty for easier reading and clarity, $asciiSafe for ASCII output
34	 * and $htmlSafe for HTML escaping, $forceObjects enforces the encoding of non-associateve arrays as objects.
35	 * @throws JsonException
36	 */
37	public static function encode(
38		mixed $value,
39		bool|int $pretty = false,
40		bool $asciiSafe = false,
41		bool $htmlSafe = false,
42		bool $forceObjects = false,
43	): string
44	{
45		if (is_int($pretty)) { // back compatibility
46			$flags = ($pretty & self::ESCAPE_UNICODE ? 0 : JSON_UNESCAPED_UNICODE) | ($pretty & ~self::ESCAPE_UNICODE);
47		} else {
48			$flags = ($asciiSafe ? 0 : JSON_UNESCAPED_UNICODE)
49				| ($pretty ? JSON_PRETTY_PRINT : 0)
50				| ($forceObjects ? JSON_FORCE_OBJECT : 0)
51				| ($htmlSafe ? JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG : 0);
52		}
53
54		$flags |= JSON_UNESCAPED_SLASHES
55			| (defined('JSON_PRESERVE_ZERO_FRACTION') ? JSON_PRESERVE_ZERO_FRACTION : 0); // since PHP 5.6.6 & PECL JSON-C 1.3.7
56
57		$json = json_encode($value, $flags);
58		if ($error = json_last_error()) {
59			throw new JsonException(json_last_error_msg(), $error);
60		}
61
62		return $json;
63	}
64
65
66	/**
67	 * Parses JSON to PHP value. The $forceArrays enforces the decoding of objects as arrays.
68	 * @throws JsonException
69	 */
70	public static function decode(string $json, bool|int $forceArrays = false): mixed
71	{
72		$flags = is_int($forceArrays) // back compatibility
73			? $forceArrays
74			: ($forceArrays ? JSON_OBJECT_AS_ARRAY : 0);
75		$flags |= JSON_BIGINT_AS_STRING;
76
77		$value = json_decode($json, flags: $flags);
78		if ($error = json_last_error()) {
79			throw new JsonException(json_last_error_msg(), $error);
80		}
81
82		return $value;
83	}
84}
85