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