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); |
||
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])) { |
|
0 ignored issues
–
show
|
|||
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) { |
|
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. ![]() |
|||
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) { |
|
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. ![]() |
|||
162 | $stash = $val; |
||
163 | $copy[$i] = $this->marker; |
||
164 | if ($val === $this->marker) { |
||
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')) { |
|
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. ![]() |
|||
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); |
||
200 | $object->hash = $hash; |
||
201 | $object->size = count($values); |
||
202 | |||
203 | View Code Duplication | if (isset($this->object_hashes[$hash])) { |
|
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. ![]() |
|||
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) { |
|
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. ![]() |
|||
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(); |
||
236 | $object->startline = $reflector->getStartLine(); |
||
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) { |
|
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. ![]() |
|||
291 | $stash = $val; |
||
292 | $copy[$i] = $this->marker; |
||
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); |
||
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 |
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.