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