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 |
||
2 | /** |
||
3 | * Scabbia2 Yaml Component |
||
4 | * https://github.com/eserozvataf/scabbia2 |
||
5 | * |
||
6 | * For the full copyright and license information, please view the LICENSE |
||
7 | * file that was distributed with this source code. |
||
8 | * |
||
9 | * @link https://github.com/eserozvataf/scabbia2-yaml for the canonical source repository |
||
10 | * @copyright 2010-2016 Eser Ozvataf. (http://eser.ozvataf.com/) |
||
11 | * @license http://www.apache.org/licenses/LICENSE-2.0 - Apache License, Version 2.0 |
||
12 | * |
||
13 | * ------------------------- |
||
14 | * Portions of this code are from Symfony YAML Component under the MIT license. |
||
15 | * |
||
16 | * (c) Fabien Potencier <[email protected]> |
||
17 | * |
||
18 | * For the full copyright and license information, please view the LICENSE-MIT |
||
19 | * file that was distributed with this source code. |
||
20 | * |
||
21 | * Modifications made: |
||
22 | * - Scabbia Framework code styles applied. |
||
23 | * - All dump methods are moved under Dumper class. |
||
24 | * - Redundant classes removed. |
||
25 | * - Namespace changed. |
||
26 | * - Tests ported to Scabbia2. |
||
27 | * - Encoding checks removed. |
||
28 | */ |
||
29 | |||
30 | namespace Scabbia\Yaml; |
||
31 | |||
32 | use Scabbia\Yaml\Inline; |
||
33 | use Scabbia\Yaml\ParseException; |
||
34 | |||
35 | /** |
||
36 | * Parser parses YAML strings to convert them to PHP arrays |
||
37 | * |
||
38 | * @package Scabbia\Yaml |
||
39 | * @author Fabien Potencier <[email protected]> |
||
40 | * @author Eser Ozvataf <[email protected]> |
||
41 | * @since 2.0.0 |
||
42 | */ |
||
43 | class Parser |
||
44 | { |
||
45 | /** @type string BLOCK_SCALAR_HEADER_PATTERN */ |
||
46 | const BLOCK_SCALAR_HEADER_PATTERN = |
||
47 | "(?P<separator>\\||>)(?P<modifiers>\\+|\\-|\\d+|\\+\\d+|\\-\\d+|\\d+\\+|\\d+\\-)?(?P<comments> +#.*)?"; |
||
48 | |||
49 | |||
50 | /** @type int $offset */ |
||
51 | protected $offset = 0; |
||
52 | /** @type array $lines */ |
||
53 | protected $lines = []; |
||
54 | /** @type int $currentLineNb */ |
||
55 | protected $currentLineNb = -1; |
||
56 | /** @type string $currentLine */ |
||
57 | protected $currentLine = ""; |
||
58 | /** @type array $refs */ |
||
59 | protected $refs = []; |
||
60 | |||
61 | |||
62 | /** |
||
63 | * Constructor |
||
64 | * |
||
65 | * @param int $offset The offset of YAML document (used for line numbers in error messages) |
||
66 | * |
||
67 | * @return Parser |
||
0 ignored issues
–
show
|
|||
68 | */ |
||
69 | public function __construct($offset = 0) |
||
70 | { |
||
71 | $this->offset = $offset; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * Parses a YAML string to a PHP value |
||
76 | * |
||
77 | * @param string $value A YAML string |
||
78 | * |
||
79 | * @throws ParseException If the YAML is not valid |
||
80 | * @return mixed A PHP value |
||
81 | */ |
||
82 | public function parse($value) |
||
83 | { |
||
84 | $this->currentLineNb = -1; |
||
85 | $this->currentLine = ""; |
||
86 | $value = $this->cleanup($value); |
||
87 | $this->lines = explode("\n", $value); |
||
88 | |||
89 | $data = []; |
||
90 | $context = null; |
||
91 | while ($this->moveToNextLine()) { |
||
92 | if ($this->isCurrentLineEmpty()) { |
||
93 | continue; |
||
94 | } |
||
95 | |||
96 | // tab? |
||
97 | if ($this->currentLine[0] === "\t") { |
||
98 | throw new ParseException( |
||
99 | "A YAML file cannot contain tabs as indentation.", |
||
100 | $this->getRealCurrentLineNb() + 1, |
||
101 | $this->currentLine |
||
102 | ); |
||
103 | } |
||
104 | |||
105 | $isRef = false; |
||
106 | $isInPlace = false; |
||
107 | $isProcessed = false; |
||
108 | if (preg_match("#^\\-((?P<leadspaces>\\s+)(?P<value>.+?))?\\s*$#u", $this->currentLine, $values)) { |
||
109 | if ($context && $context === "mapping") { |
||
0 ignored issues
–
show
The expression
$context of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
110 | throw new ParseException("You cannot define a sequence item when in a mapping"); |
||
111 | } |
||
112 | $context = "sequence"; |
||
113 | |||
114 | View Code Duplication | if (isset($values["value"]) && |
|
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. ![]() |
|||
115 | preg_match("#^&(?P<ref>[^ ]+) *(?P<value>.*)#u", $values["value"], $matches)) { |
||
116 | $isRef = $matches["ref"]; |
||
117 | $values["value"] = $matches["value"]; |
||
118 | } |
||
119 | |||
120 | // array |
||
121 | if (!isset($values["value"]) || trim($values["value"], " ") === "" || |
||
122 | strpos(ltrim($values["value"], " "), "#") === 0) { |
||
123 | $c = $this->getRealCurrentLineNb() + 1; |
||
124 | $parser = new static($c); |
||
125 | $parser->refs =& $this->refs; |
||
126 | $data[] = $parser->parse($this->getNextEmbedBlock(null, true)); |
||
127 | } else { |
||
128 | if (isset($values["leadspaces"]) |
||
129 | && preg_match( |
||
130 | "#^(?P<key>" . |
||
131 | Inline::REGEX_QUOTED_STRING . |
||
132 | "|[^ '\"\\{\\[].*?) *\\:(\\s+(?P<value>.+?))?\\s*$#u", |
||
133 | $values["value"], |
||
134 | $matches |
||
135 | ) |
||
136 | ) { |
||
137 | // this is a compact notation element, add to next block and parse |
||
138 | $c = $this->getRealCurrentLineNb(); |
||
139 | $parser = new static($c); |
||
140 | $parser->refs =& $this->refs; |
||
141 | |||
142 | $block = $values["value"]; |
||
143 | if ($this->isNextLineIndented()) { |
||
144 | $block .= "\n" . $this->getNextEmbedBlock($this->getCurrentLineIndentation() + strlen($values["leadspaces"]) + 1); |
||
145 | } |
||
146 | |||
147 | $data[] = $parser->parse($block); |
||
148 | } else { |
||
149 | $data[] = $this->parseValue($values["value"], $context); |
||
150 | } |
||
151 | } |
||
152 | |||
153 | if ($isRef) { |
||
0 ignored issues
–
show
The expression
$isRef of type string|false is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
154 | $this->refs[$isRef] = end($data); |
||
155 | } |
||
156 | } elseif (preg_match( |
||
157 | "#^(?P<key>" . |
||
158 | Inline::REGEX_QUOTED_STRING . |
||
159 | "|[^ '\"\\[\\{].*?) *\\:(\\s+(?P<value>.+?))?\\s*$#u", |
||
160 | $this->currentLine, |
||
161 | $values |
||
162 | ) && (strpos($values["key"], " #") === false || in_array($values["key"][0], ["\"", "'"]))) { |
||
163 | if ($context && $context === "sequence") { |
||
0 ignored issues
–
show
The expression
$context of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
164 | throw new ParseException("You cannot define a mapping item when in a sequence"); |
||
165 | } |
||
166 | $context = "mapping"; |
||
167 | |||
168 | // force correct settings |
||
169 | Inline::parse(null, $this->refs); |
||
170 | try { |
||
171 | $key = Inline::parseScalar($values["key"]); |
||
172 | } catch (ParseException $e) { |
||
173 | $e->setParsedLine($this->getRealCurrentLineNb() + 1); |
||
174 | $e->setSnippet($this->currentLine); |
||
175 | |||
176 | throw $e; |
||
177 | } |
||
178 | |||
179 | // Convert float keys to strings, to avoid being converted to integers by PHP |
||
180 | if (is_float($key)) { |
||
181 | $key = (string)$key; |
||
182 | } |
||
183 | |||
184 | if ($key === "<<") { |
||
185 | if (isset($values["value"]) && strpos($values["value"], "*") === 0) { |
||
186 | $isInPlace = substr($values["value"], 1); |
||
187 | if (!array_key_exists($isInPlace, $this->refs)) { |
||
188 | throw new ParseException( |
||
189 | sprintf( |
||
190 | "Reference \"%s\" does not exist.", |
||
191 | $isInPlace |
||
192 | ), |
||
193 | $this->getRealCurrentLineNb() + 1, |
||
194 | $this->currentLine |
||
195 | ); |
||
196 | } |
||
197 | } else { |
||
198 | if (isset($values["value"]) && $values["value"] !== "") { |
||
199 | $value = $values["value"]; |
||
200 | } else { |
||
201 | $value = $this->getNextEmbedBlock(); |
||
202 | } |
||
203 | |||
204 | $c = $this->getRealCurrentLineNb() + 1; |
||
205 | $parser = new static($c); |
||
206 | $parser->refs =& $this->refs; |
||
207 | $parsed = $parser->parse($value); |
||
208 | |||
209 | $merged = []; |
||
210 | if (!is_array($parsed)) { |
||
211 | throw new ParseException( |
||
212 | "YAML merge keys used with a scalar value instead of an array.", |
||
213 | $this->getRealCurrentLineNb() + 1, |
||
214 | $this->currentLine |
||
215 | ); |
||
216 | } elseif (isset($parsed[0])) { |
||
217 | // Numeric array, merge individual elements |
||
218 | foreach (array_reverse($parsed) as $parsedItem) { |
||
219 | if (!is_array($parsedItem)) { |
||
220 | throw new ParseException( |
||
221 | "Merge items must be arrays.", |
||
222 | $this->getRealCurrentLineNb() + 1, |
||
223 | $parsedItem |
||
224 | ); |
||
225 | } |
||
226 | $merged = array_merge($parsedItem, $merged); |
||
227 | } |
||
228 | } else { |
||
229 | // Associative array, merge |
||
230 | $merged = array_merge($merged, $parsed); |
||
231 | } |
||
232 | |||
233 | $isProcessed = $merged; |
||
234 | } |
||
235 | View Code Duplication | } elseif (isset($values["value"]) && |
|
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. ![]() |
|||
236 | preg_match("#^&(?P<ref>[^ ]+) *(?P<value>.*)#u", $values["value"], $matches)) { |
||
237 | $isRef = $matches["ref"]; |
||
238 | $values["value"] = $matches["value"]; |
||
239 | } |
||
240 | |||
241 | if ($isProcessed) { |
||
242 | // Merge keys |
||
243 | $data = $isProcessed; |
||
244 | } elseif (!isset($values["value"]) || |
||
245 | trim($values["value"], " ") === "" || |
||
246 | strpos(ltrim($values["value"], " "), "#") === 0) { |
||
247 | // if next line is less indented or equal, then it means that the current value is null |
||
248 | if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) { |
||
249 | $data[$key] = null; |
||
250 | } else { |
||
251 | $c = $this->getRealCurrentLineNb() + 1; |
||
252 | $parser = new static($c); |
||
253 | $parser->refs =& $this->refs; |
||
254 | $data[$key] = $parser->parse($this->getNextEmbedBlock()); |
||
255 | } |
||
256 | } else { |
||
257 | if ($isInPlace) { |
||
0 ignored issues
–
show
The expression
$isInPlace of type string|false is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
258 | $data = $this->refs[$isInPlace]; |
||
259 | } else { |
||
260 | $data[$key] = $this->parseValue($values["value"], $context); |
||
261 | } |
||
262 | } |
||
263 | |||
264 | if ($isRef) { |
||
0 ignored issues
–
show
The expression
$isRef of type string|false is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
265 | $this->refs[$isRef] = $data[$key]; |
||
266 | } |
||
267 | } else { |
||
268 | // multiple documents are not supported |
||
269 | if ($this->currentLine === "---") { |
||
270 | throw new ParseException("Multiple documents are not supported."); |
||
271 | } |
||
272 | |||
273 | // 1-liner optionally followed by newline(s) |
||
274 | if (is_string($value) && $this->lines[0] === trim($value)) { |
||
275 | try { |
||
276 | $value = Inline::parse($this->lines[0], $this->refs); |
||
277 | } catch (ParseException $e) { |
||
278 | $e->setParsedLine($this->getRealCurrentLineNb() + 1); |
||
279 | $e->setSnippet($this->currentLine); |
||
280 | |||
281 | throw $e; |
||
282 | } |
||
283 | |||
284 | if (is_array($value)) { |
||
285 | $first = reset($value); |
||
286 | if (is_string($first) && strpos($first, "*") === 0) { |
||
287 | $data = []; |
||
288 | foreach ($value as $alias) { |
||
289 | $data[] = $this->refs[substr($alias, 1)]; |
||
290 | } |
||
291 | $value = $data; |
||
292 | } |
||
293 | } |
||
294 | |||
295 | return $value; |
||
296 | } |
||
297 | |||
298 | switch (preg_last_error()) { |
||
299 | case PREG_INTERNAL_ERROR: |
||
300 | $error = "Internal PCRE error."; |
||
301 | break; |
||
302 | case PREG_BACKTRACK_LIMIT_ERROR: |
||
303 | $error = "pcre.backtrack_limit reached."; |
||
304 | break; |
||
305 | case PREG_RECURSION_LIMIT_ERROR: |
||
306 | $error = "pcre.recursion_limit reached."; |
||
307 | break; |
||
308 | case PREG_BAD_UTF8_ERROR: |
||
309 | $error = "Malformed UTF-8 data."; |
||
310 | break; |
||
311 | case PREG_BAD_UTF8_OFFSET_ERROR: |
||
312 | $error = "Offset doesn't correspond to the begin of a valid UTF-8 code point."; |
||
313 | break; |
||
314 | default: |
||
315 | $error = "Unable to parse."; |
||
316 | } |
||
317 | |||
318 | throw new ParseException($error, $this->getRealCurrentLineNb() + 1, $this->currentLine); |
||
319 | } |
||
320 | |||
321 | if ($isRef) { |
||
0 ignored issues
–
show
The expression
$isRef of type string|false is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
322 | $this->refs[$isRef] = end($data); |
||
323 | } |
||
324 | } |
||
325 | |||
326 | if (count($data) === 0) { |
||
327 | return null; |
||
328 | } |
||
329 | |||
330 | return $data; |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Returns the current line number (takes the offset into account) |
||
335 | * |
||
336 | * @return int The current line number |
||
337 | */ |
||
338 | protected function getRealCurrentLineNb() |
||
339 | { |
||
340 | return $this->currentLineNb + $this->offset; |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * Returns the current line indentation |
||
345 | * |
||
346 | * @return int The current line indentation |
||
347 | */ |
||
348 | protected function getCurrentLineIndentation() |
||
349 | { |
||
350 | return strlen($this->currentLine) - strlen(ltrim($this->currentLine, " ")); |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * Returns the next embed block of YAML |
||
355 | * |
||
356 | * @param int $indentation The indent level at which the block is to be read, or null for default |
||
357 | * @param bool $inSequence True if the enclosing data structure is a sequence |
||
358 | * |
||
359 | * @throws ParseException When indentation problem are detected |
||
360 | * @return string A YAML string |
||
361 | */ |
||
362 | protected function getNextEmbedBlock($indentation = null, $inSequence = false) |
||
363 | { |
||
364 | $oldLineIndentation = $this->getCurrentLineIndentation(); |
||
365 | $blockScalarIndentations = []; |
||
366 | |||
367 | if ($this->isBlockScalarHeader()) { |
||
368 | $blockScalarIndentations[] = $this->getCurrentLineIndentation(); |
||
369 | } |
||
370 | |||
371 | if (!$this->moveToNextLine()) { |
||
372 | return; |
||
373 | } |
||
374 | |||
375 | if ($indentation === null) { |
||
376 | $newIndent = $this->getCurrentLineIndentation(); |
||
377 | |||
378 | $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem(); |
||
379 | |||
380 | if (!$this->isCurrentLineEmpty() && $newIndent === 0 && !$unindentedEmbedBlock) { |
||
381 | throw new ParseException("Indentation problem.", $this->getRealCurrentLineNb() + 1, $this->currentLine); |
||
382 | } |
||
383 | } else { |
||
384 | $newIndent = $indentation; |
||
385 | } |
||
386 | |||
387 | $data = []; |
||
388 | if ($this->getCurrentLineIndentation() >= $newIndent) { |
||
389 | $data[] = substr($this->currentLine, $newIndent); |
||
390 | } else { |
||
391 | $this->moveToPreviousLine(); |
||
392 | return; |
||
393 | } |
||
394 | |||
395 | if ($inSequence && $oldLineIndentation === $newIndent && isset($data[0][0]) && $data[0][0] === "-") { |
||
396 | // the previous line contained a dash but no item content, this line is a sequence item |
||
397 | // with the same indentation and therefore no nested list or mapping |
||
398 | $this->moveToPreviousLine(); |
||
399 | |||
400 | return; |
||
401 | } |
||
402 | |||
403 | $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); |
||
404 | |||
405 | if (empty($blockScalarIndentations) && $this->isBlockScalarHeader()) { |
||
406 | $blockScalarIndentations[] = $this->getCurrentLineIndentation(); |
||
407 | } |
||
408 | |||
409 | $previousLineIndentation = $this->getCurrentLineIndentation(); |
||
410 | |||
411 | while ($this->moveToNextLine()) { |
||
412 | $indent = $this->getCurrentLineIndentation(); |
||
413 | |||
414 | // terminate all block scalars that are more indented than the current line |
||
415 | if (!empty($blockScalarIndentations) && $indent < $previousLineIndentation && rtrim($this->currentLine) !== "") { |
||
416 | foreach ($blockScalarIndentations as $key => $blockScalarIndentation) { |
||
417 | if ($blockScalarIndentation >= $this->getCurrentLineIndentation()) { |
||
418 | unset($blockScalarIndentations[$key]); |
||
419 | } |
||
420 | } |
||
421 | } |
||
422 | |||
423 | if (empty($blockScalarIndentations) && !$this->isCurrentLineComment() && $this->isBlockScalarHeader()) { |
||
424 | $blockScalarIndentations[] = $this->getCurrentLineIndentation(); |
||
425 | } |
||
426 | |||
427 | $previousLineIndentation = $indent; |
||
428 | |||
429 | if ($isItUnindentedCollection && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) { |
||
430 | $this->moveToPreviousLine(); |
||
431 | break; |
||
432 | } |
||
433 | |||
434 | if ($this->isCurrentLineBlank()) { |
||
435 | $data[] = substr($this->currentLine, $newIndent); |
||
436 | continue; |
||
437 | } |
||
438 | |||
439 | // we ignore "comment" lines only when we are not inside a scalar block |
||
440 | if (empty($blockScalarIndentations) && $this->isCurrentLineComment()) { |
||
441 | continue; |
||
442 | } |
||
443 | |||
444 | if ($indent >= $newIndent) { |
||
445 | $data[] = substr($this->currentLine, $newIndent); |
||
446 | } elseif ($indent === 0) { |
||
447 | $this->moveToPreviousLine(); |
||
448 | |||
449 | break; |
||
450 | } else { |
||
451 | throw new ParseException("Indentation problem.", $this->getRealCurrentLineNb() + 1, $this->currentLine); |
||
452 | } |
||
453 | } |
||
454 | |||
455 | return implode("\n", $data); |
||
456 | } |
||
457 | |||
458 | /** |
||
459 | * Moves the parser to the next line |
||
460 | * |
||
461 | * @return bool |
||
462 | */ |
||
463 | protected function moveToNextLine() |
||
464 | { |
||
465 | if ($this->currentLineNb >= count($this->lines) - 1) { |
||
466 | return false; |
||
467 | } |
||
468 | |||
469 | $this->currentLine = $this->lines[++$this->currentLineNb]; |
||
470 | |||
471 | return true; |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Moves the parser to the previous line |
||
476 | * |
||
477 | * @return void |
||
478 | */ |
||
479 | protected function moveToPreviousLine() |
||
480 | { |
||
481 | $this->currentLine = $this->lines[--$this->currentLineNb]; |
||
482 | } |
||
483 | |||
484 | /** |
||
485 | * Parses a YAML value |
||
486 | * |
||
487 | * @param string $value A YAML value |
||
488 | * @param string $context The parser context (either sequence or mapping) |
||
489 | * |
||
490 | * @throws ParseException When reference does not exist |
||
491 | * @return mixed A PHP value |
||
492 | */ |
||
493 | protected function parseValue($value, $context) |
||
494 | { |
||
495 | if (strpos($value, "*") === 0) { |
||
496 | View Code Duplication | if (($pos = strpos($value, "#")) !== false) { |
|
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. ![]() |
|||
497 | $value = substr($value, 1, $pos - 2); |
||
498 | } else { |
||
499 | $value = substr($value, 1); |
||
500 | } |
||
501 | |||
502 | if (!array_key_exists($value, $this->refs)) { |
||
503 | throw new ParseException(sprintf("Reference \"%s\" does not exist.", $value), $this->currentLine); |
||
504 | } |
||
505 | |||
506 | return $this->refs[$value]; |
||
507 | } |
||
508 | |||
509 | if (preg_match("/^" . self::BLOCK_SCALAR_HEADER_PATTERN . "$/", $value, $matches)) { |
||
510 | $modifiers = isset($matches["modifiers"]) ? $matches["modifiers"] : ""; |
||
511 | |||
512 | return $this->parseBlockScalar( |
||
513 | $matches["separator"], |
||
514 | preg_replace("#\\d+#", "", $modifiers), |
||
515 | (int)abs($modifiers) |
||
516 | ); |
||
517 | } |
||
518 | |||
519 | try { |
||
520 | $parsedValue = Inline::parse($value, $this->refs); |
||
521 | |||
522 | if ($context === "mapping" && $value[0] !== "\"" && $value[0] !== "'" && $value[0] !== "[" && $value[0] !== "{" && $value[0] !== "!" && strpos($parsedValue, ": ") !== false) { |
||
523 | throw new ParseException("A colon cannot be used in an unquoted mapping value."); |
||
524 | } |
||
525 | |||
526 | return $parsedValue; |
||
527 | } catch (ParseException $e) { |
||
528 | $e->setParsedLine($this->getRealCurrentLineNb() + 1); |
||
529 | $e->setSnippet($this->currentLine); |
||
530 | |||
531 | throw $e; |
||
532 | } |
||
533 | } |
||
534 | |||
535 | /** |
||
536 | * Parses a block scalar |
||
537 | * |
||
538 | * @param string $separator The style indicator that was used to begin this block scalar (| or >) |
||
0 ignored issues
–
show
There is no parameter named
$separator . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
539 | * @param string $indicator The chomping indicator that was used to begin this block scalar (+ or -) |
||
0 ignored issues
–
show
There is no parameter named
$indicator . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
540 | * @param int $indentation The indentation indicator that was used to begin this block scalar |
||
541 | * |
||
542 | * @return string The text value |
||
543 | */ |
||
544 | protected function parseBlockScalar($style, $chomping = "", $indentation = 0) |
||
545 | { |
||
546 | $notEOF = $this->moveToNextLine(); |
||
547 | if (!$notEOF) { |
||
548 | return ""; |
||
549 | } |
||
550 | |||
551 | $isCurrentLineBlank = $this->isCurrentLineBlank(); |
||
552 | $blockLines = []; |
||
553 | |||
554 | // leading blank lines are consumed before determining indentation |
||
555 | while ($notEOF && $isCurrentLineBlank) { |
||
556 | // newline only if not EOF |
||
557 | if ($notEOF = $this->moveToNextLine()) { |
||
558 | $blockLines[] = ""; |
||
559 | $isCurrentLineBlank = $this->isCurrentLineBlank(); |
||
560 | } |
||
561 | } |
||
562 | |||
563 | // determine indentation if not specified |
||
564 | if ($indentation === 0) { |
||
565 | if (preg_match("/^ +/", $this->currentLine, $matches)) { |
||
566 | $indentation = strlen($matches[0]); |
||
567 | } |
||
568 | } |
||
569 | |||
570 | if ($indentation > 0) { |
||
571 | $pattern = sprintf("/^ {%d}(.*)$/", $indentation); |
||
572 | |||
573 | while ($notEOF && ($isCurrentLineBlank || preg_match($pattern, $this->currentLine, $matches))) { |
||
574 | if ($isCurrentLineBlank && strlen($this->currentLine) > $indentation) { |
||
575 | $blockLines[] = substr($this->currentLine, $indentation); |
||
576 | } elseif ($isCurrentLineBlank) { |
||
577 | $blockLines[] = ""; |
||
578 | } else { |
||
579 | $blockLines[] = $matches[1]; |
||
0 ignored issues
–
show
The variable
$matches does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
580 | } |
||
581 | |||
582 | // newline only if not EOF |
||
583 | if ($notEOF = $this->moveToNextLine()) { |
||
584 | $isCurrentLineBlank = $this->isCurrentLineBlank(); |
||
585 | } |
||
586 | } |
||
587 | } elseif ($notEOF) { |
||
588 | $blockLines[] = ""; |
||
589 | } |
||
590 | |||
591 | if ($notEOF) { |
||
592 | $blockLines[] = ""; |
||
593 | $this->moveToPreviousLine(); |
||
594 | } |
||
595 | |||
596 | // folded style |
||
597 | if ($style === ">") { |
||
598 | $text = ""; |
||
599 | $previousLineIndented = false; |
||
600 | $previousLineBlank = false; |
||
601 | |||
602 | for ($i = 0; $i < count($blockLines); ++$i) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
603 | if ($blockLines[$i] === "") { |
||
604 | $text .= "\n"; |
||
605 | $previousLineIndented = false; |
||
606 | $previousLineBlank = true; |
||
607 | } elseif ($blockLines[$i][0] === " ") { |
||
608 | $text .= "\n" . $blockLines[$i]; |
||
609 | $previousLineIndented = true; |
||
610 | $previousLineBlank = false; |
||
611 | View Code Duplication | } elseif ($previousLineIndented) { |
|
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. ![]() |
|||
612 | $text .= "\n" . $blockLines[$i]; |
||
613 | $previousLineIndented = false; |
||
614 | $previousLineBlank = false; |
||
615 | } elseif ($previousLineBlank || 0 === $i) { |
||
616 | $text .= $blockLines[$i]; |
||
617 | $previousLineIndented = false; |
||
618 | $previousLineBlank = false; |
||
619 | View Code Duplication | } else { |
|
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. ![]() |
|||
620 | $text .= " " . $blockLines[$i]; |
||
621 | $previousLineIndented = false; |
||
622 | $previousLineBlank = false; |
||
623 | } |
||
624 | } |
||
625 | } else { |
||
626 | $text = implode("\n", $blockLines); |
||
627 | } |
||
628 | |||
629 | // deal with trailing newlines |
||
630 | if ($chomping === "") { |
||
631 | $text = preg_replace("/\\n+$/", "\n", $text); |
||
632 | } elseif ($chomping === "-") { |
||
633 | $text = preg_replace("/\\n+$/", "", $text); |
||
634 | } |
||
635 | |||
636 | return $text; |
||
637 | } |
||
638 | |||
639 | /** |
||
640 | * Returns true if the next line is indented |
||
641 | * |
||
642 | * @return bool Returns true if the next line is indented, false otherwise |
||
643 | */ |
||
644 | protected function isNextLineIndented() |
||
645 | { |
||
646 | $currentIndentation = $this->getCurrentLineIndentation(); |
||
647 | $EOF = !$this->moveToNextLine(); |
||
648 | |||
649 | while (!$EOF && $this->isCurrentLineEmpty()) { |
||
650 | $EOF = !$this->moveToNextLine(); |
||
651 | } |
||
652 | |||
653 | if ($EOF) { |
||
654 | return false; |
||
655 | } |
||
656 | |||
657 | $ret = false; |
||
658 | if ($this->getCurrentLineIndentation() > $currentIndentation) { |
||
659 | $ret = true; |
||
660 | } |
||
661 | |||
662 | $this->moveToPreviousLine(); |
||
663 | |||
664 | return $ret; |
||
665 | } |
||
666 | |||
667 | /** |
||
668 | * Returns true if the current line is blank or if it is a comment line |
||
669 | * |
||
670 | * @return bool Returns true if the current line is empty or if it is a comment line, false otherwise |
||
671 | */ |
||
672 | protected function isCurrentLineEmpty() |
||
673 | { |
||
674 | return $this->isCurrentLineBlank() || $this->isCurrentLineComment(); |
||
675 | } |
||
676 | |||
677 | /** |
||
678 | * Returns true if the current line is blank |
||
679 | * |
||
680 | * @return bool Returns true if the current line is blank, false otherwise |
||
681 | */ |
||
682 | protected function isCurrentLineBlank() |
||
683 | { |
||
684 | return trim($this->currentLine, " ") === ""; |
||
685 | } |
||
686 | |||
687 | /** |
||
688 | * Returns true if the current line is a comment line |
||
689 | * |
||
690 | * @return bool Returns true if the current line is a comment line, false otherwise |
||
691 | */ |
||
692 | protected function isCurrentLineComment() |
||
693 | { |
||
694 | //checking explicitly the first char of the trim is faster than loops or strpos |
||
695 | $ltrimmedLine = ltrim($this->currentLine, " "); |
||
696 | |||
697 | return $ltrimmedLine !== "" && $ltrimmedLine[0] === "#"; |
||
698 | } |
||
699 | |||
700 | /** |
||
701 | * Cleanups a YAML string to be parsed |
||
702 | * |
||
703 | * @param string $value The input YAML string |
||
704 | * |
||
705 | * @return string A cleaned up YAML string |
||
706 | */ |
||
707 | protected function cleanup($value) |
||
708 | { |
||
709 | $value = str_replace(["\r\n", "\r"], "\n", $value); |
||
710 | |||
711 | // strip YAML header |
||
712 | $count = 0; |
||
713 | $value = preg_replace("#^\\%YAML[: ][\\d\\.]+.*\\n#u", "", $value, -1, $count); |
||
714 | $this->offset += $count; |
||
715 | |||
716 | // remove leading comments |
||
717 | $trimmedValue = preg_replace("#^(\\#.*?\\n)+#s", "", $value, -1, $count); |
||
718 | if ($count == 1) { |
||
719 | // items have been removed, update the offset |
||
720 | $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); |
||
721 | $value = $trimmedValue; |
||
722 | } |
||
723 | |||
724 | // remove start of the document marker (---) |
||
725 | $trimmedValue = preg_replace("#^\\-\\-\\-.*?\\n#s", "", $value, -1, $count); |
||
726 | if ($count == 1) { |
||
727 | // items have been removed, update the offset |
||
728 | $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); |
||
729 | $value = $trimmedValue; |
||
730 | |||
731 | // remove end of the document marker (...) |
||
732 | $value = preg_replace("#\\.\\.\\.\\s*$#", "", $value); |
||
733 | } |
||
734 | |||
735 | return $value; |
||
736 | } |
||
737 | |||
738 | /** |
||
739 | * Returns true if the next line starts unindented collection |
||
740 | * |
||
741 | * @return bool Returns true if the next line starts unindented collection, false otherwise |
||
742 | */ |
||
743 | protected function isNextLineUnIndentedCollection() |
||
744 | { |
||
745 | $currentIndentation = $this->getCurrentLineIndentation(); |
||
746 | $notEOF = $this->moveToNextLine(); |
||
747 | |||
748 | while ($notEOF && $this->isCurrentLineEmpty()) { |
||
749 | $notEOF = $this->moveToNextLine(); |
||
750 | } |
||
751 | |||
752 | if ($notEOF === false) { |
||
753 | return false; |
||
754 | } |
||
755 | |||
756 | $ret = false; |
||
757 | if ($this->getCurrentLineIndentation() == $currentIndentation && |
||
758 | $this->isStringUnIndentedCollectionItem()) { |
||
759 | $ret = true; |
||
760 | } |
||
761 | |||
762 | $this->moveToPreviousLine(); |
||
763 | |||
764 | return $ret; |
||
765 | } |
||
766 | |||
767 | /** |
||
768 | * Returns true if the string is un-indented collection item |
||
769 | * |
||
770 | * @return bool Returns true if the string is un-indented collection item, false otherwise |
||
771 | */ |
||
772 | protected function isStringUnIndentedCollectionItem() |
||
773 | { |
||
774 | return (strpos($this->currentLine, "- ") === 0); |
||
775 | } |
||
776 | |||
777 | /** |
||
778 | * Tests whether or not the current line is the header of a block scalar. |
||
779 | * |
||
780 | * @return bool |
||
781 | */ |
||
782 | protected function isBlockScalarHeader() |
||
783 | { |
||
784 | return (bool)preg_match("~" . self::BLOCK_SCALAR_HEADER_PATTERN . "$~", $this->currentLine); |
||
785 | } |
||
786 | } |
||
787 |
Adding a
@return
annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.Please refer to the PHP core documentation on constructors.