BaseJson.php
5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\helpers;
use yii\base\InvalidParamException;
use yii\base\Arrayable;
use yii\web\JsExpression;
/**
* BaseJson provides concrete implementation for [[Json]].
*
* Do not use BaseJson. Use [[Json]] instead.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class BaseJson
{
/**
* Encodes the given value into a JSON string.
* The method enhances `json_encode()` by supporting JavaScript expressions.
* In particular, the method will not encode a JavaScript expression that is
* represented in terms of a [[JsExpression]] object.
* @param mixed $value the data to be encoded.
* @param integer $options the encoding options. For more details please refer to
* <http://www.php.net/manual/en/function.json-encode.php>. Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`.
* @return string the encoding result.
* @throws InvalidParamException if there is any encoding error.
*/
public static function encode($value, $options = 320)
{
$expressions = [];
$value = static::processData($value, $expressions, uniqid('', false));
$json = json_encode($value, $options);
static::handleJsonError(json_last_error());
return $expressions === [] ? $json : strtr($json, $expressions);
}
/**
* Encodes the given value into a JSON string HTML-escaping entities so it is safe to be embedded in HTML code.
* The method enhances `json_encode()` by supporting JavaScript expressions.
* In particular, the method will not encode a JavaScript expression that is
* represented in terms of a [[JsExpression]] object.
*
* @param mixed $value the data to be encoded
* @return string the encoding result
* @since 2.0.4
* @throws InvalidParamException if there is any encoding error
*/
public static function htmlEncode($value)
{
return static::encode($value, JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS);
}
/**
* Decodes the given JSON string into a PHP data structure.
* @param string $json the JSON string to be decoded
* @param boolean $asArray whether to return objects in terms of associative arrays.
* @return mixed the PHP data
* @throws InvalidParamException if there is any decoding error
*/
public static function decode($json, $asArray = true)
{
if (is_array($json)) {
throw new InvalidParamException('Invalid JSON data.');
}
$decode = json_decode((string) $json, $asArray);
static::handleJsonError(json_last_error());
return $decode;
}
/**
* Handles [[encode()]] and [[decode()]] errors by throwing exceptions with the respective error message.
*
* @param integer $lastError error code from [json_last_error()](http://php.net/manual/en/function.json-last-error.php).
* @throws \yii\base\InvalidParamException if there is any encoding/decoding error.
* @since 2.0.6
*/
protected static function handleJsonError($lastError)
{
switch ($lastError) {
case JSON_ERROR_NONE:
break;
case JSON_ERROR_DEPTH:
throw new InvalidParamException('The maximum stack depth has been exceeded.');
case JSON_ERROR_CTRL_CHAR:
throw new InvalidParamException('Control character error, possibly incorrectly encoded.');
case JSON_ERROR_SYNTAX:
throw new InvalidParamException('Syntax error.');
case JSON_ERROR_STATE_MISMATCH:
throw new InvalidParamException('Invalid or malformed JSON.');
case JSON_ERROR_UTF8:
throw new InvalidParamException('Malformed UTF-8 characters, possibly incorrectly encoded.');
default:
throw new InvalidParamException('Unknown JSON decoding error.');
}
}
/**
* Pre-processes the data before sending it to `json_encode()`.
* @param mixed $data the data to be processed
* @param array $expressions collection of JavaScript expressions
* @param string $expPrefix a prefix internally used to handle JS expressions
* @return mixed the processed data
*/
protected static function processData($data, &$expressions, $expPrefix)
{
if (is_object($data)) {
if ($data instanceof JsExpression) {
$token = "!{[$expPrefix=" . count($expressions) . ']}!';
$expressions['"' . $token . '"'] = $data->expression;
return $token;
} elseif ($data instanceof \JsonSerializable) {
$data = $data->jsonSerialize();
} elseif ($data instanceof Arrayable) {
$data = $data->toArray();
} else {
$result = [];
foreach ($data as $name => $value) {
$result[$name] = $value;
}
$data = $result;
}
if ($data === []) {
return new \stdClass();
}
}
if (is_array($data)) {
foreach ($data as $key => $value) {
if (is_array($value) || is_object($value)) {
$data[$key] = static::processData($value, $expressions, $expPrefix);
}
}
}
return $data;
}
}