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 | * @package Fuel\Common |
||
4 | * @version 2.0 |
||
5 | * @author Fuel Development Team |
||
6 | * @license MIT License |
||
7 | * @copyright 2010 - 2015 Fuel Development Team |
||
8 | * @link http://fuelphp.com |
||
9 | */ |
||
10 | |||
11 | namespace Fuel\Common; |
||
12 | |||
13 | /** |
||
14 | * Debug class, helper class to assign in debugging the application |
||
15 | * |
||
16 | * @package Fuel\Common |
||
17 | * |
||
18 | * @since 2.0 |
||
19 | */ |
||
20 | class Debug |
||
21 | { |
||
22 | /** |
||
23 | * @var int Maximum nesting level for dump output |
||
24 | */ |
||
25 | protected $maxNestingLevel = 5; |
||
26 | |||
27 | /** |
||
28 | * @var bool Whether or not the dump nesting is opened by default |
||
29 | */ |
||
30 | protected $jsOpenToggle = false; |
||
31 | |||
32 | /** |
||
33 | * @var bool Flag to track if the required javascript has already been sent |
||
34 | */ |
||
35 | protected $jsDisplayed = false; |
||
36 | |||
37 | /** |
||
38 | * @var array Cache for fileLines(), to avoid duplicate lookups |
||
39 | */ |
||
40 | protected $filesCache = array(); |
||
41 | |||
42 | /** |
||
43 | * @var DataContainer Input datacontainer |
||
44 | */ |
||
45 | protected $input; |
||
46 | |||
47 | /** |
||
48 | * @var Inflector Inflector instance |
||
49 | */ |
||
50 | protected $inflector; |
||
51 | |||
52 | /** |
||
53 | */ |
||
54 | public function __construct($input, $inflector) |
||
55 | { |
||
56 | $this->input = $input; |
||
57 | $this->inflector = $inflector; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Setter for maxNestingLevel |
||
62 | * |
||
63 | * @param int Maximum nesting level for dump output |
||
64 | * |
||
65 | * @return int The current nesting level |
||
66 | */ |
||
67 | public function setNestingLevel($level = null) |
||
68 | { |
||
69 | if (func_num_args() and is_numeric($level) and $level > 0) |
||
70 | { |
||
71 | $this->maxNestingLevel = $level; |
||
0 ignored issues
–
show
|
|||
72 | } |
||
73 | |||
74 | return $this->maxNestingLevel; |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * Setter for jsToggleOpen |
||
79 | * |
||
80 | * @param bool true for Open by default, false for closed |
||
81 | * |
||
82 | * @return bool The current toggle state |
||
83 | */ |
||
84 | public function setOpenToggle($toggle = null) |
||
85 | { |
||
86 | if (func_num_args() and is_bool($toggle)) |
||
87 | { |
||
88 | $this->jsOpenToggle = $toggle; |
||
89 | } |
||
90 | |||
91 | return $this->jsOpenToggle; |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * Quick and nice way to output mixed variable(s) |
||
96 | */ |
||
97 | public function dump() |
||
98 | { |
||
99 | if ((bool) defined('STDIN')) |
||
100 | { |
||
101 | // no fancy flying on the commandline, just dump 'm |
||
102 | foreach (func_get_args() as $arg) |
||
103 | { |
||
104 | var_dump($arg); |
||
105 | } |
||
106 | } |
||
107 | else |
||
108 | { |
||
109 | // @codeCoverageIgnoreStart |
||
110 | call_user_func_array(array($this, 'dumpAsHtml'), func_get_args()); |
||
111 | // @codeCoverageIgnoreEnd |
||
112 | } |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * Quick and nice way to output mixed variable(s) to the browser |
||
117 | */ |
||
118 | public function dumpAsHtml() |
||
119 | { |
||
120 | $arguments = func_get_args(); |
||
121 | $total = count($arguments); |
||
122 | |||
123 | $backtrace = debug_backtrace(); |
||
124 | |||
125 | // locate the first file entry that isn't this class itself |
||
126 | foreach ($backtrace as $stack => $trace) |
||
127 | { |
||
128 | if (isset($trace['file'])) |
||
129 | { |
||
130 | // If being called from within, or using call_user_func(), get the next entry |
||
131 | if (strpos($trace['function'], 'call_user_func') === 0 or (isset($trace['class']) and $trace['class'] == get_class($this))) |
||
132 | { |
||
133 | continue; |
||
134 | } |
||
135 | |||
136 | $callee = $trace; |
||
137 | $label = $this->inflector->humanize($backtrace[$stack+1]['function']); |
||
138 | |||
139 | // get info about what was dumped |
||
140 | $callee['code'] = ''; |
||
141 | for ($i = $callee['line']; $i > 0; $i--) |
||
142 | { |
||
143 | $line = $this->fileLines($callee['file'], $i, false, 0); |
||
144 | $callee['code'] = reset($line).' '.trim($callee['code']); |
||
145 | $tokens = token_get_all('<?php '.trim($callee['code'])); |
||
146 | if (is_array($tokens[1]) and isset($tokens[1][0]) and $tokens[1][0] != 377) |
||
147 | { |
||
148 | break; |
||
149 | } |
||
150 | } |
||
151 | |||
152 | $results = array(); |
||
153 | $r = false; |
||
154 | $c = 0; |
||
155 | |||
156 | foreach($tokens as $token) |
||
157 | { |
||
158 | // skip everything before our function call |
||
159 | if ($r === false) |
||
160 | { |
||
161 | if (isset($token[1]) and $token[1] == $callee['function']) |
||
162 | { |
||
163 | $r = 0; |
||
164 | } |
||
165 | continue; |
||
166 | } |
||
167 | |||
168 | // and quit if we find an end-of-statement |
||
169 | if ($token == ';') |
||
170 | { |
||
171 | break; |
||
172 | } |
||
173 | |||
174 | // check for a start-of-expresssion |
||
175 | elseif ($token == '(') |
||
176 | { |
||
177 | $c++; |
||
178 | if ($c === 1) |
||
179 | { |
||
180 | continue; |
||
181 | } |
||
182 | } |
||
183 | |||
184 | // check for an end-of-expresssion |
||
185 | elseif ($token == ')') |
||
186 | { |
||
187 | $c--; |
||
188 | if ($c === 0) |
||
189 | { |
||
190 | $r++; |
||
191 | continue; |
||
192 | } |
||
193 | } |
||
194 | |||
195 | // new expression in the same dump |
||
196 | elseif ($token == ',' and $c === 1) |
||
197 | { |
||
198 | $r++; |
||
199 | continue; |
||
200 | } |
||
201 | |||
202 | // make sure we have an array entry to add to, and add the token |
||
203 | if ( ! isset($results[$r])) |
||
204 | { |
||
205 | $results[$r] = ''; |
||
206 | } |
||
207 | $results[$r] .= is_array($token) ? $token[1] : $token; |
||
208 | } |
||
209 | |||
210 | // make sure we've parsed the same number of expressions as we have arguments |
||
211 | if (count($results) == $total) |
||
212 | { |
||
213 | $callee['code'] = $results; |
||
214 | } |
||
215 | else |
||
216 | { |
||
217 | // parsing failed, try it the old fashioned way |
||
218 | if (preg_match('/(.*'.$callee['function'].'\()(.*?)\);(.*)/', $callee['code'], $matches)) |
||
219 | { |
||
220 | $callee['code'] = 'Variable'.($total==1?'':'s').' dumped: '.$matches[2]; |
||
221 | } |
||
222 | } |
||
223 | |||
224 | $callee['file'] = cleanpath($callee['file']); |
||
225 | |||
226 | break; |
||
227 | } |
||
228 | } |
||
229 | |||
230 | if ( ! $this->jsDisplayed) |
||
231 | { |
||
232 | echo <<<JS |
||
233 | <script type="text/javascript">function fuel_debug_toggle(a){if(document.getElementById){if(document.getElementById(a).style.display=="none"){document.getElementById(a).style.display="block"}else{document.getElementById(a).style.display="none"}}else{if(document.layers){if(document.id.display=="none"){document.id.display="block"}else{document.id.display="none"}}else{if(document.all.id.style.display=="none"){document.all.id.style.display="block"}else{document.all.id.style.display="none"}}}};</script> |
||
234 | JS; |
||
235 | $this->jsDisplayed = true; |
||
236 | } |
||
237 | |||
238 | echo '<div class="fuelphp-dump" style="font-size: 13px;background: #EEE !important; border:1px solid #666; color: #000 !important; padding:10px;">'; |
||
239 | echo '<h1 style="padding: 0 0 5px 0; margin: 0; font: bold 110% sans-serif;">File: '.$callee['file'].' @ line: '.$callee['line'].'</h1>'; |
||
240 | if (is_string($callee['code'])) |
||
241 | { |
||
242 | echo '<h5 style="border-bottom: 1px solid #CCC;padding: 0 0 5px 0; margin: 0 0 5px 0; font: bold 85% sans-serif;">'.$callee['code'].'</h5>'.PHP_EOL; |
||
243 | } |
||
244 | echo '<pre style="overflow:auto;font-size:100%;">'; |
||
245 | |||
246 | $i = 0; |
||
247 | foreach ($arguments as $argument) |
||
248 | { |
||
249 | if (is_string($callee['code'])) |
||
250 | { |
||
251 | echo '<strong>Variable #'.(++$i).' of '.$total.':</strong>'.PHP_EOL; |
||
252 | } |
||
253 | elseif (substr(trim($callee['code'][$i]),0,1) == '$') |
||
254 | { |
||
255 | echo '<strong>Variable: '.trim($callee['code'][$i++]).'</strong>'.PHP_EOL; |
||
256 | } |
||
257 | else |
||
258 | { |
||
259 | echo '<strong>Expression: '.trim($callee['code'][$i++]).'</strong>'.PHP_EOL; |
||
260 | } |
||
261 | echo $this->format('', $argument); |
||
262 | if ($i < $total) |
||
263 | { |
||
264 | echo PHP_EOL; |
||
265 | } |
||
266 | } |
||
267 | |||
268 | echo "</pre>"; |
||
269 | echo "</div>"; |
||
270 | } |
||
271 | |||
272 | /** |
||
273 | * Formats the given $var's output in a nice looking, Foldable interface. |
||
274 | * |
||
275 | * @param string $name the name of the var |
||
276 | * @param mixed $var the variable |
||
277 | * @param int $level the indentation level |
||
278 | * @param string $indent_char the indentation character |
||
279 | * @return string the formatted string. |
||
280 | */ |
||
281 | public function format($name, $var, $level = 0, $indent_char = ' ', $scope = '') |
||
282 | { |
||
283 | static $itemCounter = 1; |
||
284 | |||
285 | $return = str_repeat($indent_char, $level); |
||
286 | |||
287 | if (is_array($var)) |
||
288 | { |
||
289 | $id = 'fuel_debug_'.$itemCounter++; |
||
290 | $return .= "<i>{$scope}</i> <strong>{$name}</strong>"; |
||
291 | $return .= " (Array, ".count($var)." element".(count($var)!=1?"s":"").")"; |
||
292 | if (count($var) > 0 and $this->maxNestingLevel > $level) |
||
293 | { |
||
294 | $return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".(($this->jsOpenToggle or $level == 0)?"close":"open")."\">↵</a>".PHP_EOL; |
||
295 | } |
||
296 | else |
||
297 | { |
||
298 | $return .= PHP_EOL; |
||
299 | } |
||
300 | |||
301 | if ($this->maxNestingLevel <= $level) |
||
302 | { |
||
303 | $return .= str_repeat($indent_char, $level + 1)."...".PHP_EOL; |
||
304 | } |
||
305 | else |
||
306 | { |
||
307 | $sub_return = ''; |
||
308 | foreach ($var as $key => $val) |
||
309 | { |
||
310 | $sub_return .= $this->format($key, $val, $level + 1); |
||
311 | } |
||
312 | View Code Duplication | if (count($var) > 0) |
|
313 | { |
||
314 | $return .= "<span id=\"$id\" style=\"display: ".(($this->jsOpenToggle or $level == 0)?"block":"none").";\">$sub_return</span>"; |
||
315 | } |
||
316 | else |
||
317 | { |
||
318 | $return .= $sub_return; |
||
319 | } |
||
320 | } |
||
321 | |||
322 | } |
||
323 | elseif (is_string($var)) |
||
324 | { |
||
325 | $return .= "<i>{$scope}</i> <strong>{$name}</strong> (String): <span style=\"color:#E00000;\">\"".htmlentities($var, ENT_QUOTES, 'UTF-8', false)."\"</span> (".strlen($var)." characters)".PHP_EOL; |
||
326 | } |
||
327 | elseif (is_float($var)) |
||
328 | { |
||
329 | $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Float): {$var}".PHP_EOL; |
||
330 | } |
||
331 | elseif (is_int($var)) |
||
332 | { |
||
333 | $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Integer): {$var}".PHP_EOL; |
||
334 | } |
||
335 | elseif (is_null($var)) |
||
336 | { |
||
337 | $return .= "<i>{$scope}</i> <strong>{$name}</strong> : null".PHP_EOL; |
||
338 | } |
||
339 | elseif (is_bool($var)) |
||
340 | { |
||
341 | $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Boolean): ".($var ? 'true' : 'false').PHP_EOL; |
||
342 | } |
||
343 | elseif (is_object($var)) |
||
344 | { |
||
345 | // dirty hack to get the object id |
||
346 | ob_start(); |
||
347 | var_dump($var); |
||
348 | $contents = ob_get_contents(); |
||
349 | ob_end_clean(); |
||
350 | |||
351 | // process it based on the xdebug presence and configuration |
||
352 | // @codeCoverageIgnoreStart |
||
353 | if (extension_loaded('xdebug') and ini_get('xdebug.overload_var_dump') === '1') |
||
354 | { |
||
355 | if (ini_get('html_errors')) |
||
356 | { |
||
357 | preg_match('~(.*?)\)\[<i>(\d+)(.*)~', $contents, $matches); |
||
358 | } |
||
359 | else |
||
360 | { |
||
361 | preg_match('~class (.*?)#(\d+)(.*)~', $contents, $matches); |
||
362 | } |
||
363 | } |
||
364 | else |
||
365 | { |
||
366 | preg_match('~object\((.*?)#(\d+)(.*)~', $contents, $matches); |
||
367 | } |
||
368 | // @codeCoverageIgnoreEnd |
||
369 | |||
370 | $id = 'fuel_debug_'.$itemCounter++; |
||
371 | $rvar = new \ReflectionObject($var); |
||
372 | $vars = $rvar->getProperties(); |
||
373 | $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Object #".$matches[2]."): ".get_class($var); |
||
374 | if (count($vars) > 0 and $this->maxNestingLevel > $level) |
||
375 | { |
||
376 | $return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".($this->jsOpenToggle?"close":"open")."\">↵</a>".PHP_EOL; |
||
377 | } |
||
378 | |||
379 | $sub_return = ''; |
||
380 | foreach ($rvar->getProperties() as $prop) |
||
381 | { |
||
382 | $prop->isPublic() or $prop->setAccessible(true); |
||
383 | if ($prop->isPrivate()) |
||
384 | { |
||
385 | $scope = '<span style="color:red;">private</span>'; |
||
386 | } |
||
387 | elseif ($prop->isProtected()) |
||
388 | { |
||
389 | $scope = '<span style="color:blue;">protected</span>'; |
||
390 | } |
||
391 | else |
||
392 | { |
||
393 | $scope = '<span style="color:green;">public</span>'; |
||
394 | } |
||
395 | if ($this->maxNestingLevel <= $level) |
||
396 | { |
||
397 | $sub_return .= str_repeat($indent_char, $level + 1)."...".PHP_EOL; |
||
398 | } |
||
399 | else |
||
400 | { |
||
401 | $sub_return .= $this->format($prop->name, $prop->getValue($var), $level + 1, $indent_char, $scope); |
||
402 | } |
||
403 | } |
||
404 | |||
405 | View Code Duplication | if (count($vars) > 0) |
|
406 | { |
||
407 | $return .= "<span id=\"$id\" style=\"display: ".($this->jsOpenToggle?"block":"none").";\">$sub_return</span>"; |
||
408 | } |
||
409 | else |
||
410 | { |
||
411 | $return .= $sub_return; |
||
412 | } |
||
413 | } |
||
414 | else |
||
415 | { |
||
416 | $return .= "<i>{$scope}</i> <strong>{$name}</strong>: {$var}".PHP_EOL; |
||
417 | } |
||
418 | return $return; |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * Returns the debug lines from the specified file |
||
423 | * |
||
424 | * @access protected |
||
425 | * @param string the file path |
||
426 | * @param int the line number |
||
427 | * @param bool whether to use syntax highlighting or not |
||
428 | * @param int the amount of line padding |
||
429 | * @return array |
||
430 | */ |
||
431 | public function fileLines($filepath, $line_num, $highlight = true, $padding = 5) |
||
432 | { |
||
433 | // deal with eval'd code |
||
434 | if (strpos($filepath, 'eval()\'d code') !== false) |
||
435 | { |
||
436 | return ''; |
||
437 | } |
||
438 | |||
439 | // We cache the entire file to reduce disk IO for multiple errors |
||
440 | if ( ! isset($this->filesCache[$filepath])) |
||
441 | { |
||
442 | $this->filesCache[$filepath] = file($filepath, FILE_IGNORE_NEW_LINES); |
||
443 | array_unshift($this->filesCache[$filepath], ''); |
||
444 | } |
||
445 | |||
446 | $start = max(0, $line_num - $padding); |
||
447 | $length = ($line_num - $start) + $padding + 1; |
||
448 | |||
449 | if (($start + $length) > count($this->filesCache[$filepath]) - 1) |
||
450 | { |
||
451 | $length = null; |
||
452 | } |
||
453 | |||
454 | $debug_lines = array_slice($this->filesCache[$filepath], $start, $length, true); |
||
455 | |||
456 | if ($highlight) |
||
457 | { |
||
458 | $to_replace = array('<code>', '</code>', '<span style="color: #0000BB"><?php ', PHP_EOL); |
||
459 | $replace_with = array('', '', '<span style="color: #0000BB">', ''); |
||
460 | |||
461 | foreach ($debug_lines as &$line) |
||
462 | { |
||
463 | $line = str_replace($to_replace, $replace_with, highlight_string('<?php ' . $line, true)); |
||
464 | } |
||
465 | } |
||
466 | |||
467 | return $debug_lines; |
||
468 | } |
||
469 | |||
470 | public function backtrace() |
||
471 | { |
||
472 | return $this->dump(debug_backtrace()); |
||
473 | } |
||
474 | |||
475 | /** |
||
476 | * Prints a list of all currently declared classes. |
||
477 | * |
||
478 | * @access public |
||
479 | */ |
||
480 | public function classes() |
||
481 | { |
||
482 | return $this->dump(get_declared_classes()); |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * Prints a list of all currently declared interfaces (PHP5 only). |
||
487 | * |
||
488 | * @access public |
||
489 | */ |
||
490 | public function interfaces() |
||
491 | { |
||
492 | return $this->dump(get_declared_interfaces()); |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * Prints a list of all currently included (or required) files. |
||
497 | * |
||
498 | * @access public |
||
499 | */ |
||
500 | public function includes() |
||
501 | { |
||
502 | return $this->dump(get_included_files()); |
||
503 | } |
||
504 | |||
505 | /** |
||
506 | * Prints a list of all currently declared functions. |
||
507 | * |
||
508 | * @access public |
||
509 | */ |
||
510 | public function functions() |
||
511 | { |
||
512 | return $this->dump(get_defined_functions()); |
||
513 | } |
||
514 | |||
515 | /** |
||
516 | * Prints a list of all currently declared constants. |
||
517 | * |
||
518 | * @access public |
||
519 | */ |
||
520 | public function constants() |
||
521 | { |
||
522 | return $this->dump(get_defined_constants()); |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Prints a list of all currently loaded PHP extensions. |
||
527 | * |
||
528 | * @access public |
||
529 | */ |
||
530 | public function extensions() |
||
531 | { |
||
532 | return $this->dump(get_loaded_extensions()); |
||
533 | } |
||
534 | |||
535 | /** |
||
536 | * Prints a list of all HTTP request headers. |
||
537 | * |
||
538 | * @access public |
||
539 | */ |
||
540 | public function headers() |
||
541 | { |
||
542 | // get the current request headers and dump them |
||
543 | return $this->dump($this->input->headers()); |
||
544 | } |
||
545 | |||
546 | /** |
||
547 | * Prints a list of the configuration settings read from <i>php.ini</i> |
||
548 | * |
||
549 | * @access public |
||
550 | */ |
||
551 | public function phpini() |
||
552 | { |
||
553 | return is_readable(get_cfg_var('cfg_file_path')) ? $this->dump(parse_ini_file(get_cfg_var('cfg_file_path'), true)) : false; |
||
554 | } |
||
555 | |||
556 | /** |
||
557 | * Benchmark anything that is callable |
||
558 | * |
||
559 | * @access public |
||
560 | */ |
||
561 | public function benchmark($callable, array $params = array()) |
||
562 | { |
||
563 | // get the before-benchmark time |
||
564 | list($usec, $sec) = explode(" ", microtime()); |
||
565 | $time_before = ((float)$usec + (float)$sec); |
||
566 | |||
567 | // call the function to be benchmarked |
||
568 | $result = is_callable($callable) ? call_user_func_array($callable, $params) : null; |
||
569 | |||
570 | // get the after-benchmark time |
||
571 | list($usec, $sec) = explode(" ", microtime()); |
||
572 | $time_after = ((float)$usec + (float)$sec); |
||
573 | |||
574 | return array( |
||
575 | 'time' => sprintf('%1.6f', $time_after - $time_before), |
||
576 | 'result' => $result |
||
577 | ); |
||
578 | } |
||
579 | |||
580 | } |
||
581 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.