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\Escaper; |
||
33 | use Scabbia\Yaml\ParseException; |
||
34 | |||
35 | /** |
||
36 | * Inline implements a YAML parser for the YAML inline syntax |
||
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 Inline |
||
44 | { |
||
45 | /** @type string REGEX_QUOTED_STRING a regular expression pattern to match quoted strings */ |
||
46 | const REGEX_QUOTED_STRING = "(?:\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|'([^']*(?:''[^']*)*)')"; |
||
47 | |||
48 | |||
49 | /** |
||
50 | * Converts a YAML string to a PHP array |
||
51 | * |
||
52 | * @param string $value A YAML string |
||
53 | * @param array $references Mapping of variable names to values |
||
54 | * |
||
55 | * @throws ParseException If the YAML is not valid |
||
56 | * @return array A PHP array representing the YAML string |
||
57 | */ |
||
58 | public static function parse($value, $references = []) |
||
59 | { |
||
60 | $value = trim($value); |
||
61 | |||
62 | if (strlen($value) === 0) { |
||
63 | return ""; |
||
64 | } |
||
65 | |||
66 | $i = 0; |
||
67 | if ($value[0] === "[") { |
||
68 | $result = self::parseSequence($value, $i, $references); |
||
69 | ++$i; |
||
70 | } elseif ($value[0] === "{") { |
||
71 | $result = self::parseMapping($value, $i, $references); |
||
72 | ++$i; |
||
73 | } else { |
||
74 | $result = self::parseScalar($value, null, ["\"", "'"], $i, true, $references); |
||
75 | } |
||
76 | |||
77 | // some comments are allowed at the end |
||
78 | if (preg_replace("/\\s+#.*$/A", "", substr($value, $i))) { |
||
79 | throw new ParseException(sprintf("Unexpected characters near \"%s\".", substr($value, $i))); |
||
80 | } |
||
81 | |||
82 | return $result; |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * Parses a scalar to a YAML string |
||
87 | * |
||
88 | * @param scalar $scalar |
||
89 | * @param string $delimiters |
||
90 | * @param array $stringDelimiters |
||
91 | * @param int &$i |
||
92 | * @param bool $evaluate |
||
93 | * @param array $references |
||
94 | * |
||
95 | * @throws ParseException When malformed inline YAML string is parsed |
||
96 | * @return string A YAML string |
||
97 | * |
||
98 | * @internal |
||
99 | */ |
||
100 | public static function parseScalar( |
||
101 | $scalar, |
||
102 | $delimiters = null, |
||
103 | array $stringDelimiters = ["\"", "'"], |
||
104 | &$i = 0, |
||
105 | $evaluate = true, |
||
106 | $references = [] |
||
107 | ) { |
||
108 | if (in_array($scalar[$i], $stringDelimiters)) { |
||
109 | // quoted scalar |
||
110 | $output = self::parseQuotedScalar($scalar, $i); |
||
111 | |||
112 | if ($delimiters !== null) { |
||
113 | $tmp = ltrim(substr($scalar, $i), " "); |
||
114 | if (!in_array($tmp[0], $delimiters)) { |
||
115 | throw new ParseException(sprintf("Unexpected characters (%s).", substr($scalar, $i))); |
||
116 | } |
||
117 | } |
||
118 | |||
119 | return $output; |
||
120 | } |
||
121 | |||
122 | // "normal" string |
||
123 | if (!$delimiters) { |
||
0 ignored issues
–
show
|
|||
124 | $output = substr($scalar, $i); |
||
125 | $i += strlen($output); |
||
126 | |||
127 | // remove comments |
||
128 | if (preg_match("/[ \t]+#/", $output, $match, PREG_OFFSET_CAPTURE)) { |
||
129 | $output = substr($output, 0, $match[0][1]); |
||
130 | } |
||
131 | } elseif (preg_match("/^(.+?)(" . implode("|", $delimiters) . ")/", substr($scalar, $i), $match)) { |
||
132 | $output = $match[1]; |
||
133 | $i += strlen($output); |
||
134 | } else { |
||
135 | throw new ParseException(sprintf("Malformed inline YAML string (%s).", $scalar)); |
||
136 | } |
||
137 | |||
138 | // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >) |
||
139 | if ($output && ($output[0] === "@" || $output[0] === "`" || $output[0] === "|" || $output[0] === ">")) { |
||
140 | throw new ParseException(sprintf("The reserved indicator \"%s\" cannot start a plain scalar; you need to quote the scalar.", $output[0])); |
||
141 | } |
||
142 | |||
143 | if ($evaluate) { |
||
144 | return self::evaluateScalar($output, $references); |
||
145 | } |
||
146 | |||
147 | return $output; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Parses a quoted scalar to YAML |
||
152 | * |
||
153 | * @param string $scalar |
||
154 | * @param int &$i |
||
155 | * |
||
156 | * @throws ParseException When malformed inline YAML string is parsed |
||
157 | * @return string A YAML string |
||
158 | */ |
||
159 | protected static function parseQuotedScalar($scalar, &$i) |
||
160 | { |
||
161 | if (!preg_match("/" . self::REGEX_QUOTED_STRING . "/Au", substr($scalar, $i), $match)) { |
||
162 | throw new ParseException(sprintf("Malformed inline YAML string (%s).", substr($scalar, $i))); |
||
163 | } |
||
164 | |||
165 | $output = substr($match[0], 1, strlen($match[0]) - 2); |
||
166 | |||
167 | $escaper = new Escaper(); |
||
168 | if ($scalar[$i] == "\"") { |
||
169 | $output = $escaper->unescapeDoubleQuotedString($output); |
||
170 | } else { |
||
171 | $output = $escaper->unescapeSingleQuotedString($output); |
||
172 | } |
||
173 | |||
174 | $i += strlen($match[0]); |
||
175 | |||
176 | return $output; |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Parses a sequence to a YAML string |
||
181 | * |
||
182 | * @param string $sequence |
||
183 | * @param int &$i |
||
184 | * @param array $references |
||
185 | * |
||
186 | * @throws ParseException When malformed inline YAML string is parsed |
||
187 | * @return string A YAML string |
||
188 | */ |
||
189 | protected static function parseSequence($sequence, &$i = 0, $references = []) |
||
190 | { |
||
191 | $output = []; |
||
192 | $len = strlen($sequence); |
||
193 | ++$i; |
||
194 | |||
195 | // [foo, bar, ...] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
50% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
196 | while ($i < $len) { |
||
197 | if ($sequence[$i] === "[") { |
||
198 | // nested sequence |
||
199 | $output[] = self::parseSequence($sequence, $i, $references); |
||
200 | } elseif ($sequence[$i] === "{") { |
||
201 | // nested mapping |
||
202 | $output[] = self::parseMapping($sequence, $i, $references); |
||
203 | } elseif ($sequence[$i] === "]") { |
||
204 | return $output; |
||
205 | } elseif ($sequence[$i] !== "," && $sequence[$i] !== " ") { |
||
206 | $isQuoted = in_array($sequence[$i], ["\"", "'"]); |
||
207 | $value = self::parseScalar($sequence, [",", "]"], ["\"", "'"], $i, true, $references); |
||
0 ignored issues
–
show
array(',', ']') is of type array<integer,string,{"0":"string","1":"string"}> , but the function expects a string|null .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
208 | |||
209 | // the value can be an array if a reference has been resolved to an array var |
||
210 | if (!is_array($value) && !$isQuoted && strpos($value, ": ") !== false) { |
||
211 | // embedded mapping? |
||
212 | try { |
||
213 | $pos = 0; |
||
214 | $value = self::parseMapping("{" . $value . "}", $pos, $references); |
||
215 | } catch (\InvalidArgumentException $e) { |
||
216 | // no, it's not |
||
217 | } |
||
218 | } |
||
219 | |||
220 | $output[] = $value; |
||
221 | --$i; |
||
222 | } |
||
223 | |||
224 | ++$i; |
||
225 | } |
||
226 | |||
227 | throw new ParseException(sprintf("Malformed inline YAML string %s", $sequence)); |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * Parses a mapping to a YAML string |
||
232 | * |
||
233 | * @param string $mapping |
||
234 | * @param int &$i |
||
235 | * @param array $references |
||
236 | * |
||
237 | * @throws ParseException When malformed inline YAML string is parsed |
||
238 | * @return string A YAML string |
||
239 | */ |
||
240 | protected static function parseMapping($mapping, &$i = 0, $references = []) |
||
241 | { |
||
242 | $output = []; |
||
243 | $len = strlen($mapping); |
||
244 | ++$i; |
||
245 | |||
246 | // {foo: bar, bar:foo, ...} |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
54% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
247 | while ($i < $len) { |
||
248 | if ($mapping[$i] === " " || $mapping[$i] === ",") { |
||
249 | ++$i; |
||
250 | continue; |
||
251 | } elseif ($mapping[$i] === "}") { |
||
252 | return $output; |
||
253 | } |
||
254 | |||
255 | // key |
||
256 | $key = self::parseScalar($mapping, [":", " "], ["\"", "'"], $i, false); |
||
0 ignored issues
–
show
array(':', ' ') is of type array<integer,string,{"0":"string","1":"string"}> , but the function expects a string|null .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
257 | |||
258 | // value |
||
259 | $done = false; |
||
260 | while ($i < $len) { |
||
261 | if ($mapping[$i] === "[") { |
||
262 | // nested sequence |
||
263 | $output[$key] = self::parseSequence($mapping, $i, $references); |
||
264 | $done = true; |
||
265 | } elseif ($mapping[$i] === "{") { |
||
266 | // nested mapping |
||
267 | $output[$key] = self::parseMapping($mapping, $i, $references); |
||
268 | $done = true; |
||
269 | } elseif ($mapping[$i] !== ":" && $mapping[$i] !== " ") { |
||
270 | $output[$key] = self::parseScalar($mapping, [",", "}"], ["\"", "'"], $i, true, $references); |
||
0 ignored issues
–
show
array(',', '}') is of type array<integer,string,{"0":"string","1":"string"}> , but the function expects a string|null .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
271 | $done = true; |
||
272 | --$i; |
||
273 | } |
||
274 | |||
275 | ++$i; |
||
276 | |||
277 | if ($done) { |
||
278 | continue 2; |
||
279 | } |
||
280 | } |
||
281 | } |
||
282 | |||
283 | throw new ParseException(sprintf("Malformed inline YAML string %s", $mapping)); |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Evaluates scalars and replaces magic values |
||
288 | * |
||
289 | * @param string $scalar |
||
290 | * @param array $references |
||
291 | * |
||
292 | * @throws ParseException when a reference could not be resolved |
||
293 | * @return string A YAML string |
||
294 | */ |
||
295 | protected static function evaluateScalar($scalar, $references = []) |
||
296 | { |
||
297 | $scalar = trim($scalar); |
||
298 | $scalarLower = strtolower($scalar); |
||
299 | |||
300 | if (strpos($scalar, "*") === 0) { |
||
301 | View Code Duplication | if (($pos = strpos($scalar, "#")) !== 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. ![]() |
|||
302 | $value = substr($scalar, 1, $pos - 2); |
||
303 | } else { |
||
304 | $value = substr($scalar, 1); |
||
305 | } |
||
306 | |||
307 | // an unquoted * |
||
308 | if ($value === false || $value === "") { |
||
309 | throw new ParseException("A reference must contain at least one character."); |
||
310 | } |
||
311 | |||
312 | if (!array_key_exists($value, $references)) { |
||
313 | throw new ParseException(sprintf("Reference \"%s\" does not exist.", $value)); |
||
314 | } |
||
315 | |||
316 | return $references[$value]; |
||
317 | } |
||
318 | |||
319 | if ($scalarLower === "null" || $scalar === "" || $scalar === "~") { |
||
320 | return null; |
||
321 | } elseif ($scalarLower === "true") { |
||
322 | return true; |
||
0 ignored issues
–
show
The return type of
return true; (boolean ) is incompatible with the return type documented by Scabbia\Yaml\Inline::evaluateScalar of type string .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
323 | } elseif ($scalarLower === "false") { |
||
324 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by Scabbia\Yaml\Inline::evaluateScalar of type string .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
325 | } elseif ($scalar[0] === "+" || $scalar[0] === "-" || $scalar[0] === "." || $scalar[0] === "!" || |
||
326 | is_numeric($scalar[0])) { |
||
327 | // Optimise for returning strings. |
||
328 | if (strpos($scalar, "!str") === 0) { |
||
329 | return (string)substr($scalar, 5); |
||
330 | } elseif (strpos($scalar, "! ") === 0) { |
||
331 | return (int)self::parseScalar(substr($scalar, 2)); |
||
332 | } elseif (strpos($scalar, "!!php/object:") === 0) { |
||
333 | return unserialize(substr($scalar, 13)); |
||
334 | } elseif (strpos($scalar, "!!float ") === 0) { |
||
335 | return (float)substr($scalar, 8); |
||
336 | } elseif (ctype_digit($scalar)) { |
||
337 | $raw = $scalar; |
||
338 | $cast = (int)$scalar; |
||
339 | |||
340 | return $scalar[0] == "0" ? octdec($scalar) : (((string)$raw == (string)$cast) ? $cast : $raw); |
||
341 | } elseif ($scalar[0] === "-" && ctype_digit(substr($scalar, 1))) { |
||
342 | $raw = $scalar; |
||
343 | $cast = (int)$scalar; |
||
344 | |||
345 | return $scalar[1] == "0" ? octdec($scalar) : (((string)$raw == (string)$cast) ? $cast : $raw); |
||
346 | } elseif (is_numeric($scalar) || preg_match(self::getHexRegex(), $scalar)) { |
||
347 | return $scalar[0] . $scalar[1] == "0x" ? hexdec($scalar) : (float)$scalar; |
||
348 | } elseif ($scalarLower === ".inf" || $scalarLower === ".nan") { |
||
349 | return -log(0); |
||
350 | } elseif ($scalarLower === "-.inf") { |
||
351 | return log(0); |
||
352 | } elseif (preg_match("/^(-|\\+)?[0-9,]+(\\.[0-9]+)?$/", $scalar)) { |
||
353 | return (float)str_replace(",", "", $scalar); |
||
354 | } elseif (preg_match(self::getTimestampRegex(), $scalar)) { |
||
355 | return strtotime($scalar); |
||
356 | } |
||
357 | } else { |
||
358 | return (string)$scalar; |
||
359 | } |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * Gets a regex that matches a YAML date |
||
364 | * |
||
365 | * @return string The regular expression |
||
366 | * |
||
367 | * @see http://www.yaml.org/spec/1.2/spec.html#id2761573 |
||
368 | */ |
||
369 | public static function getTimestampRegex() |
||
370 | { |
||
371 | return <<<EOF |
||
372 | ~^ |
||
373 | (?P<year>[0-9][0-9][0-9][0-9]) |
||
374 | -(?P<month>[0-9][0-9]?) |
||
375 | -(?P<day>[0-9][0-9]?) |
||
376 | (?:(?:[Tt]|[ \t]+) |
||
377 | (?P<hour>[0-9][0-9]?) |
||
378 | :(?P<minute>[0-9][0-9]) |
||
379 | :(?P<second>[0-9][0-9]) |
||
380 | (?:\.(?P<fraction>[0-9]*))? |
||
381 | (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?) |
||
382 | (?::(?P<tz_minute>[0-9][0-9]))?))?)? |
||
383 | $~x |
||
384 | EOF; |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * Gets a regex that matches a YAML number in hexadecimal notation. |
||
389 | * |
||
390 | * @return string |
||
391 | */ |
||
392 | public static function getHexRegex() |
||
393 | { |
||
394 | return "~^0x[0-9a-f]++$~i"; |
||
395 | } |
||
396 | } |
||
397 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: