1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.yiiframework.com/ |
4
|
|
|
* @copyright Copyright (c) 2008 Yii Software LLC |
5
|
|
|
* @license http://www.yiiframework.com/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace yii\helpers; |
9
|
|
|
|
10
|
|
|
use yii\base\Arrayable; |
11
|
|
|
use yii\base\InvalidArgumentException; |
12
|
|
|
use yii\web\JsExpression; |
13
|
|
|
use yii\base\Model; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* BaseJson provides concrete implementation for [[Json]]. |
17
|
|
|
* |
18
|
|
|
* Do not use BaseJson. Use [[Json]] instead. |
19
|
|
|
* |
20
|
|
|
* @author Qiang Xue <[email protected]> |
21
|
|
|
* @since 2.0 |
22
|
|
|
*/ |
23
|
|
|
class BaseJson |
24
|
|
|
{ |
25
|
|
|
/** |
26
|
|
|
* List of JSON Error messages assigned to constant names for better handling of version differences. |
27
|
|
|
* @var array |
28
|
|
|
* @since 2.0.7 |
29
|
|
|
*/ |
30
|
|
|
public static $jsonErrorMessages = [ |
31
|
|
|
'JSON_ERROR_DEPTH' => 'The maximum stack depth has been exceeded.', |
32
|
|
|
'JSON_ERROR_STATE_MISMATCH' => 'Invalid or malformed JSON.', |
33
|
|
|
'JSON_ERROR_CTRL_CHAR' => 'Control character error, possibly incorrectly encoded.', |
34
|
|
|
'JSON_ERROR_SYNTAX' => 'Syntax error.', |
35
|
|
|
'JSON_ERROR_UTF8' => 'Malformed UTF-8 characters, possibly incorrectly encoded.', // PHP 5.3.3 |
36
|
|
|
'JSON_ERROR_RECURSION' => 'One or more recursive references in the value to be encoded.', // PHP 5.5.0 |
37
|
|
|
'JSON_ERROR_INF_OR_NAN' => 'One or more NAN or INF values in the value to be encoded', // PHP 5.5.0 |
38
|
|
|
'JSON_ERROR_UNSUPPORTED_TYPE' => 'A value of a type that cannot be encoded was given', // PHP 5.5.0 |
39
|
|
|
]; |
40
|
|
|
|
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Encodes the given value into a JSON string. |
44
|
|
|
* |
45
|
|
|
* The method enhances `json_encode()` by supporting JavaScript expressions. |
46
|
|
|
* In particular, the method will not encode a JavaScript expression that is |
47
|
|
|
* represented in terms of a [[JsExpression]] object. |
48
|
|
|
* |
49
|
|
|
* Note that data encoded as JSON must be UTF-8 encoded according to the JSON specification. |
50
|
|
|
* You must ensure strings passed to this method have proper encoding before passing them. |
51
|
|
|
* |
52
|
|
|
* @param mixed $value the data to be encoded. |
53
|
|
|
* @param int $options the encoding options. For more details please refer to |
54
|
|
|
* <http://www.php.net/manual/en/function.json-encode.php>. Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`. |
55
|
|
|
* @return string the encoding result. |
56
|
|
|
* @throws InvalidArgumentException if there is any encoding error. |
57
|
|
|
*/ |
58
|
38 |
|
public static function encode($value, $options = 320) |
59
|
|
|
{ |
60
|
38 |
|
$expressions = []; |
61
|
38 |
|
$value = static::processData($value, $expressions, uniqid('', true)); |
62
|
38 |
|
set_error_handler(function () { |
63
|
|
|
static::handleJsonError(JSON_ERROR_SYNTAX); |
64
|
38 |
|
}, E_WARNING); |
65
|
38 |
|
$json = json_encode($value, $options); |
66
|
38 |
|
restore_error_handler(); |
67
|
38 |
|
static::handleJsonError(json_last_error()); |
68
|
|
|
|
69
|
37 |
|
return $expressions === [] ? $json : strtr($json, $expressions); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Encodes the given value into a JSON string HTML-escaping entities so it is safe to be embedded in HTML code. |
74
|
|
|
* |
75
|
|
|
* The method enhances `json_encode()` by supporting JavaScript expressions. |
76
|
|
|
* In particular, the method will not encode a JavaScript expression that is |
77
|
|
|
* represented in terms of a [[JsExpression]] object. |
78
|
|
|
* |
79
|
|
|
* Note that data encoded as JSON must be UTF-8 encoded according to the JSON specification. |
80
|
|
|
* You must ensure strings passed to this method have proper encoding before passing them. |
81
|
|
|
* |
82
|
|
|
* @param mixed $value the data to be encoded |
83
|
|
|
* @return string the encoding result |
84
|
|
|
* @since 2.0.4 |
85
|
|
|
* @throws InvalidArgumentException if there is any encoding error |
86
|
|
|
*/ |
87
|
11 |
|
public static function htmlEncode($value) |
88
|
|
|
{ |
89
|
11 |
|
return static::encode($value, JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Decodes the given JSON string into a PHP data structure. |
94
|
|
|
* @param string $json the JSON string to be decoded |
95
|
|
|
* @param bool $asArray whether to return objects in terms of associative arrays. |
96
|
|
|
* @return mixed the PHP data |
97
|
|
|
* @throws InvalidArgumentException if there is any decoding error |
98
|
|
|
*/ |
99
|
15 |
|
public static function decode($json, $asArray = true) |
100
|
|
|
{ |
101
|
15 |
|
if (is_array($json)) { |
102
|
1 |
|
throw new InvalidArgumentException('Invalid JSON data.'); |
103
|
14 |
|
} elseif ($json === null || $json === '') { |
104
|
1 |
|
return null; |
105
|
|
|
} |
106
|
14 |
|
$decode = json_decode((string) $json, $asArray); |
107
|
14 |
|
static::handleJsonError(json_last_error()); |
108
|
|
|
|
109
|
13 |
|
return $decode; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Handles [[encode()]] and [[decode()]] errors by throwing exceptions with the respective error message. |
114
|
|
|
* |
115
|
|
|
* @param int $lastError error code from [json_last_error()](http://php.net/manual/en/function.json-last-error.php). |
116
|
|
|
* @throws \yii\base\InvalidArgumentException if there is any encoding/decoding error. |
117
|
|
|
* @since 2.0.6 |
118
|
|
|
*/ |
119
|
47 |
|
protected static function handleJsonError($lastError) |
120
|
|
|
{ |
121
|
47 |
|
if ($lastError === JSON_ERROR_NONE) { |
122
|
46 |
|
return; |
123
|
|
|
} |
124
|
|
|
|
125
|
2 |
|
$availableErrors = []; |
126
|
2 |
|
foreach (static::$jsonErrorMessages as $const => $message) { |
127
|
2 |
|
if (defined($const)) { |
128
|
2 |
|
$availableErrors[constant($const)] = $message; |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
|
132
|
2 |
|
if (isset($availableErrors[$lastError])) { |
133
|
2 |
|
throw new InvalidArgumentException($availableErrors[$lastError], $lastError); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
throw new InvalidArgumentException('Unknown JSON encoding/decoding error.'); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Pre-processes the data before sending it to `json_encode()`. |
141
|
|
|
* @param mixed $data the data to be processed |
142
|
|
|
* @param array $expressions collection of JavaScript expressions |
143
|
|
|
* @param string $expPrefix a prefix internally used to handle JS expressions |
144
|
|
|
* @return mixed the processed data |
145
|
|
|
*/ |
146
|
38 |
|
protected static function processData($data, &$expressions, $expPrefix) |
147
|
|
|
{ |
148
|
38 |
|
if (is_object($data)) { |
149
|
8 |
|
if ($data instanceof JsExpression) { |
150
|
3 |
|
$token = "!{[$expPrefix=" . count($expressions) . ']}!'; |
151
|
3 |
|
$expressions['"' . $token . '"'] = $data->expression; |
152
|
|
|
|
153
|
3 |
|
return $token; |
154
|
7 |
|
} elseif ($data instanceof \JsonSerializable) { |
|
|
|
|
155
|
2 |
|
return static::processData($data->jsonSerialize(), $expressions, $expPrefix); |
156
|
7 |
|
} elseif ($data instanceof Arrayable) { |
157
|
2 |
|
$data = $data->toArray(); |
158
|
6 |
|
} elseif ($data instanceof \SimpleXMLElement) { |
159
|
1 |
|
$data = (array) $data; |
160
|
|
|
} else { |
161
|
6 |
|
$result = []; |
162
|
6 |
|
foreach ($data as $name => $value) { |
163
|
6 |
|
$result[$name] = $value; |
164
|
|
|
} |
165
|
6 |
|
$data = $result; |
166
|
|
|
} |
167
|
|
|
|
168
|
7 |
|
if ($data === []) { |
169
|
2 |
|
return new \stdClass(); |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
|
173
|
38 |
|
if (is_array($data)) { |
174
|
31 |
|
foreach ($data as $key => $value) { |
175
|
24 |
|
if (is_array($value) || is_object($value)) { |
176
|
24 |
|
$data[$key] = static::processData($value, $expressions, $expPrefix); |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
|
181
|
38 |
|
return $data; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* Generates a summary of the validation errors. |
186
|
|
|
* @param Model|Model[] $models the model(s) whose validation errors are to be displayed. |
187
|
|
|
* @param array $options the tag options in terms of name-value pairs. The following options are specially handled: |
188
|
|
|
* |
189
|
|
|
* - showAllErrors: boolean, if set to true every error message for each attribute will be shown otherwise |
190
|
|
|
* only the first error message for each attribute will be shown. Defaults to `false`. |
191
|
|
|
* |
192
|
|
|
* @return string the generated error summary |
193
|
|
|
* @since 2.0.14 |
194
|
|
|
*/ |
195
|
1 |
|
public static function errorSummary($models, $options = []) |
196
|
|
|
{ |
197
|
1 |
|
$showAllErrors = ArrayHelper::remove($options, 'showAllErrors', false); |
198
|
1 |
|
$lines = self::collectErrors($models, $showAllErrors); |
199
|
|
|
|
200
|
1 |
|
return json_encode($lines); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* Return array of the validation errors |
205
|
|
|
* @param Model|Model[] $models the model(s) whose validation errors are to be displayed. |
206
|
|
|
* @param $showAllErrors boolean, if set to true every error message for each attribute will be shown otherwise |
207
|
|
|
* only the first error message for each attribute will be shown. |
208
|
|
|
* @return array of the validation errors |
209
|
|
|
* @since 2.0.14 |
210
|
|
|
*/ |
211
|
1 |
|
private static function collectErrors($models, $showAllErrors) |
212
|
|
|
{ |
213
|
1 |
|
$lines = []; |
214
|
1 |
|
if (!is_array($models)) { |
215
|
1 |
|
$models = [$models]; |
216
|
|
|
} |
217
|
|
|
|
218
|
1 |
|
foreach ($models as $model) { |
219
|
1 |
|
$lines = array_unique(array_merge($lines, $model->getErrorSummary($showAllErrors))); |
220
|
|
|
} |
221
|
|
|
|
222
|
1 |
|
return $lines; |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.