1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Tracy;
9:
10: use Tracy;
11:
12:
13: 14: 15: 16: 17:
18: class BlueScreen
19: {
20:
21: public $info = array();
22:
23:
24: private $panels = array();
25:
26:
27: public $collapsePaths = array();
28:
29:
30: public function __construct()
31: {
32: $this->collapsePaths[] = preg_match('#(.+/vendor)/tracy/tracy/src/Tracy$#', strtr(__DIR__, '\\', '/'), $m)
33: ? $m[1]
34: : __DIR__;
35: }
36:
37:
38: 39: 40: 41: 42:
43: public function addPanel($panel)
44: {
45: if (!in_array($panel, $this->panels, TRUE)) {
46: $this->panels[] = $panel;
47: }
48: return $this;
49: }
50:
51:
52: 53: 54: 55: 56:
57: public function render($exception)
58: {
59: $panels = $this->panels;
60: $info = array_filter($this->info);
61: require __DIR__ . '/templates/bluescreen.phtml';
62: }
63:
64:
65: 66: 67: 68: 69: 70: 71:
72: public static function highlightFile($file, $line, $lines = 15, array $vars = NULL)
73: {
74: $source = @file_get_contents($file);
75: if ($source) {
76: $source = static::highlightPhp($source, $line, $lines, $vars);
77: if ($editor = Helpers::editorUri($file, $line)) {
78: $source = substr_replace($source, ' data-tracy-href="' . htmlspecialchars($editor, ENT_QUOTES, 'UTF-8') . '"', 4, 0);
79: }
80: return $source;
81: }
82: }
83:
84:
85: 86: 87: 88: 89: 90: 91:
92: public static function highlightPhp($source, $line, $lines = 15, array $vars = NULL)
93: {
94: if (function_exists('ini_set')) {
95: ini_set('highlight.comment', '#998; font-style: italic');
96: ini_set('highlight.default', '#000');
97: ini_set('highlight.html', '#06B');
98: ini_set('highlight.keyword', '#D24; font-weight: bold');
99: ini_set('highlight.string', '#080');
100: }
101:
102: $source = str_replace(array("\r\n", "\r"), "\n", $source);
103: $source = explode("\n", highlight_string($source, TRUE));
104: $out = $source[0];
105: $source = str_replace('<br />', "\n", $source[1]);
106: $out .= static::highlightLine($source, $line, $lines);
107:
108: if ($vars) {
109: $out = preg_replace_callback('#">\$(\w+)( )?</span>#', function ($m) use ($vars) {
110: return array_key_exists($m[1], $vars)
111: ? '" title="'
112: . str_replace('"', '"', trim(strip_tags(Dumper::toHtml($vars[$m[1]], array(Dumper::DEPTH => 1)))))
113: . $m[0]
114: : $m[0];
115: }, $out);
116: }
117:
118: $out = str_replace(' ', ' ', $out);
119: return "<pre class='php'><div>$out</div></pre>";
120: }
121:
122:
123:
124: 125: 126: 127:
128: public static function highlightLine($html, $line, $lines = 15)
129: {
130: $source = explode("\n", "\n" . str_replace("\r\n", "\n", $html));
131: $out = '';
132: $spans = 1;
133: $start = $i = max(1, $line - floor($lines * 2 / 3));
134: while (--$i >= 1) {
135: if (preg_match('#.*(</?span[^>]*>)#', $source[$i], $m)) {
136: if ($m[1] !== '</span>') {
137: $spans++;
138: $out .= $m[1];
139: }
140: break;
141: }
142: }
143:
144: $source = array_slice($source, $start, $lines, TRUE);
145: end($source);
146: $numWidth = strlen((string) key($source));
147:
148: foreach ($source as $n => $s) {
149: $spans += substr_count($s, '<span') - substr_count($s, '</span');
150: $s = str_replace(array("\r", "\n"), array('', ''), $s);
151: preg_match_all('#<[^>]+>#', $s, $tags);
152: if ($n == $line) {
153: $out .= sprintf(
154: "<span class='highlight'>%{$numWidth}s: %s\n</span>%s",
155: $n,
156: strip_tags($s),
157: implode('', $tags[0])
158: );
159: } else {
160: $out .= sprintf("<span class='line'>%{$numWidth}s:</span> %s\n", $n, $s);
161: }
162: }
163: $out .= str_repeat('</span>', $spans) . '</code>';
164: return $out;
165: }
166:
167:
168: 169: 170: 171: 172:
173: public function isCollapsed($file)
174: {
175: foreach ($this->collapsePaths as $path) {
176: if (strpos(strtr($file, '\\', '/'), strtr("$path/", '\\', '/')) === 0) {
177: return TRUE;
178: }
179: }
180: return FALSE;
181: }
182:
183: }
184: