PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/core/classes/debug.php

https://bitbucket.org/codeyash/bootstrap
PHP | 504 lines | 337 code | 50 blank | 117 comment | 26 complexity | 44947bda82fb7aafd729b00c602770e7 MD5 | raw file
Possible License(s): MIT, Apache-2.0
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * Debug class
  15. *
  16. * The Debug class is a simple utility for debugging variables, objects, arrays, etc by outputting information to the display.
  17. *
  18. * @package Fuel
  19. * @category Core
  20. * @link http://docs.fuelphp.com/classes/debug.html
  21. */
  22. class Debug
  23. {
  24. public static $max_nesting_level = 5;
  25. public static $js_toggle_open = false;
  26. protected static $js_displayed = false;
  27. protected static $files = array();
  28. /**
  29. * Quick and nice way to output a mixed variable to the browser
  30. *
  31. * @static
  32. * @access public
  33. * @return string
  34. */
  35. public static function dump()
  36. {
  37. if (\Fuel::$is_cli)
  38. {
  39. // no fancy flying, jump dump 'm
  40. foreach (func_get_args() as $arg)
  41. {
  42. var_dump($arg);
  43. }
  44. }
  45. else
  46. {
  47. $backtrace = debug_backtrace();
  48. // If being called from within, show the file above in the backtrack
  49. if (strpos($backtrace[0]['file'], 'core/classes/debug.php') !== FALSE)
  50. {
  51. $callee = $backtrace[1];
  52. $label = \Inflector::humanize($backtrace[1]['function']);
  53. }
  54. else
  55. {
  56. $callee = $backtrace[0];
  57. $label = 'Debug';
  58. }
  59. $arguments = func_get_args();
  60. $callee['file'] = \Fuel::clean_path($callee['file']);
  61. if ( ! static::$js_displayed)
  62. {
  63. echo <<<JS
  64. <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>
  65. JS;
  66. static::$js_displayed = true;
  67. }
  68. echo '<div class="fuelphp-dump" style="font-size: 13px;background: #EEE !important; border:1px solid #666; color: #000 !important; padding:10px;">';
  69. echo '<h1 style="border-bottom: 1px solid #CCC; padding: 0 0 5px 0; margin: 0 0 5px 0; font: bold 120% sans-serif;">'.$callee['file'].' @ line: '.$callee['line'].'</h1>';
  70. echo '<pre style="overflow:auto;font-size:100%;">';
  71. $count = count($arguments);
  72. for ($i = 1; $i <= $count; $i++)
  73. {
  74. echo '<strong>Variable #'.$i.':</strong>'.PHP_EOL;
  75. echo static::format('', $arguments[$i - 1]);
  76. echo PHP_EOL.PHP_EOL;
  77. }
  78. echo "</pre>";
  79. echo "</div>";
  80. }
  81. }
  82. /**
  83. * Quick and nice way to output a mixed variable to the browser
  84. *
  85. * @static
  86. * @access public
  87. * @return string
  88. */
  89. public static function inspect()
  90. {
  91. $backtrace = debug_backtrace();
  92. // If being called from within, show the file above in the backtrack
  93. if (strpos($backtrace[0]['file'], 'core/classes/debug.php') !== FALSE)
  94. {
  95. $callee = $backtrace[1];
  96. $label = \Inflector::humanize($backtrace[1]['function']);
  97. }
  98. else
  99. {
  100. $callee = $backtrace[0];
  101. $label = 'Debug';
  102. }
  103. $arguments = func_get_args();
  104. $total_arguments = count($arguments);
  105. $callee['file'] = \Fuel::clean_path($callee['file']);
  106. if ( ! static::$js_displayed)
  107. {
  108. echo <<<JS
  109. <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>
  110. JS;
  111. static::$js_displayed = true;
  112. }
  113. echo '<div class="fuelphp-inspect" style="font-size: 13px;background: #EEE !important; border:1px solid #666; color: #000 !important; padding:10px;">';
  114. echo '<h1 style="border-bottom: 1px solid #CCC; padding: 0 0 5px 0; margin: 0 0 5px 0; font: bold 120% sans-serif;">'.$callee['file'].' @ line: '.$callee['line'].'</h1>';
  115. echo '<pre style="overflow:auto;font-size:100%;">';
  116. $i = 0;
  117. foreach ($arguments as $argument)
  118. {
  119. echo '<strong>'.$label.' #'.(++$i).' of '.$total_arguments.'</strong>:<br />';
  120. echo static::format('...', $argument);
  121. echo '<br />';
  122. }
  123. echo "</pre>";
  124. echo "</div>";
  125. }
  126. /**
  127. * Formats the given $var's output in a nice looking, Foldable interface.
  128. *
  129. * @param string $name the name of the var
  130. * @param mixed $var the variable
  131. * @param int $level the indentation level
  132. * @param string $indent_char the indentation character
  133. * @return string the formatted string.
  134. */
  135. public static function format($name, $var, $level = 0, $indent_char = '&nbsp;&nbsp;&nbsp;&nbsp;', $scope = '')
  136. {
  137. $return = str_repeat($indent_char, $level);
  138. if (is_array($var))
  139. {
  140. $id = 'fuel_debug_'.mt_rand();
  141. $return .= "<i>{$scope}</i> <strong>{$name}</strong>";
  142. $return .= " (Array, ".count($var)." element".(count($var)!=1?"s":"").")";
  143. if (count($var) > 0 and static::$max_nesting_level > $level)
  144. {
  145. $return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".(static::$js_toggle_open?"close":"open")."\">&crarr;</a>\n";
  146. }
  147. else
  148. {
  149. $return .= "\n";
  150. }
  151. if (static::$max_nesting_level <= $level)
  152. {
  153. $return .= str_repeat($indent_char, $level + 1)."...\n";
  154. }
  155. else
  156. {
  157. $sub_return = '';
  158. foreach ($var as $key => $val)
  159. {
  160. $sub_return .= static::format($key, $val, $level + 1);
  161. }
  162. if (count($var) > 0)
  163. {
  164. $return .= "<span id=\"$id\" style=\"display: ".(static::$js_toggle_open?"block":"none").";\">$sub_return</span>";
  165. }
  166. else
  167. {
  168. $return .= $sub_return;
  169. }
  170. }
  171. }
  172. elseif (is_string($var))
  173. {
  174. $return .= "<i>{$scope}</i> <strong>{$name}</strong> (String): <span style=\"color:#E00000;\">\"".htmlentities($var)."\"</span> (".strlen($var)." characters)\n";
  175. }
  176. elseif (is_float($var))
  177. {
  178. $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Float): {$var}\n";
  179. }
  180. elseif (is_long($var))
  181. {
  182. $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Integer): {$var}\n";
  183. }
  184. elseif (is_null($var))
  185. {
  186. $return .= "<i>{$scope}</i> <strong>{$name}</strong> : null\n";
  187. }
  188. elseif (is_bool($var))
  189. {
  190. $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Boolean): ".($var ? 'true' : 'false')."\n";
  191. }
  192. elseif (is_double($var))
  193. {
  194. $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Double): {$var}\n";
  195. }
  196. elseif (is_object($var))
  197. {
  198. // dirty hack to get the object id
  199. ob_start();
  200. var_dump($var);
  201. $contents = ob_get_contents();
  202. strpos($contents, 'xdebug-var-dump') !== false ? preg_match('~(.*?)\)\[<i>(\d+)(.*)~', $contents, $matches) : preg_match('~object\((.*?)#(\d+)(.*)~', $contents, $matches);
  203. ob_end_clean();
  204. $id = 'fuel_debug_'.mt_rand();
  205. $rvar = new \ReflectionObject($var);
  206. $vars = $rvar->getProperties();
  207. $return .= "<i>{$scope}</i> <strong>{$name}</strong> (Object #".$matches[2]."): ".get_class($var);
  208. if (count($vars) > 0 and static::$max_nesting_level > $level)
  209. {
  210. $return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".(static::$js_toggle_open?"close":"open")."\">&crarr;</a>\n";
  211. }
  212. $return .= "\n";
  213. $sub_return = '';
  214. foreach ($rvar->getProperties() as $prop)
  215. {
  216. $prop->isPublic() or $prop->setAccessible(true);
  217. if ($prop->isPrivate())
  218. {
  219. $scope = 'private';
  220. }
  221. elseif ($prop->isProtected())
  222. {
  223. $scope = 'protected';
  224. }
  225. else
  226. {
  227. $scope = 'public';
  228. }
  229. if (static::$max_nesting_level <= $level)
  230. {
  231. $sub_return .= str_repeat($indent_char, $level + 1)."...\n";
  232. }
  233. else
  234. {
  235. $sub_return .= static::format($prop->name, $prop->getValue($var), $level + 1, $indent_char, $scope);
  236. }
  237. }
  238. if (count($vars) > 0)
  239. {
  240. $return .= "<span id=\"$id\" style=\"display: ".(static::$js_toggle_open?"block":"none").";\">$sub_return</span>";
  241. }
  242. else
  243. {
  244. $return .= $sub_return;
  245. }
  246. }
  247. else
  248. {
  249. $return .= "<i>{$scope}</i> <strong>{$name}</strong>: {$var}\n";
  250. }
  251. return $return;
  252. }
  253. /**
  254. * Returns the debug lines from the specified file
  255. *
  256. * @access protected
  257. * @param string the file path
  258. * @param int the line number
  259. * @param bool whether to use syntax highlighting or not
  260. * @param int the amount of line padding
  261. * @return array
  262. */
  263. public static function file_lines($filepath, $line_num, $highlight = true, $padding = 5)
  264. {
  265. // deal with eval'd code
  266. if (strpos($filepath, 'eval()\'d code') !== false)
  267. {
  268. return '';
  269. }
  270. // We cache the entire file to reduce disk IO for multiple errors
  271. if ( ! isset(static::$files[$filepath]))
  272. {
  273. static::$files[$filepath] = file($filepath, FILE_IGNORE_NEW_LINES);
  274. array_unshift(static::$files[$filepath], '');
  275. }
  276. $start = $line_num - $padding;
  277. if ($start < 0)
  278. {
  279. $start = 0;
  280. }
  281. $length = ($line_num - $start) + $padding + 1;
  282. if (($start + $length) > count(static::$files[$filepath]) - 1)
  283. {
  284. $length = NULL;
  285. }
  286. $debug_lines = array_slice(static::$files[$filepath], $start, $length, TRUE);
  287. if ($highlight)
  288. {
  289. $to_replace = array('<code>', '</code>', '<span style="color: #0000BB">&lt;?php&nbsp;', "\n");
  290. $replace_with = array('', '', '<span style="color: #0000BB">', '');
  291. foreach ($debug_lines as & $line)
  292. {
  293. $line = str_replace($to_replace, $replace_with, highlight_string('<?php ' . $line, TRUE));
  294. }
  295. }
  296. return $debug_lines;
  297. }
  298. public static function backtrace()
  299. {
  300. return static::dump(debug_backtrace());
  301. }
  302. /**
  303. * Prints a list of all currently declared classes.
  304. *
  305. * @access public
  306. * @static
  307. */
  308. public static function classes()
  309. {
  310. return static::dump(get_declared_classes());
  311. }
  312. /**
  313. * Prints a list of all currently declared interfaces (PHP5 only).
  314. *
  315. * @access public
  316. * @static
  317. */
  318. public static function interfaces()
  319. {
  320. return static::dump(get_declared_interfaces());
  321. }
  322. /**
  323. * Prints a list of all currently included (or required) files.
  324. *
  325. * @access public
  326. * @static
  327. */
  328. public static function includes()
  329. {
  330. return static::dump(get_included_files());
  331. }
  332. /**
  333. * Prints a list of all currently declared functions.
  334. *
  335. * @access public
  336. * @static
  337. */
  338. public static function functions()
  339. {
  340. return static::dump(get_defined_functions());
  341. }
  342. /**
  343. * Prints a list of all currently declared constants.
  344. *
  345. * @access public
  346. * @static
  347. */
  348. public static function constants()
  349. {
  350. return static::dump(get_defined_constants());
  351. }
  352. /**
  353. * Prints a list of all currently loaded PHP extensions.
  354. *
  355. * @access public
  356. * @static
  357. */
  358. public static function extensions()
  359. {
  360. return static::dump(get_loaded_extensions());
  361. }
  362. /**
  363. * Prints a list of all HTTP request headers.
  364. *
  365. * @access public
  366. * @static
  367. */
  368. public static function headers()
  369. {
  370. // deal with fcgi installs on PHP 5.3
  371. if (version_compare(PHP_VERSION, '5.4.0') < 0 and ! function_exists('apache_request_headers'))
  372. {
  373. $headers = array();
  374. foreach (\Input::server() as $name => $value)
  375. {
  376. if (strpos($name, 'HTTP_') === 0)
  377. {
  378. $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
  379. $headers[$name] = $value;
  380. }
  381. elseif ($name == 'CONTENT_TYPE')
  382. {
  383. $headers['Content-Type'] = $value;
  384. }
  385. elseif ($name == 'CONTENT_LENGTH')
  386. {
  387. $headers['Content-Length'] = $value;
  388. }
  389. }
  390. }
  391. else
  392. {
  393. $headers = getAllHeaders();
  394. }
  395. return static::dump($headers);
  396. }
  397. /**
  398. * Prints a list of the configuration settings read from <i>php.ini</i>
  399. *
  400. * @access public
  401. * @static
  402. */
  403. public static function phpini()
  404. {
  405. if ( ! is_readable(get_cfg_var('cfg_file_path')))
  406. {
  407. return false;
  408. }
  409. // render it
  410. return static::dump(parse_ini_file(get_cfg_var('cfg_file_path'), true));
  411. }
  412. /**
  413. * Benchmark anything that is callable
  414. *
  415. * @access public
  416. * @static
  417. */
  418. public static function benchmark($callable, array $params = array())
  419. {
  420. // get the before-benchmark time
  421. if (function_exists('getrusage'))
  422. {
  423. $dat = getrusage();
  424. $utime_before = $dat['ru_utime.tv_sec'] + round($dat['ru_utime.tv_usec']/1000000, 4);
  425. $stime_before = $dat['ru_stime.tv_sec'] + round($dat['ru_stime.tv_usec']/1000000, 4);
  426. }
  427. else
  428. {
  429. list($usec, $sec) = explode(" ", microtime());
  430. $utime_before = ((float)$usec + (float)$sec);
  431. $stime_before = 0;
  432. }
  433. // call the function to be benchmarked
  434. $result = is_callable($callable) ? call_user_func_array($callable, $params) : null;
  435. // get the after-benchmark time
  436. if (function_exists('getrusage'))
  437. {
  438. $dat = getrusage();
  439. $utime_after = $dat['ru_utime.tv_sec'] + round($dat['ru_utime.tv_usec']/1000000, 4);
  440. $stime_after = $dat['ru_stime.tv_sec'] + round($dat['ru_stime.tv_usec']/1000000, 4);
  441. }
  442. else
  443. {
  444. list($usec, $sec) = explode(" ", microtime());
  445. $utime_after = ((float)$usec + (float)$sec);
  446. $stime_after = 0;
  447. }
  448. return array(
  449. 'user' => sprintf('%1.6f', $utime_after - $utime_before),
  450. 'system' => sprintf('%1.6f', $stime_after - $stime_before),
  451. 'result' => $result
  452. );
  453. }
  454. }