1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Tracy;
9:
10: use Tracy;
11:
12:
13: 14: 15:
16: class OutputDebugger
17: {
18: const BOM = "\xEF\xBB\xBF";
19:
20:
21: private $list = array();
22:
23:
24: public static function enable()
25: {
26: $me = new static;
27: $me->start();
28: }
29:
30:
31: public function start()
32: {
33: foreach (get_included_files() as $file) {
34: if (fread(fopen($file, 'r'), 3) === self::BOM) {
35: $this->list[] = array($file, 1, self::BOM);
36: }
37: }
38: ob_start(array($this, 'handler'), PHP_VERSION_ID >= 50400 ? 1 : 2);
39: }
40:
41:
42:
43: public function handler($s, $phase)
44: {
45: $trace = debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE);
46: if (isset($trace[0]['file'], $trace[0]['line'])) {
47: $stack = $trace;
48: unset($stack[0]['line'], $stack[0]['args']);
49: $i = count($this->list);
50: if ($i && $this->list[$i - 1][3] === $stack) {
51: $this->list[$i - 1][2] .= $s;
52: } else {
53: $this->list[] = array($trace[0]['file'], $trace[0]['line'], $s, $stack);
54: }
55: }
56: if ($phase === PHP_OUTPUT_HANDLER_FINAL) {
57: return $this->renderHtml();
58: }
59: }
60:
61:
62: private function renderHtml()
63: {
64: $res = '<style>code, pre {white-space:nowrap} a {text-decoration:none} pre {color:gray;display:inline} big {color:red}</style><code>';
65: foreach ($this->list as $item) {
66: $stack = array();
67: foreach (array_slice($item[3], 1) as $t) {
68: $t += array('class' => '', 'type' => '', 'function' => '');
69: $stack[] = "$t[class]$t[type]$t[function]()"
70: . (isset($t['file'], $t['line']) ? ' in ' . basename($t['file']) . ":$t[line]" : '');
71: }
72:
73: $res .= Helpers::editorLink($item[0], $item[1]) . ' '
74: . '<span title="' . htmlspecialchars(implode("\n", $stack), ENT_IGNORE | ENT_QUOTES, 'UTF-8') . '">'
75: . str_replace(self::BOM, '<big>BOM</big>', Dumper::toHtml($item[2]))
76: . "</span><br>\n";
77: }
78: return $res . '</code>';
79: }
80:
81: }
82: