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 | class Kint_Parser |
||
4 | { |
||
5 | public $caller_class; |
||
6 | public $max_depth; |
||
7 | |||
8 | private $marker; |
||
9 | private $object_hashes = array(); |
||
10 | private $parse_break = false; |
||
11 | private $plugins = array(); |
||
12 | |||
13 | /** |
||
14 | * Plugin triggers. |
||
15 | * |
||
16 | * These are constants indicating trigger points for plugins |
||
17 | * |
||
18 | * BEGIN: Before normal parsing |
||
19 | * SUCCESS: After successful parsing |
||
20 | * RECURSION: After parsing cancelled by recursion |
||
21 | * DEPTH_LIMIT: After parsing cancelled by depth limit |
||
22 | * COMPLETE: SUCCESS | RECURSION | DEPTH_LIMIT |
||
23 | * |
||
24 | * While a plugin's getTriggers may return any of these |
||
25 | */ |
||
26 | const TRIGGER_NONE = 0; |
||
27 | const TRIGGER_BEGIN = 1; |
||
28 | const TRIGGER_SUCCESS = 2; |
||
29 | const TRIGGER_RECURSION = 4; |
||
30 | const TRIGGER_DEPTH_LIMIT = 8; |
||
31 | const TRIGGER_COMPLETE = 14; |
||
32 | |||
33 | public function __construct($max_depth = false, $c = null) |
||
34 | { |
||
35 | $this->marker = uniqid("kint\0", true); |
||
36 | $this->caller_class = $c; |
||
37 | $this->max_depth = $max_depth; |
||
38 | } |
||
39 | |||
40 | public function parse(&$var, Kint_Object $o) |
||
41 | { |
||
42 | $o->type = strtolower(gettype($var)); |
||
43 | |||
44 | if (!$this->applyPlugins($var, $o, self::TRIGGER_BEGIN)) { |
||
45 | return $o; |
||
46 | } |
||
47 | |||
48 | switch ($o->type) { |
||
49 | case 'array': |
||
50 | return $this->parseArray($var, $o); |
||
51 | case 'boolean': |
||
52 | case 'double': |
||
53 | case 'integer': |
||
54 | case 'null': |
||
55 | return $this->parseGeneric($var, $o); |
||
56 | case 'object': |
||
57 | return $this->parseObject($var, $o); |
||
58 | case 'resource': |
||
59 | return $this->parseResource($var, $o); |
||
60 | case 'string': |
||
61 | return $this->parseString($var, $o); |
||
62 | default: |
||
63 | return $this->parseUnknown($var, $o); |
||
64 | } |
||
65 | } |
||
66 | |||
67 | private function parseGeneric(&$var, Kint_Object $o) |
||
68 | { |
||
69 | $rep = new Kint_Object_Representation('Contents'); |
||
70 | $rep->contents = $var; |
||
71 | $rep->implicit_label = true; |
||
72 | $o->addRepresentation($rep); |
||
73 | |||
74 | $this->applyPlugins($var, $o, self::TRIGGER_SUCCESS); |
||
75 | |||
76 | return $o; |
||
77 | } |
||
78 | |||
79 | private function parseString(&$var, Kint_Object $o) |
||
80 | { |
||
81 | $string = $o->transplant(new Kint_Object_Blob()); |
||
82 | $string->encoding = Kint_Object_Blob::detectEncoding($var); |
||
0 ignored issues
–
show
|
|||
83 | $string->size = Kint_Object_Blob::strlen($var, $string->encoding); |
||
84 | |||
85 | $rep = new Kint_Object_Representation('Contents'); |
||
86 | $rep->contents = $var; |
||
87 | $rep->implicit_label = true; |
||
88 | |||
89 | $string->addRepresentation($rep); |
||
90 | |||
91 | $this->applyPlugins($var, $string, self::TRIGGER_SUCCESS); |
||
92 | |||
93 | return $string; |
||
94 | } |
||
95 | |||
96 | private function parseArray(array &$var, Kint_Object $o) |
||
97 | { |
||
98 | $array = $o->transplant(new Kint_Object()); |
||
99 | $array->size = count($var); |
||
100 | |||
101 | View Code Duplication | if (isset($var[$this->marker])) { |
|
102 | --$array->size; |
||
103 | $array->hints[] = 'recursion'; |
||
104 | |||
105 | $this->applyPlugins($var, $array, self::TRIGGER_RECURSION); |
||
106 | |||
107 | return $array; |
||
108 | } |
||
109 | |||
110 | $rep = new Kint_Object_Representation('Contents'); |
||
111 | $rep->implicit_label = true; |
||
112 | $array->addRepresentation($rep); |
||
113 | |||
114 | if ($array->size) { |
||
115 | View Code Duplication | if ($this->max_depth && $o->depth >= $this->max_depth) { |
|
116 | $array->hints[] = 'depth_limit'; |
||
117 | |||
118 | $this->applyPlugins($var, $array, self::TRIGGER_DEPTH_LIMIT); |
||
119 | |||
120 | return $array; |
||
121 | } |
||
122 | |||
123 | // Don't even bother with reference checking below 5.2.2. It's an |
||
124 | // absolute nightmare. The foreach loop depends on the array pointer |
||
125 | // which "conveniently" moves about semi-randomly when you alter |
||
126 | // the value you're looping over by means of a reference. |
||
127 | if (KINT_PHP522) { |
||
128 | $copy = array_values($var); |
||
129 | } |
||
130 | |||
131 | // It's really really hard to access numeric string keys in arrays, |
||
132 | // and it's really really hard to access integer properties in |
||
133 | // objects, so we just use array_values and index by counter to get |
||
134 | // at it reliably for reference testing. This also affects access |
||
135 | // paths since it's pretty much impossible to access these things |
||
136 | // without complicated stuff you should never need to do. |
||
137 | $i = 0; |
||
138 | |||
139 | // Set the marker for recursion |
||
140 | $var[$this->marker] = $array->depth; |
||
141 | |||
142 | foreach ($var as $key => &$val) { |
||
143 | if ($key === $this->marker) { |
||
144 | continue; |
||
145 | } |
||
146 | |||
147 | $child = new Kint_Object(); |
||
148 | $child->name = $key; |
||
149 | $child->depth = $array->depth + 1; |
||
150 | $child->access = Kint_Object::ACCESS_NONE; |
||
151 | $child->operator = Kint_Object::OPERATOR_ARRAY; |
||
152 | |||
153 | if ($array->access_path !== null) { |
||
154 | if (is_string($key) && (string) (int) $key === $key) { |
||
155 | $child->access_path = 'array_values('.$array->access_path.')['.$i.']'; |
||
156 | } else { |
||
157 | $child->access_path = $array->access_path.'['.var_export($key, true).']'; |
||
158 | } |
||
159 | } |
||
160 | |||
161 | View Code Duplication | if (KINT_PHP522) { |
|
162 | $stash = $val; |
||
163 | $copy[$i] = $this->marker; |
||
0 ignored issues
–
show
The variable
$copy 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
![]() |
|||
164 | if ($val === $this->marker) { |
||
0 ignored issues
–
show
|
|||
165 | $child->reference = true; |
||
166 | $val = $stash; |
||
167 | } |
||
168 | } |
||
169 | |||
170 | $rep->contents[] = $this->parse($val, $child); |
||
171 | ++$i; |
||
172 | } |
||
173 | |||
174 | $this->applyPlugins($var, $array, self::TRIGGER_SUCCESS); |
||
175 | unset($var[$this->marker]); |
||
176 | |||
177 | return $array; |
||
178 | } else { |
||
179 | $this->applyPlugins($var, $array, self::TRIGGER_SUCCESS); |
||
180 | |||
181 | return $array; |
||
182 | } |
||
183 | } |
||
184 | |||
185 | private function parseObject(&$var, Kint_Object $o) |
||
186 | { |
||
187 | View Code Duplication | if (KINT_PHP53 || function_exists('spl_object_hash')) { |
|
188 | $hash = spl_object_hash($var); |
||
189 | } else { |
||
190 | ob_start(); |
||
191 | var_dump($var); |
||
192 | preg_match('/#(\d+)/', ob_get_clean(), $match); |
||
193 | $hash = $match[1]; |
||
194 | } |
||
195 | |||
196 | $values = (array) $var; |
||
197 | |||
198 | $object = $o->transplant(new Kint_Object_Instance()); |
||
199 | $object->classname = get_class($var); |
||
0 ignored issues
–
show
The property
classname does not seem to exist in Kint_Object .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
200 | $object->hash = $hash; |
||
0 ignored issues
–
show
The property
hash does not seem to exist in Kint_Object .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
201 | $object->size = count($values); |
||
202 | |||
203 | View Code Duplication | if (isset($this->object_hashes[$hash])) { |
|
204 | $object->hints[] = 'recursion'; |
||
205 | |||
206 | $this->applyPlugins($var, $object, self::TRIGGER_RECURSION); |
||
207 | |||
208 | return $object; |
||
209 | } |
||
210 | |||
211 | $this->object_hashes[$hash] = $object; |
||
212 | |||
213 | View Code Duplication | if ($this->max_depth && $o->depth >= $this->max_depth) { |
|
214 | $object->hints[] = 'depth_limit'; |
||
215 | |||
216 | $this->applyPlugins($var, $object, self::TRIGGER_DEPTH_LIMIT); |
||
217 | unset($this->object_hashes[$hash]); |
||
218 | |||
219 | return $object; |
||
220 | } |
||
221 | |||
222 | // ArrayObject (and maybe ArrayIterator, did not try yet) unsurprisingly |
||
223 | // consist of mainly dark magic. What bothers me most, var_dump sees no |
||
224 | // problem with it, and ArrayObject also uses a custom, undocumented |
||
225 | // serialize function, so you can see the properties in internal functions, |
||
226 | // but can never iterate some of them if the flags are not STD_PROP_LIST. Fun stuff. |
||
227 | if ($var instanceof ArrayObject) { |
||
228 | $ArrayObject_flags_stash = $var->getFlags(); |
||
229 | $var->setFlags(ArrayObject::STD_PROP_LIST); |
||
230 | } |
||
231 | |||
232 | $reflector = new ReflectionObject($var); |
||
233 | |||
234 | if ($reflector->isUserDefined()) { |
||
235 | $object->filename = $reflector->getFileName(); |
||
0 ignored issues
–
show
The property
filename does not seem to exist in Kint_Object .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
236 | $object->startline = $reflector->getStartLine(); |
||
0 ignored issues
–
show
The property
startline does not seem to exist in Kint_Object .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
237 | } |
||
238 | |||
239 | $rep = new Kint_Object_Representation('Properties'); |
||
240 | |||
241 | if (KINT_PHP522) { |
||
242 | $copy = array_values($values); |
||
243 | } |
||
244 | |||
245 | $i = 0; |
||
246 | |||
247 | // Reflection will not show parent classes private properties, and if a |
||
248 | // property was unset it will happly trigger a notice looking for it. |
||
249 | foreach ($values as $key => &$val) { |
||
250 | // Casting object to array: |
||
251 | // private properties show in the form "\0$owner_class_name\0$property_name"; |
||
252 | // protected properties show in the form "\0*\0$property_name"; |
||
253 | // public properties show in the form "$property_name"; |
||
254 | // http://www.php.net/manual/en/language.types.array.php#language.types.array.casting |
||
255 | |||
256 | $child = new Kint_Object(); |
||
257 | $child->depth = $object->depth + 1; |
||
258 | $child->owner_class = $object->classname; |
||
259 | $child->operator = Kint_Object::OPERATOR_OBJECT; |
||
260 | $child->access = Kint_Object::ACCESS_PUBLIC; |
||
261 | |||
262 | $split_key = explode("\0", $key, 3); |
||
263 | |||
264 | if (count($split_key) === 3 && $split_key[0] === '') { |
||
265 | $child->name = $split_key[2]; |
||
266 | if ($split_key[1] === '*') { |
||
267 | $child->access = Kint_Object::ACCESS_PROTECTED; |
||
268 | } else { |
||
269 | $child->access = Kint_Object::ACCESS_PRIVATE; |
||
270 | $child->owner_class = $split_key[1]; |
||
271 | } |
||
272 | } elseif (KINT_PHP72) { |
||
273 | $child->name = (string) $key; |
||
274 | } else { |
||
275 | $child->name = $key; |
||
276 | } |
||
277 | |||
278 | if ($this->childHasPath($object, $child)) { |
||
279 | $child->access_path = $object->access_path; |
||
280 | |||
281 | if (!KINT_PHP72 && is_int($child->name)) { |
||
282 | $child->access_path = 'array_values((array) '.$child->access_path.')['.$i.']'; |
||
283 | } elseif (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $child->name)) { |
||
284 | $child->access_path .= '->'.$child->name; |
||
285 | } else { |
||
286 | $child->access_path .= '->{'.var_export((string) $child->name, true).'}'; |
||
287 | } |
||
288 | } |
||
289 | |||
290 | View Code Duplication | if (KINT_PHP522) { |
|
291 | $stash = $val; |
||
292 | $copy[$i] = $this->marker; |
||
0 ignored issues
–
show
The variable
$copy 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
![]() |
|||
293 | if ($val === $this->marker) { |
||
294 | $child->reference = true; |
||
295 | $val = $stash; |
||
296 | } |
||
297 | } |
||
298 | |||
299 | $rep->contents[] = $this->parse($val, $child); |
||
300 | ++$i; |
||
301 | } |
||
302 | |||
303 | if (isset($ArrayObject_flags_stash)) { |
||
304 | $var->setFlags($ArrayObject_flags_stash); |
||
305 | } |
||
306 | |||
307 | usort($rep->contents, array('Kint_Parser', 'sortObjectProperties')); |
||
308 | |||
309 | $object->addRepresentation($rep); |
||
310 | $this->applyPlugins($var, $object, self::TRIGGER_SUCCESS); |
||
311 | unset($this->object_hashes[$hash]); |
||
312 | |||
313 | return $object; |
||
314 | } |
||
315 | |||
316 | private function parseResource(&$var, Kint_Object $o) |
||
317 | { |
||
318 | $resource = $o->transplant(new Kint_Object_Resource()); |
||
319 | $resource->resource_type = get_resource_type($var); |
||
0 ignored issues
–
show
The property
resource_type does not seem to exist in Kint_Object .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
320 | |||
321 | $this->applyPlugins($var, $resource, self::TRIGGER_SUCCESS); |
||
322 | |||
323 | return $resource; |
||
324 | } |
||
325 | |||
326 | private function parseUnknown(&$var, Kint_Object $o) |
||
327 | { |
||
328 | $o->type = 'unknown'; |
||
329 | $this->applyPlugins($var, $o, self::TRIGGER_SUCCESS); |
||
330 | |||
331 | return $o; |
||
332 | } |
||
333 | |||
334 | public function addPlugin(Kint_Parser_Plugin $p) |
||
335 | { |
||
336 | if (!$types = $p->getTypes()) { |
||
337 | return false; |
||
338 | } |
||
339 | |||
340 | if (!$triggers = $p->getTriggers()) { |
||
341 | return false; |
||
342 | } |
||
343 | |||
344 | $p->setParser($this); |
||
345 | |||
346 | foreach ($types as $type) { |
||
347 | if (!isset($this->plugins[$type])) { |
||
348 | $this->plugins[$type] = array( |
||
349 | self::TRIGGER_BEGIN => array(), |
||
350 | self::TRIGGER_SUCCESS => array(), |
||
351 | self::TRIGGER_RECURSION => array(), |
||
352 | self::TRIGGER_DEPTH_LIMIT => array(), |
||
353 | ); |
||
354 | } |
||
355 | |||
356 | foreach ($this->plugins[$type] as $trigger => &$pool) { |
||
357 | if ($triggers & $trigger) { |
||
358 | $pool[] = $p; |
||
359 | } |
||
360 | } |
||
361 | } |
||
362 | |||
363 | return true; |
||
364 | } |
||
365 | |||
366 | public function clearPlugins() |
||
367 | { |
||
368 | $this->plugins = array(); |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * Applies plugins for an object type. |
||
373 | * |
||
374 | * @param mixed &$var variable |
||
375 | * @param Kint_Object &$o Kint object parsed so far |
||
376 | * @param int $trigger The trigger to check for the plugins |
||
377 | * |
||
378 | * @return bool Continue parsing |
||
379 | */ |
||
380 | private function applyPlugins(&$var, Kint_Object &$o, $trigger) |
||
381 | { |
||
382 | $break_stash = $this->parse_break; |
||
383 | $this->parse_break = false; |
||
384 | |||
385 | $plugins = array(); |
||
386 | |||
387 | if (isset($this->plugins[$o->type][$trigger])) { |
||
388 | $plugins = $this->plugins[$o->type][$trigger]; |
||
389 | } |
||
390 | |||
391 | foreach ($plugins as $plugin) { |
||
392 | try { |
||
393 | $plugin->parse($var, $o, $trigger); |
||
394 | } catch (Exception $e) { |
||
395 | trigger_error( |
||
396 | 'An exception ('.get_class($e).') was thrown in '.$e->getFile().' on line '.$e->getLine().' while executing Kint Parser Plugin "'.get_class($plugin).'". Error message: '.$e->getMessage(), |
||
397 | E_USER_WARNING |
||
398 | ); |
||
399 | } |
||
400 | |||
401 | if ($this->parse_break) { |
||
402 | $this->parse_break = $break_stash; |
||
403 | |||
404 | return false; |
||
405 | } |
||
406 | } |
||
407 | |||
408 | $this->parse_break = $break_stash; |
||
409 | |||
410 | return true; |
||
411 | } |
||
412 | |||
413 | public function haltParse() |
||
414 | { |
||
415 | $this->parse_break = true; |
||
416 | } |
||
417 | |||
418 | public function childHasPath(Kint_Object_Instance $parent, Kint_Object $child) |
||
419 | { |
||
420 | if ($parent->type === 'object' && ($parent->access_path !== null || $child->static || $child->const)) { |
||
421 | if ($child->access === Kint_Object::ACCESS_PUBLIC) { |
||
422 | return true; |
||
423 | } elseif ($child->access === Kint_Object::ACCESS_PRIVATE && $this->caller_class && $this->caller_class === $child->owner_class) { |
||
424 | // We can't accurately determine owner class on statics / consts below 5.3 so deny |
||
425 | // the access path just to be sure. See ClassStatics for more info |
||
426 | if (KINT_PHP53 || (!$child->static && !$child->const)) { |
||
427 | return true; |
||
428 | } |
||
429 | } elseif ($child->access === Kint_Object::ACCESS_PROTECTED && $this->caller_class) { |
||
430 | if ($this->caller_class === $child->owner_class) { |
||
431 | return true; |
||
432 | } |
||
433 | if (is_subclass_of($this->caller_class, $child->owner_class)) { |
||
434 | return true; |
||
435 | } |
||
436 | if (is_subclass_of($child->owner_class, $this->caller_class)) { |
||
437 | return true; |
||
438 | } |
||
439 | } |
||
440 | } |
||
441 | |||
442 | return false; |
||
443 | } |
||
444 | |||
445 | /** |
||
446 | * Returns an array without the recursion marker in it. |
||
447 | * |
||
448 | * DO NOT pass an array that has had it's marker removed back |
||
449 | * into the parser, it will result in an extra recursion |
||
450 | * |
||
451 | * @param array $array Array potentially containing a recursion marker |
||
452 | * |
||
453 | * @return array Array with recursion marker removed |
||
454 | */ |
||
455 | public function getCleanArray(array $array) |
||
456 | { |
||
457 | unset($array[$this->marker]); |
||
458 | |||
459 | return $array; |
||
460 | } |
||
461 | |||
462 | private static function sortObjectProperties(Kint_Object $a, Kint_Object $b) |
||
463 | { |
||
464 | $sort = Kint_Object::sortByAccess($a, $b); |
||
465 | if ($sort) { |
||
466 | return $sort; |
||
467 | } |
||
468 | |||
469 | $sort = Kint_Object::sortByName($a, $b); |
||
470 | if ($sort) { |
||
471 | return $sort; |
||
472 | } |
||
473 | |||
474 | return Kint_Object_Instance::sortByHierarchy($a->owner_class, $b->owner_class); |
||
475 | } |
||
476 | } |
||
477 |
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.