PageRenderTime 66ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/system/classes/kohana/debug.php

https://github.com/plbabin/Hybride-Ironweb-2011
PHP | 464 lines | 295 code | 57 blank | 112 comment | 31 complexity | abff7aae5fd0ceb0a83b9b5df25e9c02 MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Contains debugging and dumping tools.
  4. *
  5. * @package Kohana
  6. * @category Base
  7. * @author Kohana Team
  8. * @copyright (c) 2008-2011 Kohana Team
  9. * @license http://kohanaphp.com/license
  10. */
  11. class Kohana_Debug {
  12. /**
  13. * Returns an HTML string of debugging information about any number of
  14. * variables, each wrapped in a "pre" tag:
  15. *
  16. * // Displays the type and value of each variable
  17. * echo Debug::vars($foo, $bar, $baz);
  18. *
  19. * @param mixed variable to debug
  20. * @param ...
  21. * @return string
  22. */
  23. public static function vars()
  24. {
  25. if (func_num_args() === 0)
  26. return;
  27. // Get all passed variables
  28. $variables = func_get_args();
  29. $output = array();
  30. foreach ($variables as $var)
  31. {
  32. $output[] = Debug::_dump($var, 1024);
  33. }
  34. return '<pre class="debug">'.implode("\n", $output).'</pre>';
  35. }
  36. /**
  37. * Returns an HTML string of information about a single variable.
  38. *
  39. * Borrows heavily on concepts from the Debug class of [Nette](http://nettephp.com/).
  40. *
  41. * @param mixed variable to dump
  42. * @param integer maximum length of strings
  43. * @return string
  44. */
  45. public static function dump($value, $length = 128)
  46. {
  47. return Debug::_dump($value, $length);
  48. }
  49. /**
  50. * Helper for Debug::dump(), handles recursion in arrays and objects.
  51. *
  52. * @param mixed variable to dump
  53. * @param integer maximum length of strings
  54. * @param integer recursion level (internal)
  55. * @return string
  56. */
  57. protected static function _dump( & $var, $length = 128, $level = 0)
  58. {
  59. if ($var === NULL)
  60. {
  61. return '<small>NULL</small>';
  62. }
  63. elseif (is_bool($var))
  64. {
  65. return '<small>bool</small> '.($var ? 'TRUE' : 'FALSE');
  66. }
  67. elseif (is_float($var))
  68. {
  69. return '<small>float</small> '.$var;
  70. }
  71. elseif (is_resource($var))
  72. {
  73. if (($type = get_resource_type($var)) === 'stream' AND $meta = stream_get_meta_data($var))
  74. {
  75. $meta = stream_get_meta_data($var);
  76. if (isset($meta['uri']))
  77. {
  78. $file = $meta['uri'];
  79. if (function_exists('stream_is_local'))
  80. {
  81. // Only exists on PHP >= 5.2.4
  82. if (stream_is_local($file))
  83. {
  84. $file = Debug::path($file);
  85. }
  86. }
  87. return '<small>resource</small><span>('.$type.')</span> '.htmlspecialchars($file, ENT_NOQUOTES, Kohana::$charset);
  88. }
  89. }
  90. else
  91. {
  92. return '<small>resource</small><span>('.$type.')</span>';
  93. }
  94. }
  95. elseif (is_string($var))
  96. {
  97. // Clean invalid multibyte characters. iconv is only invoked
  98. // if there are non ASCII characters in the string, so this
  99. // isn't too much of a hit.
  100. $var = UTF8::clean($var, Kohana::$charset);
  101. if (UTF8::strlen($var) > $length)
  102. {
  103. // Encode the truncated string
  104. $str = htmlspecialchars(UTF8::substr($var, 0, $length), ENT_NOQUOTES, Kohana::$charset).'&nbsp;&hellip;';
  105. }
  106. else
  107. {
  108. // Encode the string
  109. $str = htmlspecialchars($var, ENT_NOQUOTES, Kohana::$charset);
  110. }
  111. return '<small>string</small><span>('.strlen($var).')</span> "'.$str.'"';
  112. }
  113. elseif (is_array($var))
  114. {
  115. $output = array();
  116. // Indentation for this variable
  117. $space = str_repeat($s = ' ', $level);
  118. static $marker;
  119. if ($marker === NULL)
  120. {
  121. // Make a unique marker
  122. $marker = uniqid("\x00");
  123. }
  124. if (empty($var))
  125. {
  126. // Do nothing
  127. }
  128. elseif (isset($var[$marker]))
  129. {
  130. $output[] = "(\n$space$s*RECURSION*\n$space)";
  131. }
  132. elseif ($level < 5)
  133. {
  134. $output[] = "<span>(";
  135. $var[$marker] = TRUE;
  136. foreach ($var as $key => & $val)
  137. {
  138. if ($key === $marker) continue;
  139. if ( ! is_int($key))
  140. {
  141. $key = '"'.htmlspecialchars($key, ENT_NOQUOTES, Kohana::$charset).'"';
  142. }
  143. $output[] = "$space$s$key => ".Debug::_dump($val, $length, $level + 1);
  144. }
  145. unset($var[$marker]);
  146. $output[] = "$space)</span>";
  147. }
  148. else
  149. {
  150. // Depth too great
  151. $output[] = "(\n$space$s...\n$space)";
  152. }
  153. return '<small>array</small><span>('.count($var).')</span> '.implode("\n", $output);
  154. }
  155. elseif (is_object($var))
  156. {
  157. // Copy the object as an array
  158. $array = (array) $var;
  159. $output = array();
  160. // Indentation for this variable
  161. $space = str_repeat($s = ' ', $level);
  162. $hash = spl_object_hash($var);
  163. // Objects that are being dumped
  164. static $objects = array();
  165. if (empty($var))
  166. {
  167. // Do nothing
  168. }
  169. elseif (isset($objects[$hash]))
  170. {
  171. $output[] = "{\n$space$s*RECURSION*\n$space}";
  172. }
  173. elseif ($level < 10)
  174. {
  175. $output[] = "<code>{";
  176. $objects[$hash] = TRUE;
  177. foreach ($array as $key => & $val)
  178. {
  179. if ($key[0] === "\x00")
  180. {
  181. // Determine if the access is protected or protected
  182. $access = '<small>'.(($key[1] === '*') ? 'protected' : 'private').'</small>';
  183. // Remove the access level from the variable name
  184. $key = substr($key, strrpos($key, "\x00") + 1);
  185. }
  186. else
  187. {
  188. $access = '<small>public</small>';
  189. }
  190. $output[] = "$space$s$access $key => ".Debug::_dump($val, $length, $level + 1);
  191. }
  192. unset($objects[$hash]);
  193. $output[] = "$space}</code>";
  194. }
  195. else
  196. {
  197. // Depth too great
  198. $output[] = "{\n$space$s...\n$space}";
  199. }
  200. return '<small>object</small> <span>'.get_class($var).'('.count($array).')</span> '.implode("\n", $output);
  201. }
  202. else
  203. {
  204. return '<small>'.gettype($var).'</small> '.htmlspecialchars(print_r($var, TRUE), ENT_NOQUOTES, Kohana::$charset);
  205. }
  206. }
  207. /**
  208. * Removes application, system, modpath, or docroot from a filename,
  209. * replacing them with the plain text equivalents. Useful for debugging
  210. * when you want to display a shorter path.
  211. *
  212. * // Displays SYSPATH/classes/kohana.php
  213. * echo Debug::path(Kohana::find_file('classes', 'kohana'));
  214. *
  215. * @param string path to debug
  216. * @return string
  217. */
  218. public static function path($file)
  219. {
  220. if (strpos($file, APPPATH) === 0)
  221. {
  222. $file = 'APPPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(APPPATH));
  223. }
  224. elseif (strpos($file, SYSPATH) === 0)
  225. {
  226. $file = 'SYSPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(SYSPATH));
  227. }
  228. elseif (strpos($file, MODPATH) === 0)
  229. {
  230. $file = 'MODPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(MODPATH));
  231. }
  232. elseif (strpos($file, DOCROOT) === 0)
  233. {
  234. $file = 'DOCROOT'.DIRECTORY_SEPARATOR.substr($file, strlen(DOCROOT));
  235. }
  236. return $file;
  237. }
  238. /**
  239. * Returns an HTML string, highlighting a specific line of a file, with some
  240. * number of lines padded above and below.
  241. *
  242. * // Highlights the current line of the current file
  243. * echo Debug::source(__FILE__, __LINE__);
  244. *
  245. * @param string file to open
  246. * @param integer line number to highlight
  247. * @param integer number of padding lines
  248. * @return string source of file
  249. * @return FALSE file is unreadable
  250. */
  251. public static function source($file, $line_number, $padding = 5)
  252. {
  253. if ( ! $file OR ! is_readable($file))
  254. {
  255. // Continuing will cause errors
  256. return FALSE;
  257. }
  258. // Open the file and set the line position
  259. $file = fopen($file, 'r');
  260. $line = 0;
  261. // Set the reading range
  262. $range = array('start' => $line_number - $padding, 'end' => $line_number + $padding);
  263. // Set the zero-padding amount for line numbers
  264. $format = '% '.strlen($range['end']).'d';
  265. $source = '';
  266. while (($row = fgets($file)) !== FALSE)
  267. {
  268. // Increment the line number
  269. if (++$line > $range['end'])
  270. break;
  271. if ($line >= $range['start'])
  272. {
  273. // Make the row safe for output
  274. //$row = htmlspecialchars($row, ENT_NOQUOTES, Kohana::$charset);
  275. //$row
  276. // Trim whitespace and sanitize the row
  277. $row = '<span class="number">'.sprintf($format, $line).'</span> '.$row;
  278. if ($line === $line_number)
  279. {
  280. // Apply highlighting to this row
  281. $row = '<span class="line highlight">'.$row.'</span>';
  282. }
  283. else
  284. {
  285. $row = '<span class="line">'.$row.'</span>';
  286. }
  287. // Add to the captured source
  288. $source .= $row;
  289. }
  290. }
  291. // Close the file
  292. fclose($file);
  293. return '<pre class="source"><code>'.$source.'</code></pre>';
  294. }
  295. /**
  296. * Returns an array of HTML strings that represent each step in the backtrace.
  297. *
  298. * // Displays the entire current backtrace
  299. * echo implode('<br/>', Debug::trace());
  300. *
  301. * @param string path to debug
  302. * @return string
  303. */
  304. public static function trace(array $trace = NULL)
  305. {
  306. if ($trace === NULL)
  307. {
  308. // Start a new trace
  309. $trace = debug_backtrace();
  310. }
  311. // Non-standard function calls
  312. $statements = array('include', 'include_once', 'require', 'require_once');
  313. $output = array();
  314. foreach ($trace as $step)
  315. {
  316. if ( ! isset($step['function']))
  317. {
  318. // Invalid trace step
  319. continue;
  320. }
  321. if (isset($step['file']) AND isset($step['line']))
  322. {
  323. // Include the source of this step
  324. $source = Debug::source($step['file'], $step['line']);
  325. }
  326. if (isset($step['file']))
  327. {
  328. $file = $step['file'];
  329. if (isset($step['line']))
  330. {
  331. $line = $step['line'];
  332. }
  333. }
  334. // function()
  335. $function = $step['function'];
  336. if (in_array($step['function'], $statements))
  337. {
  338. if (empty($step['args']))
  339. {
  340. // No arguments
  341. $args = array();
  342. }
  343. else
  344. {
  345. // Sanitize the file path
  346. $args = array($step['args'][0]);
  347. }
  348. }
  349. elseif (isset($step['args']))
  350. {
  351. if ( ! function_exists($step['function']) OR strpos($step['function'], '{closure}') !== FALSE)
  352. {
  353. // Introspection on closures or language constructs in a stack trace is impossible
  354. $params = NULL;
  355. }
  356. else
  357. {
  358. if (isset($step['class']))
  359. {
  360. if (method_exists($step['class'], $step['function']))
  361. {
  362. $reflection = new ReflectionMethod($step['class'], $step['function']);
  363. }
  364. else
  365. {
  366. $reflection = new ReflectionMethod($step['class'], '__call');
  367. }
  368. }
  369. else
  370. {
  371. $reflection = new ReflectionFunction($step['function']);
  372. }
  373. // Get the function parameters
  374. $params = $reflection->getParameters();
  375. }
  376. $args = array();
  377. foreach ($step['args'] as $i => $arg)
  378. {
  379. if (isset($params[$i]))
  380. {
  381. // Assign the argument by the parameter name
  382. $args[$params[$i]->name] = $arg;
  383. }
  384. else
  385. {
  386. // Assign the argument by number
  387. $args[$i] = $arg;
  388. }
  389. }
  390. }
  391. if (isset($step['class']))
  392. {
  393. // Class->method() or Class::method()
  394. $function = $step['class'].$step['type'].$step['function'];
  395. }
  396. $output[] = array(
  397. 'function' => $function,
  398. 'args' => isset($args) ? $args : NULL,
  399. 'file' => isset($file) ? $file : NULL,
  400. 'line' => isset($line) ? $line : NULL,
  401. 'source' => isset($source) ? $source : NULL,
  402. );
  403. unset($function, $args, $file, $line, $source);
  404. }
  405. return $output;
  406. }
  407. }