PageRenderTime 60ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/blog/engine/lib/external/HackerConsole/Main.php

https://github.com/diar/foodfood.ru
PHP | 309 lines | 196 code | 33 blank | 80 comment | 48 complexity | 29c1337e7158fec5777db62314057e92 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, GPL-3.0, GPL-2.0
  1. <?php
  2. /**
  3. * Debug_HackerConsole_Main: write debug messages into hidden console.
  4. * (C) 2005 Dmitry Koterov, http://forum.dklab.ru/users/DmitryKoterov/
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. * See http://www.gnu.org/copyleft/lesser.html
  11. * Console may be toggled using Shift+Ctrl+` (tilde) combination.
  12. *
  13. * @version 1.x $Id: Main.php 168 2007-01-30 21:12:03Z dk $
  14. */
  15. class Debug_HackerConsole_Main
  16. {
  17. var $_hc_height = "400"; // height of the console (pixels)
  18. var $_hc_entries = array();
  19. var $TAB_SIZE = 4;
  20. /**
  21. * constructor($autoAttachToHtmlOutput=true)
  22. * Create new console. If $autoAttachToHtmlOutput, output buffering
  23. * handler is set to automatically attach JavaScript showing code to
  24. * HTML page.
  25. */
  26. function Debug_HackerConsole_Main($autoAttach=false)
  27. {
  28. if ($autoAttach) ob_start(array(&$this, '_obHandler'));
  29. $GLOBALS['Debug_HackerConsole_Main_LAST'] =& $this;
  30. }
  31. /**
  32. * string attachToHtml(string $pageHtml)
  33. * Attach the console to given HTML page.
  34. */
  35. function attachToHtml($page)
  36. {
  37. $js = implode("", file(dirname(__FILE__).'/Js.js'));
  38. if (get_magic_quotes_runtime()) $js = stripslashes($js);
  39. $js = str_replace('{HEIGHT}', $this->_hc_height, $js);
  40. // We MUST use "hackerConsole" instead of "console" because of Safari.
  41. $code = "window.hackerConsole = window.hackerConsole || window.Debug_HackerConsole_Js && new window.Debug_HackerConsole_Js();\n";
  42. $code .= "if (window.hackerConsole) setTimeout(function() { with (window.hackerConsole) {\n";
  43. foreach ($this->_hc_entries as $gid=>$elements) {
  44. foreach ($elements as $e) {
  45. if ($e['tip'] === null) {
  46. $file = str_replace('\\', '/', $e['file']);
  47. if (isset($_SERVER['DOCUMENT_ROOT'])) {
  48. // Under IIS DOCUMENT_ROOT may not be available.
  49. $dr = str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']);
  50. $file = preg_replace('{^'.preg_quote($dr,'{}').'}is', '~', $file);
  51. }
  52. $title = "at {$file} line {$e['line']}" . (!empty($e['function'])? ", {$e['function']}" : "");
  53. } else {
  54. $title = $e['tip'];
  55. }
  56. $text = $this->toPre($e['text']);
  57. if (!empty($e['color'])) $text = "<div style=\"color:{$e['color']}\">$text</div>";
  58. $code .= " out(".$this->_toJs($text).", ".$this->_toJs($title).", ".$this->_toJs($gid).");\n";
  59. }
  60. }
  61. $code .= "}}, 200);";
  62. $html = '';
  63. // Dirty close opened tags. This is bad, but better than nothing...
  64. $lower = strtolower($page);
  65. if (strpos($lower, '</body>') === false) {
  66. foreach (array('script', 'xmp', 'pre') as $tag) {
  67. if (substr_count($lower, "<$tag") > substr_count($lower, "</$tag")) {
  68. $html .= "</$tag>";
  69. }
  70. }
  71. }
  72. $html .= "\n";
  73. $html .= "<!-- ##################### -->\n";
  74. $html .= "<!-- ### HackerConsole ### -->\n";
  75. $html .= "<!-- ##################### -->\n";
  76. $html .= "<script type=\"text/javascript\" language=\"JavaScript\">//<![CDATA[\n{$js}\n{$code}\n//]]></script>\n";
  77. $page = preg_replace('{(?=</body[^>]*>|$)}si', preg_replace('/([\\\\$])/', '\\\\$1', $html), $page, 1);
  78. return $page;
  79. }
  80. /**
  81. * void out(string $msg, string $group="message", $color=null, $tip=null)
  82. * Add new message to the console.
  83. * Messages may be grouped together using $group parameters for better view.
  84. * By default messages are tipped with caller context (file, line).
  85. * Contexts generated by call_user_func() are skipped!
  86. */
  87. function out($v, $group="message", $color=null, $tip=null)
  88. {
  89. static $dumpCnt;
  90. if (is_null($dumpCnt)) {
  91. $dumpCnt = 0;
  92. }
  93. // Have to work only with $obj, NOT $this!
  94. if (empty($this) || strtolower(get_class($this)) != 'debug_hackerconsole_main') {
  95. $obj =& $GLOBALS['Debug_HackerConsole_Main_LAST'];
  96. } else {
  97. $obj =& $this;
  98. }
  99. if (!$obj) return;
  100. // Detect caller if needed. Used in tip.
  101. $s = array();
  102. if ($tip === null) {
  103. // Find caller. Use call_user_func to get context of out() calling.
  104. $s = call_user_func(
  105. array(&$obj, 'debug_backtrace_smart'),
  106. 'call_user_func.*', // ignore indirect contexts
  107. true
  108. );
  109. }
  110. if (is_scalar($v)) $text = "$v\n";
  111. else $text = Debug_HackerConsole_Main::print_r($v, true);
  112. $obj->_hc_entries[$group][] = array(
  113. 'file' => isset($s['file'])? $s['file'] : null,
  114. 'line' => isset($s['line'])? $s['line'] : null,
  115. 'function' => isset($s['function'])? $s['function'] : null,
  116. 'text' => '#'.$dumpCnt.' '.$text,
  117. 'color' => $color,
  118. 'tip' => $tip,
  119. );
  120. $dumpCnt++;
  121. }
  122. /**
  123. * void disable()
  124. * Disable displaying of the console.
  125. */
  126. function disable()
  127. {
  128. // Work only with $obj, NOT $this!
  129. if (empty($this) || strtolower(get_class($this)) != 'debug_hackerconsole_main') {
  130. $obj =& $GLOBALS['Debug_HackerConsole_Main_LAST'];
  131. } else {
  132. $obj =& $this;
  133. }
  134. $obj->disabled = true;
  135. }
  136. /**
  137. * string toPre($text)
  138. * Format plaintext like <pre> tag does, but with <br> at the line tails
  139. * and &nbsp; in line prefixes.
  140. */
  141. function toPre($text, $tabSize=null)
  142. {
  143. $text = htmlspecialchars($text);
  144. // Expand tabulators.
  145. if ($tabSize === null) {
  146. if (isset($GLOBALS['Debug_HackerConsole_Main_LAST']))
  147. $tabSize = $GLOBALS['Debug_HackerConsole_Main_LAST']->TAB_SIZE;
  148. else
  149. $tabSize = 4;
  150. }
  151. $text = Debug_HackerConsole_Main::expandTabs($text, $tabSize);
  152. $text = str_replace(' ', '&nbsp;', $text);
  153. $text = nl2br($text);
  154. return $text;
  155. }
  156. /**
  157. * We need manual custom print_r() to use it in OB handlers
  158. * (original print_r() cannot work inside OB handler).
  159. */
  160. function print_r($obj, $no_print=0, $level=0)
  161. {
  162. if ($level < 10) {
  163. if (is_array($obj)) {
  164. $type = "Array[".count($obj)."]";
  165. } elseif (is_object($obj)) {
  166. $type = "Object";
  167. } elseif (gettype($obj) == "boolean") {
  168. $type = $obj? "TRUE" : "FALSE";
  169. } elseif ($obj === null) {
  170. $type = "NULL";
  171. } else {
  172. $type = preg_replace("/\r?\n/", "\\n", $obj);
  173. }
  174. $buf = $type;
  175. if (is_array($obj) || is_object($obj)) {
  176. $leftSp = str_repeat(" ", $level+1);
  177. for (reset($obj); list($k, $v) = each($obj); ) {
  178. if ($k === "GLOBALS") continue;
  179. $buf .= "\n{$leftSp}[$k] => ".Debug_HackerConsole_Main::print_r($v, $no_print, $level+1);
  180. }
  181. }
  182. } else {
  183. $buf = "*RECURSION*";
  184. }
  185. $buf = str_replace("\x00", " ", $buf); // PHP5 private methods contain \x00 in names
  186. if ($no_print) return $buf;
  187. else echo $buf;
  188. return null;
  189. }
  190. /**
  191. * string expandTabs($text, $tabSize=4)
  192. * Correctly convert tabulators to spaces.
  193. */
  194. function expandTabs($text, $tabSize=4)
  195. {
  196. $GLOBALS['expandTabs_tabSize'] = $tabSize;
  197. while (1) {
  198. $old = $text;
  199. $text = preg_replace_callback('/^([^\t\r\n]*)\t(\t*)/m', array('Debug_HackerConsole_Main', 'expandTabs_callback'), $text);
  200. if ($old === $text) return $text;
  201. }
  202. }
  203. function expandTabs_callback($m)
  204. {
  205. $tabSize = $GLOBALS['expandTabs_tabSize'];
  206. $n =
  207. intval((strlen($m[1]) + $tabSize) / $tabSize) * $tabSize
  208. - strlen($m[1])
  209. + strlen($m[2]) * $tabSize;
  210. return $m[1] . str_repeat(' ', $n);
  211. }
  212. /**
  213. * Internal methods.
  214. */
  215. function _obHandler($s)
  216. {
  217. return $this->attachToHtml($s);
  218. }
  219. function _toJs($a)
  220. {
  221. $a = addslashes($a);
  222. $a = str_replace(array("\n", "\r", ">", "<"), array('\n', '\r', "'+'>", "<'+'"), $a);
  223. return "'$a'";
  224. }
  225. /**
  226. * array debug_backtrace_smart($ignoresRe=null, $returnCaller=false)
  227. *
  228. * Return stacktrace. Correctly work with call_user_func*
  229. * (totally skip them correcting caller references).
  230. * If $returnCaller is true, return only first matched caller,
  231. * not all stacktrace.
  232. *
  233. * @version 2.03
  234. */
  235. function debug_backtrace_smart($ignoresRe=null, $returnCaller=false)
  236. {
  237. if (!is_callable($tracer='debug_backtrace')) return array();
  238. $trace = $tracer();
  239. if ($ignoresRe !== null) $ignoresRe = "/^(?>{$ignoresRe})$/six";
  240. $smart = array();
  241. $framesSeen = 0;
  242. for ($i=0, $n=count($trace); $i<$n; $i++) {
  243. $t = $trace[$i];
  244. if (!$t) continue;
  245. // Next frame.
  246. $next = isset($trace[$i+1])? $trace[$i+1] : null;
  247. // Dummy frame before call_user_func* frames.
  248. if (!isset($t['file'])) {
  249. $t['over_function'] = $trace[$i+1]['function'];
  250. $t = $t + $trace[$i+1];
  251. $trace[$i+1] = null; // skip call_user_func on next iteration
  252. }
  253. // Skip myself frame.
  254. if (++$framesSeen < 2) continue;
  255. // 'class' and 'function' field of next frame define where
  256. // this frame function situated. Skip frames for functions
  257. // situated in ignored places.
  258. if ($ignoresRe && $next) {
  259. // Name of function "inside which" frame was generated.
  260. $frameCaller = (isset($next['class'])? $next['class'].'::' : '') . (isset($next['function'])? $next['function'] : '');
  261. if (preg_match($ignoresRe, $frameCaller)) continue;
  262. }
  263. // On each iteration we consider ability to add PREVIOUS frame
  264. // to $smart stack.
  265. if ($returnCaller) return $t;
  266. $smart[] = $t;
  267. }
  268. return $smart;
  269. }
  270. }
  271. /**
  272. * Last created console.
  273. */
  274. $GLOBALS['Debug_HackerConsole_Main_LAST'] = null;
  275. ?>