This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace CMPayments\JsonLint; |
||
2 | |||
3 | use CMPayments\JsonLint\Exceptions\DuplicateKeyException; |
||
4 | use CMPayments\JsonLint\Exceptions\ParseException; |
||
5 | use CMPayments\JsonLint\Exceptions\UndefinedException; |
||
6 | use stdClass; |
||
7 | |||
8 | /** |
||
9 | * Class JsonParser |
||
10 | * |
||
11 | * @package CMPayments\JsonLint |
||
12 | */ |
||
13 | class JsonLinter |
||
14 | { |
||
15 | const DETECT_KEY_CONFLICTS = 1; |
||
16 | const ALLOW_DUPLICATE_KEYS = 2; |
||
17 | const PARSE_TO_ASSOC = 4; |
||
18 | |||
19 | /** |
||
20 | * @var |
||
21 | */ |
||
22 | private $lexer; |
||
23 | |||
24 | /** |
||
25 | * @var |
||
26 | */ |
||
27 | private $flags; |
||
28 | |||
29 | /** |
||
30 | * @var |
||
31 | */ |
||
32 | private $stack; |
||
33 | |||
34 | /** |
||
35 | * @var |
||
36 | */ |
||
37 | private $vStack; // semantic value stack |
||
38 | |||
39 | /** |
||
40 | * @var |
||
41 | */ |
||
42 | private $lStack; // location stack |
||
43 | |||
44 | /** |
||
45 | * @var array |
||
46 | */ |
||
47 | private $symbols = [ |
||
48 | 'error' => 2, |
||
49 | 'JSONString' => 3, |
||
50 | 'STRING' => 4, |
||
51 | 'JSONNumber' => 5, |
||
52 | 'NUMBER' => 6, |
||
53 | 'JSONNullLiteral' => 7, |
||
54 | 'NULL' => 8, |
||
55 | 'JSONBooleanLiteral' => 9, |
||
56 | 'TRUE' => 10, |
||
57 | 'FALSE' => 11, |
||
58 | 'JSONText' => 12, |
||
59 | 'JSONValue' => 13, |
||
60 | 'EOF' => 14, |
||
61 | 'JSONObject' => 15, |
||
62 | 'JSONArray' => 16, |
||
63 | '{' => 17, |
||
64 | '}' => 18, |
||
65 | 'JSONMemberList' => 19, |
||
66 | 'JSONMember' => 20, |
||
67 | ':' => 21, |
||
68 | ',' => 22, |
||
69 | '[' => 23, |
||
70 | ']' => 24, |
||
71 | 'JSONElementList' => 25, |
||
72 | '$accept' => 0, |
||
73 | '$end' => 1 |
||
74 | ]; |
||
75 | |||
76 | /** |
||
77 | * @var array |
||
78 | */ |
||
79 | private $terminals = [2 => "error", 4 => "STRING", 6 => "NUMBER", 8 => "NULL", 10 => "TRUE", 11 => "FALSE", 14 => "EOF", 17 => "{", 18 => "}", 21 => ":", 22 => ",", 23 => "[", 24 => "]"]; |
||
80 | |||
81 | /** |
||
82 | * @var array |
||
83 | */ |
||
84 | private $productions = [0, [3, 1], [5, 1], [7, 1], [9, 1], [9, 1], [12, 2], [13, 1], [13, 1], [13, 1], [13, 1], [13, 1], [13, 1], [15, 2], [15, 3], [20, 3], [19, 1], [19, 3], [16, 2], [16, 3], [25, 1], [25, 3]]; |
||
85 | |||
86 | /** |
||
87 | * @var array |
||
88 | */ |
||
89 | private $table = [ |
||
90 | [3 => 5, 4 => [1, 12], 5 => 6, 6 => [1, 13], 7 => 3, 8 => [1, 9], 9 => 4, 10 => [1, 10], 11 => [1, 11], 12 => 1, 13 => 2, 15 => 7, 16 => 8, 17 => [1, 14], 23 => [1, 15]], |
||
91 | [1 => [3]], |
||
92 | [14 => [1, 16]], |
||
93 | [14 => [2, 7], 18 => [2, 7], 22 => [2, 7], 24 => [2, 7]], |
||
94 | [14 => [2, 8], 18 => [2, 8], 22 => [2, 8], 24 => [2, 8]], |
||
95 | [14 => [2, 9], 18 => [2, 9], 22 => [2, 9], 24 => [2, 9]], |
||
96 | [14 => [2, 10], 18 => [2, 10], 22 => [2, 10], 24 => [2, 10]], |
||
97 | [14 => [2, 11], 18 => [2, 11], 22 => [2, 11], 24 => [2, 11]], |
||
98 | [14 => [2, 12], 18 => [2, 12], 22 => [2, 12], 24 => [2, 12]], |
||
99 | [14 => [2, 3], 18 => [2, 3], 22 => [2, 3], 24 => [2, 3]], |
||
100 | [14 => [2, 4], 18 => [2, 4], 22 => [2, 4], 24 => [2, 4]], |
||
101 | [14 => [2, 5], 18 => [2, 5], 22 => [2, 5], 24 => [2, 5]], |
||
102 | [14 => [2, 1], 18 => [2, 1], 21 => [2, 1], 22 => [2, 1], 24 => [2, 1]], |
||
103 | [14 => [2, 2], 18 => [2, 2], 22 => [2, 2], 24 => [2, 2]], |
||
104 | [3 => 20, 4 => [1, 12], 18 => [1, 17], 19 => 18, 20 => 19], |
||
105 | [3 => 5, 4 => [1, 12], 5 => 6, 6 => [1, 13], 7 => 3, 8 => [1, 9], 9 => 4, 10 => [1, 10], 11 => [1, 11], 13 => 23, 15 => 7, 16 => 8, 17 => [1, 14], 23 => [1, 15], 24 => [1, 21], 25 => 22], |
||
106 | [1 => [2, 6]], |
||
107 | [14 => [2, 13], 18 => [2, 13], 22 => [2, 13], 24 => [2, 13]], |
||
108 | [18 => [1, 24], 22 => [1, 25]], |
||
109 | [18 => [2, 16], 22 => [2, 16]], |
||
110 | [21 => [1, 26]], |
||
111 | [14 => [2, 18], 18 => [2, 18], 22 => [2, 18], 24 => [2, 18]], |
||
112 | [22 => [1, 28], 24 => [1, 27]], |
||
113 | [22 => [2, 20], 24 => [2, 20]], |
||
114 | [14 => [2, 14], 18 => [2, 14], 22 => [2, 14], 24 => [2, 14]], |
||
115 | [3 => 20, 4 => [1, 12], 20 => 29], |
||
116 | [3 => 5, 4 => [1, 12], 5 => 6, 6 => [1, 13], 7 => 3, 8 => [1, 9], 9 => 4, 10 => [1, 10], 11 => [1, 11], 13 => 30, 15 => 7, 16 => 8, 17 => [1, 14], 23 => [1, 15]], |
||
117 | [14 => [2, 19], 18 => [2, 19], 22 => [2, 19], 24 => [2, 19]], |
||
118 | [3 => 5, 4 => [1, 12], 5 => 6, 6 => [1, 13], 7 => 3, 8 => [1, 9], 9 => 4, 10 => [1, 10], 11 => [1, 11], 13 => 31, 15 => 7, 16 => 8, 17 => [1, 14], 23 => [1, 15]], |
||
119 | [18 => [2, 17], 22 => [2, 17]], |
||
120 | [18 => [2, 15], 22 => [2, 15]], |
||
121 | [22 => [2, 21], 24 => [2, 21]] |
||
122 | ]; |
||
123 | |||
124 | /** |
||
125 | * @var array |
||
126 | */ |
||
127 | private $defaultActions = [16 => [2, 6]]; |
||
128 | |||
129 | /** |
||
130 | * @param string $input JSON string |
||
131 | * @param int $flags |
||
132 | * |
||
133 | * @return boolean|ParseException null if no error is found, a ParseException containing all details otherwise |
||
134 | */ |
||
135 | public function lint($input, $flags = 0) |
||
136 | { |
||
137 | try { |
||
138 | |||
139 | $this->parse($input, $flags); |
||
140 | } catch (\Exception $e) { |
||
141 | |||
142 | return $e; |
||
143 | } |
||
144 | |||
145 | return null; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * @param string $input |
||
150 | * @param int $flags |
||
151 | * |
||
152 | * @return bool |
||
153 | * @throws DuplicateKeyException |
||
154 | * @throws ParseException |
||
155 | * @throws null |
||
156 | */ |
||
157 | public function parse($input, $flags = 0) |
||
158 | { |
||
159 | $this->lexer = new Lexer(); |
||
160 | $this->lexer->setInput($input); |
||
161 | |||
162 | if (!is_string($input)) { |
||
163 | |||
164 | $e = new ParseException(ParseException::ERROR_NOT_A_STRING, [gettype($input)]); |
||
165 | |||
166 | // we +1 the line number on which an error occurred to make it human readable |
||
167 | $e->setJsonLineNo(($this->lexer->yLineNo + 1)); |
||
168 | |||
169 | throw $e; |
||
170 | } |
||
171 | |||
172 | $this->failOnBOM($input); |
||
173 | |||
174 | $this->flags = $flags; |
||
175 | |||
176 | $this->stack = [0]; |
||
177 | $this->vStack = [null]; |
||
178 | $this->lStack = []; |
||
179 | |||
180 | $yText = ''; |
||
181 | $yLineNo = $recovering = 0; |
||
182 | $eof = 1; |
||
183 | $terror = 2; |
||
184 | |||
185 | $yLocation = $this->lexer->yLocation; |
||
186 | $this->lStack[] = $yLocation; |
||
187 | |||
188 | $symbol = $preErrorSymbol = $p = null; |
||
189 | $yVal = new stdClass; |
||
190 | |||
191 | $isMultiLine = count(explode("\n", str_replace("\n\r", "\n", $input))) > 1; |
||
192 | |||
193 | while (true) { |
||
194 | |||
195 | // retrieve state number from top of stack |
||
196 | $state = $this->stack[count($this->stack) - 1]; |
||
197 | |||
198 | // use default actions if available |
||
199 | if (isset($this->defaultActions[$state])) { |
||
200 | |||
201 | $action = $this->defaultActions[$state]; |
||
202 | } else { |
||
203 | |||
204 | if ($symbol === null) { |
||
205 | |||
206 | $symbol = $this->lex(); |
||
207 | } |
||
208 | |||
209 | // read action for current state and first input |
||
210 | $action = isset($this->table[$state][$symbol]) ? $this->table[$state][$symbol] : false; |
||
211 | } |
||
212 | |||
213 | // handle parse error |
||
214 | if (!$action || !$action[0]) { |
||
215 | |||
216 | $e = null; |
||
217 | |||
218 | if (!$recovering) { |
||
219 | |||
220 | // Report error |
||
221 | $expected = []; |
||
222 | |||
223 | foreach ($this->table[$state] as $p => $ignore) { |
||
224 | |||
225 | if (isset($this->terminals[$p]) && $p > 2) { |
||
226 | |||
227 | $expected[] = $this->terminals[$p]; |
||
228 | } |
||
229 | } |
||
230 | |||
231 | if (in_array("STRING", $expected) && in_array(substr($this->lexer->yText, 0, 1), ['"', "'"])) { |
||
232 | |||
233 | if (substr($this->lexer->yText, 0, 1) === "'") { |
||
234 | |||
235 | $e = new ParseException(ParseException::ERROR_USED_SINGLE_QUOTES, array_merge(['match' => $this->lexer->match], $this->getExceptionArguments($symbol))); |
||
236 | } elseif (preg_match('{".+?(\\\\[^"bfnrt/\\\\u])}', $this->lexer->getUpcomingInput())) { |
||
237 | |||
238 | $e = new ParseException(ParseException::ERROR_UNESCAPED_BACKSLASH, array_merge(['match' => $this->lexer->match], $this->getExceptionArguments($symbol))); |
||
239 | } elseif (preg_match('{"(?:[^"]+|\\\\")*$}m', $this->lexer->getUpcomingInput())) { |
||
240 | |||
241 | $e = new ParseException(ParseException::ERROR_NOT_TERMINATED_OR_MULTI_LINE, array_merge(['match' => $this->lexer->match], $this->getExceptionArguments($symbol))); |
||
242 | } else { |
||
243 | |||
244 | $e = new ParseException(ParseException::ERROR_INVALID_STRING, $this->getExceptionArguments($symbol)); |
||
245 | } |
||
246 | } |
||
247 | |||
248 | if (is_null($e)) { |
||
249 | |||
250 | $e = new ParseException(ParseException::ERROR_EXPECTED_INPUT_TO_BE_SOMETHING_ELSE, array_merge( |
||
251 | [ |
||
252 | ((count($expected) > 1) ? ' one of' : ''), |
||
253 | implode('\', \'', $expected), |
||
254 | utf8_encode($this->lexer->match) // encode any special characters that might be entered by the user |
||
255 | ], $this->getExceptionArguments($symbol) |
||
256 | )); |
||
257 | } |
||
258 | |||
259 | if (substr(trim($this->lexer->getPastInput()), -1) === ',') { |
||
260 | |||
261 | $e->appendMessage($e->getItemFromVariableArray(ParseException::ERROR_APPEND_TRAILING_COMMA_ERROR)); |
||
262 | |||
263 | // usually we +1 the line number on which an error occurred to make it human readable |
||
264 | // BUT when it involves a trailing comma the error is located on the line above the current one |
||
265 | // IF however the $input IS multi line, we do NOT increase the line number |
||
266 | $e->setJsonLineNo((($isMultiLine) ? $this->lexer->yLineNo : ($this->lexer->yLineNo + 1))); |
||
267 | } else { |
||
268 | |||
269 | // we +1 the line number on which an error occurred to make it human readable |
||
270 | $e->setJsonLineNo(($this->lexer->yLineNo + 1)); |
||
271 | } |
||
272 | |||
273 | $e->setJsonMatch($this->lexer->match); |
||
274 | $e->setJsonToken((!empty($this->terminals[$symbol]) ? $this->terminals[$symbol] : $symbol)); |
||
275 | $e->setJsonColumnNo($this->lexer->yColumnNo); |
||
276 | $e->setJsonExpected($expected); |
||
277 | |||
278 | throw $e; |
||
279 | } |
||
280 | |||
281 | // just recovered from another error |
||
282 | if ($recovering == 3) { |
||
283 | |||
284 | if ($symbol == $eof) { |
||
285 | |||
286 | if (is_null($e)) { |
||
287 | |||
288 | throw new ParseException(ParseException::ERROR_PARSING_HALTED); |
||
289 | } |
||
290 | } |
||
291 | |||
292 | // discard current lookahead and grab another |
||
293 | $yText = $this->lexer->yText; |
||
294 | $yLineNo = $this->lexer->yLineNo; |
||
295 | $symbol = $this->lex(); |
||
296 | } |
||
297 | |||
298 | // try to recover from error |
||
299 | while (true) { |
||
300 | |||
301 | // check for error recovery rule in this state |
||
302 | if (array_key_exists($terror, $this->table[$state])) { |
||
303 | |||
304 | break; |
||
305 | } |
||
306 | |||
307 | if ($state == 0) { |
||
308 | |||
309 | if (is_null($e)) { |
||
310 | |||
311 | throw new ParseException(ParseException::ERROR_PARSING_HALTED); |
||
312 | } |
||
313 | } |
||
314 | |||
315 | $this->popStack(1); |
||
316 | $state = $this->stack[count($this->stack) - 1]; |
||
317 | } |
||
318 | |||
319 | // save the lookahead token |
||
320 | $preErrorSymbol = $symbol; |
||
321 | |||
322 | // insert generic error symbol as new lookahead |
||
323 | $symbol = $terror; |
||
324 | |||
325 | // allow 3 real symbols to be shifted before reporting a new error |
||
326 | $recovering = 3; |
||
327 | $state = $this->stack[count($this->stack) - 1]; |
||
328 | $action = isset($this->table[$state][$terror]) ? $this->table[$state][$terror] : false; |
||
329 | } |
||
330 | |||
331 | // this shouldn't happen, unless resolve defaults are off |
||
332 | if (is_array($action[0]) && is_array($action) && count($action) > 1) { |
||
333 | |||
334 | throw new ParseException(ParseException::ERROR_PARSING_ERROR_MULTIPLE_ACTIONS, [$state, $symbol]); |
||
335 | } |
||
336 | |||
337 | switch ($action[0]) { |
||
338 | |||
339 | // shift |
||
340 | case 1: |
||
341 | $this->stack[] = $symbol; |
||
342 | $this->vStack[] = $this->lexer->yText; |
||
343 | $this->lStack[] = $this->lexer->yLocation; |
||
344 | $this->stack[] = $action[1]; // push state |
||
345 | $symbol = null; |
||
346 | |||
347 | // normal execution/no error |
||
348 | if ($preErrorSymbol === null) { |
||
349 | |||
350 | $yText = $this->lexer->yText; |
||
351 | $yLineNo = $this->lexer->yLineNo; |
||
352 | |||
353 | if ($recovering > 0) { |
||
354 | |||
355 | $recovering--; |
||
356 | } |
||
357 | } else { |
||
358 | |||
359 | // error just occurred, resume old lookahead f/ before error |
||
360 | $symbol = $preErrorSymbol; |
||
361 | $preErrorSymbol = null; |
||
362 | } |
||
363 | break; |
||
364 | |||
365 | // reduce |
||
366 | case 2: |
||
367 | $len = $this->productions[$action[1]][1]; |
||
368 | |||
369 | // perform semantic action |
||
370 | $yVal->token = $this->vStack[count($this->vStack) - $len]; |
||
371 | |||
372 | // default location, uses first token for firsts, last for lasts |
||
373 | $yVal->store = [ |
||
374 | 'last_line' => $this->lStack[count($this->lStack) - 1]['last_line'], |
||
375 | 'last_column' => $this->lStack[count($this->lStack) - 1]['last_column'], |
||
376 | ]; |
||
377 | |||
378 | $result = $this->performAction($yVal, $yText, $yLineNo, $action[1], $this->vStack); |
||
379 | |||
380 | if (!$result instanceof UndefinedException) { |
||
381 | |||
382 | return $result; |
||
383 | } |
||
384 | |||
385 | if ($len) { |
||
386 | |||
387 | $this->popStack($len); |
||
388 | } |
||
389 | |||
390 | // push non terminal (reduce) |
||
391 | $this->stack[] = $this->productions[$action[1]][0]; |
||
392 | $this->vStack[] = $yVal->token; |
||
393 | $this->lStack[] = $yVal->store; |
||
394 | $newState = $this->table[$this->stack[count($this->stack) - 2]][$this->stack[count($this->stack) - 1]]; |
||
395 | $this->stack[] = $newState; |
||
396 | break; |
||
397 | |||
398 | // accept |
||
399 | case 3: |
||
0 ignored issues
–
show
|
|||
400 | |||
401 | return true; |
||
402 | } |
||
403 | } |
||
404 | |||
405 | return true; |
||
406 | } |
||
407 | |||
408 | /** |
||
409 | * @param null|string $symbol |
||
410 | * |
||
411 | * @return array |
||
412 | */ |
||
413 | private function getExceptionArguments($symbol = null) |
||
414 | { |
||
415 | $arr = [ |
||
416 | 'lineNo' => ($this->lexer->yLineNo + 1), |
||
417 | 'columnNo' => $this->lexer->yColumnNo, |
||
418 | 'match' => $this->lexer->match |
||
419 | ]; |
||
420 | |||
421 | if (!is_null($symbol)) { |
||
422 | |||
423 | $arr['token'] = (!empty($this->terminals[$symbol]) ? $this->terminals[$symbol] : $symbol); |
||
424 | } |
||
425 | |||
426 | return $arr; |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * @param stdClass $yVal |
||
431 | * @param string $yText |
||
432 | * @param int $yLineNo |
||
433 | * @param int $yState |
||
434 | * @param array $tokens |
||
435 | * |
||
436 | * @return UndefinedException |
||
437 | * @throws DuplicateKeyException |
||
438 | */ |
||
439 | private function performAction(stdClass $yVal, $yText, $yLineNo, $yState, &$tokens) |
||
440 | { |
||
441 | $len = count($tokens) - 1; |
||
442 | |||
443 | switch ($yState) { |
||
444 | |||
445 | case 1: |
||
446 | $yText = preg_replace_callback('{(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4})}', [$this, 'stringInterpolation'], $yText); |
||
447 | $yVal->token = $yText; |
||
448 | break; |
||
449 | |||
450 | case 2: |
||
451 | if (strpos($yText, 'e') !== false || strpos($yText, 'E') !== false) { |
||
452 | |||
453 | $yVal->token = floatval($yText); |
||
454 | } else { |
||
455 | |||
456 | $yVal->token = strpos($yText, '.') === false ? intval($yText) : floatval($yText); |
||
457 | } |
||
458 | break; |
||
459 | |||
460 | case 3: |
||
461 | $yVal->token = null; |
||
462 | break; |
||
463 | |||
464 | case 4: |
||
465 | $yVal->token = true; |
||
466 | break; |
||
467 | |||
468 | case 5: |
||
469 | $yVal->token = false; |
||
470 | break; |
||
471 | |||
472 | case 6: |
||
473 | return $yVal->token = $tokens[$len - 1]; |
||
474 | |||
475 | case 13: |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
476 | |||
477 | if ($this->flags & self::PARSE_TO_ASSOC) { |
||
478 | |||
479 | $yVal->token = []; |
||
480 | } else { |
||
481 | |||
482 | $yVal->token = new stdClass; |
||
483 | } |
||
484 | break; |
||
485 | |||
486 | case 14: |
||
487 | $yVal->token = $tokens[$len - 1]; |
||
488 | break; |
||
489 | |||
490 | case 15: |
||
491 | $yVal->token = [$tokens[$len - 2], $tokens[$len]]; |
||
492 | break; |
||
493 | |||
494 | case 16: |
||
495 | $property = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0]; |
||
496 | |||
497 | if ($this->flags & self::PARSE_TO_ASSOC) { |
||
498 | |||
499 | $yVal->token = []; |
||
500 | $yVal->token[$property] = $tokens[$len][1]; |
||
501 | } else { |
||
502 | |||
503 | $yVal->token = new stdClass; |
||
504 | $yVal->token->$property = $tokens[$len][1]; |
||
505 | } |
||
506 | break; |
||
507 | |||
508 | case 17: |
||
509 | if ($this->flags & self::PARSE_TO_ASSOC) { |
||
510 | |||
511 | $yVal->token = & $tokens[$len - 2]; |
||
512 | $key = $tokens[$len][0]; |
||
513 | |||
514 | if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len - 2][$key])) { |
||
515 | |||
516 | $args = ['line' => ($yLineNo + 1), 'key' => $tokens[$len][0]]; |
||
517 | $e = new DuplicateKeyException(DuplicateKeyException::ERROR_PARSE_ERROR_DUPLICATE_KEY, $tokens[$len][0], $args); |
||
518 | |||
519 | $e->setJsonLineNo($args['line']); |
||
520 | $e->setJsonMatch($args['key']); |
||
521 | $e->setJsonColumnNo($this->lexer->yColumnNo); |
||
522 | |||
523 | throw $e; |
||
524 | View Code Duplication | } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len - 2][$key])) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
525 | |||
526 | $duplicateCount = 1; |
||
527 | |||
528 | do { |
||
529 | |||
530 | $duplicateKey = $key . '.' . $duplicateCount++; |
||
531 | } while (isset($tokens[$len - 2][$duplicateKey])); |
||
532 | |||
533 | $key = $duplicateKey; |
||
534 | } |
||
535 | |||
536 | $tokens[$len - 2][$key] = $tokens[$len][1]; |
||
537 | } else { |
||
538 | |||
539 | $yVal->token = $tokens[$len - 2]; |
||
540 | $key = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0]; |
||
541 | |||
542 | if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len - 2]->{$key})) { |
||
543 | |||
544 | $args = ['line' => ($yLineNo + 1), 'key' => $tokens[$len][0]]; |
||
545 | $e = new DuplicateKeyException(DuplicateKeyException::ERROR_PARSE_ERROR_DUPLICATE_KEY, $tokens[$len][0], $args); |
||
546 | |||
547 | $e->setJsonLineNo($args['line']); |
||
548 | $e->setJsonMatch($args['key']); |
||
549 | $e->setJsonColumnNo($this->lexer->yColumnNo); |
||
550 | |||
551 | throw $e; |
||
552 | View Code Duplication | } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len - 2]->{$key})) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
553 | |||
554 | $duplicateCount = 1; |
||
555 | |||
556 | do { |
||
557 | |||
558 | $duplicateKey = $key . '.' . $duplicateCount++; |
||
559 | } while (isset($tokens[$len - 2]->$duplicateKey)); |
||
560 | |||
561 | $key = $duplicateKey; |
||
562 | } |
||
563 | |||
564 | $tokens[$len - 2]->$key = $tokens[$len][1]; |
||
565 | } |
||
566 | break; |
||
567 | |||
568 | case 18: |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
569 | |||
570 | $yVal->token = []; |
||
571 | break; |
||
572 | |||
573 | case 19: |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
574 | |||
575 | $yVal->token = $tokens[$len - 1]; |
||
576 | break; |
||
577 | |||
578 | case 20: |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
579 | |||
580 | $yVal->token = [$tokens[$len]]; |
||
581 | break; |
||
582 | |||
583 | case 21: |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
584 | |||
585 | $tokens[$len - 2][] = $tokens[$len]; |
||
586 | $yVal->token = $tokens[$len - 2]; |
||
587 | break; |
||
588 | } |
||
589 | |||
590 | return new UndefinedException(UndefinedException::ERROR_UNDEFINED_VALIDATION); |
||
591 | } |
||
592 | |||
593 | /** |
||
594 | * alter $match[0] to a new value |
||
595 | * |
||
596 | * @param array $match |
||
597 | * |
||
598 | * @return string |
||
599 | */ |
||
600 | private function stringInterpolation($match) |
||
601 | { |
||
602 | switch ($match[0]) { |
||
603 | |||
604 | case '\\\\': |
||
605 | return '\\'; |
||
606 | |||
607 | case '\"': |
||
608 | return '"'; |
||
609 | |||
610 | case '\b': |
||
611 | return chr(8); |
||
612 | |||
613 | case '\f': |
||
614 | return chr(12); |
||
615 | |||
616 | case '\n': |
||
617 | return "\n"; |
||
618 | |||
619 | case '\r': |
||
620 | return "\r"; |
||
621 | |||
622 | case '\t': |
||
623 | return "\t"; |
||
624 | |||
625 | case '\/': |
||
626 | return "/"; |
||
627 | |||
628 | default: |
||
629 | return html_entity_decode('&#x' . ltrim(substr($match[0], 2), '0') . ';', 0, 'UTF-8'); |
||
630 | } |
||
631 | } |
||
632 | |||
633 | /** |
||
634 | * Returns the sequence of elements from the arrays as specified by the offset and length ($n) parameters. |
||
635 | * |
||
636 | * @param int $n |
||
637 | */ |
||
638 | private function popStack($n) |
||
639 | { |
||
640 | $this->stack = array_slice($this->stack, 0, -(2 * $n)); |
||
641 | $this->vStack = array_slice($this->vStack, 0, -$n); |
||
642 | $this->lStack = array_slice($this->lStack, 0, -$n); |
||
643 | } |
||
644 | |||
645 | /** |
||
646 | * @return int |
||
647 | */ |
||
648 | private function lex() |
||
649 | { |
||
650 | $token = $this->lexer->lex() ?: 1; |
||
651 | |||
652 | // if token isn't its numeric value, convert |
||
653 | if (!is_numeric($token)) { |
||
654 | |||
655 | $token = isset($this->symbols[$token]) ? $this->symbols[$token] : $token; |
||
656 | } |
||
657 | |||
658 | return $token; |
||
659 | } |
||
660 | |||
661 | /** |
||
662 | * The byte order mark (BOM) is a Unicode character, which is not allowed |
||
663 | * |
||
664 | * @param string $input |
||
665 | * |
||
666 | * @throws ParseException |
||
667 | */ |
||
668 | private function failOnBOM($input) |
||
669 | { |
||
670 | // UTF-8 ByteOrderMark sequence |
||
671 | $bom = "\xEF\xBB\xBF"; |
||
672 | |||
673 | if (substr($input, 0, 3) === $bom) { |
||
674 | |||
675 | throw new ParseException(ParseException::ERROR_BYTE_ORDER_MARK_DETECTED); |
||
676 | } |
||
677 | } |
||
678 | } |
||
679 |
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.