Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Utils
  • none
  • Tracy
    • Bridges
      • Nette

Classes

  • Bar
  • BlueScreen
  • Debugger
  • Dumper
  • FireLogger
  • Helpers
  • Logger
  • OutputDebugger

Interfaces

  • IBarPanel
  • ILogger
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Tracy (https://tracy.nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Tracy;
  9: 
 10: 
 11: /**
 12:  * Debug Bar.
 13:  */
 14: class Bar
 15: {
 16:     /** @var IBarPanel[] */
 17:     private $panels = [];
 18: 
 19:     /** @var bool */
 20:     private $useSession;
 21: 
 22: 
 23:     /**
 24:      * Add custom panel.
 25:      * @param  IBarPanel
 26:      * @param  string
 27:      * @return static
 28:      */
 29:     public function addPanel(IBarPanel $panel, $id = NULL)
 30:     {
 31:         if ($id === NULL) {
 32:             $c = 0;
 33:             do {
 34:                 $id = get_class($panel) . ($c++ ? "-$c" : '');
 35:             } while (isset($this->panels[$id]));
 36:         }
 37:         $this->panels[$id] = $panel;
 38:         return $this;
 39:     }
 40: 
 41: 
 42:     /**
 43:      * Returns panel with given id
 44:      * @param  string
 45:      * @return IBarPanel|NULL
 46:      */
 47:     public function getPanel($id)
 48:     {
 49:         return isset($this->panels[$id]) ? $this->panels[$id] : NULL;
 50:     }
 51: 
 52: 
 53:     /**
 54:      * Renders debug bar.
 55:      * @return void
 56:      */
 57:     public function render()
 58:     {
 59:         $useSession = $this->useSession && session_status() === PHP_SESSION_ACTIVE;
 60:         $redirectQueue = &$_SESSION['_tracy']['redirect'];
 61: 
 62:         foreach (['bar', 'redirect', 'bluescreen'] as $key) {
 63:             $queue = &$_SESSION['_tracy'][$key];
 64:             $queue = array_slice((array) $queue, -10, NULL, TRUE);
 65:             $queue = array_filter($queue, function ($item) {
 66:                 return isset($item['time']) && $item['time'] > time() - 60;
 67:             });
 68:         }
 69: 
 70:         if (!Helpers::isHtmlMode() && !Helpers::isAjax()) {
 71:             return;
 72: 
 73:         } elseif (Helpers::isAjax()) {
 74:             $rows[] = (object) ['type' => 'ajax', 'panels' => $this->renderPanels('-ajax')];
 75:             $dumps = Dumper::fetchLiveData();
 76:             $contentId = $useSession ? $_SERVER['HTTP_X_TRACY_AJAX'] . '-ajax' : NULL;
 77: 
 78:         } elseif (preg_match('#^Location:#im', implode("\n", headers_list()))) { // redirect
 79:             Dumper::fetchLiveData();
 80:             Dumper::$livePrefix = count($redirectQueue) . 'p';
 81:             $redirectQueue[] = [
 82:                 'panels' => $this->renderPanels('-r' . count($redirectQueue)),
 83:                 'dumps' => Dumper::fetchLiveData(),
 84:                 'time' => time(),
 85:             ];
 86:             return;
 87: 
 88:         } else {
 89:             $rows[] = (object) ['type' => 'main', 'panels' => $this->renderPanels()];
 90:             $dumps = Dumper::fetchLiveData();
 91:             foreach (array_reverse((array) $redirectQueue) as $info) {
 92:                 $rows[] = (object) ['type' => 'redirect', 'panels' => $info['panels']];
 93:                 $dumps += $info['dumps'];
 94:             }
 95:             $redirectQueue = NULL;
 96:             $contentId = $useSession ? substr(md5(uniqid('', TRUE)), 0, 10) : NULL;
 97:         }
 98: 
 99:         ob_start(function () {});
100:         require __DIR__ . '/assets/Bar/panels.phtml';
101:         require __DIR__ . '/assets/Bar/bar.phtml';
102:         $content = Helpers::fixEncoding(ob_get_clean());
103: 
104:         if ($contentId) {
105:             $_SESSION['_tracy']['bar'][$contentId] = ['content' => $content, 'dumps' => $dumps, 'time' => time()];
106:         }
107: 
108:         if (Helpers::isHtmlMode()) {
109:             $nonce = Helpers::getNonce();
110:             require __DIR__ . '/assets/Bar/loader.phtml';
111:         }
112:     }
113: 
114: 
115:     /**
116:      * @return array
117:      */
118:     private function renderPanels($suffix = NULL)
119:     {
120:         set_error_handler(function ($severity, $message, $file, $line) {
121:             if (error_reporting() & $severity) {
122:                 throw new \ErrorException($message, 0, $severity, $file, $line);
123:             }
124:         });
125: 
126:         $obLevel = ob_get_level();
127:         $panels = [];
128: 
129:         foreach ($this->panels as $id => $panel) {
130:             $idHtml = preg_replace('#[^a-z0-9]+#i', '-', $id) . $suffix;
131:             try {
132:                 $tab = (string) $panel->getTab();
133:                 $panelHtml = $tab ? (string) $panel->getPanel() : NULL;
134:                 if ($tab && $panel instanceof \Nette\Diagnostics\IBarPanel) {
135:                     $e = new \Exception('Support for Nette\Diagnostics\IBarPanel is deprecated');
136:                 }
137: 
138:             } catch (\Throwable $e) {
139:             } catch (\Exception $e) {
140:             }
141:             if (isset($e)) {
142:                 while (ob_get_level() > $obLevel) { // restore ob-level if broken
143:                     ob_end_clean();
144:                 }
145:                 $idHtml = "error-$idHtml";
146:                 $tab = "Error in $id";
147:                 $panelHtml = "<h1>Error: $id</h1><div class='tracy-inner'>" . nl2br(Helpers::escapeHtml($e)) . '</div>';
148:                 unset($e);
149:             }
150:             $panels[] = (object) ['id' => $idHtml, 'tab' => $tab, 'panel' => $panelHtml];
151:         }
152: 
153:         restore_error_handler();
154:         return $panels;
155:     }
156: 
157: 
158:     /**
159:      * Renders debug bar assets.
160:      * @return bool
161:      */
162:     public function dispatchAssets()
163:     {
164:         $asset = isset($_GET['_tracy_bar']) ? $_GET['_tracy_bar'] : NULL;
165:         if ($asset === 'js') {
166:             header('Content-Type: text/javascript');
167:             header('Cache-Control: max-age=864000');
168:             header_remove('Pragma');
169:             header_remove('Set-Cookie');
170:             $this->renderAssets();
171:             return TRUE;
172:         }
173: 
174:         $this->useSession = session_status() === PHP_SESSION_ACTIVE;
175: 
176:         if ($this->useSession && Helpers::isAjax()) {
177:             header('X-Tracy-Ajax: 1'); // session must be already locked
178:         }
179: 
180:         if ($this->useSession && $asset && preg_match('#^content(-ajax)?.(\w+)$#', $asset, $m)) {
181:             $session = &$_SESSION['_tracy']['bar'][$m[2] . $m[1]];
182:             header('Content-Type: text/javascript');
183:             header('Cache-Control: max-age=60');
184:             header_remove('Set-Cookie');
185:             if (!$m[1]) {
186:                 $this->renderAssets();
187:             }
188:             if ($session) {
189:                 $method = $m[1] ? 'loadAjax' : 'init';
190:                 echo "Tracy.Debug.$method(", json_encode($session['content']), ', ', json_encode($session['dumps']), ');';
191:                 $session = NULL;
192:             }
193:             $session = &$_SESSION['_tracy']['bluescreen'][$m[2]];
194:             if ($session) {
195:                 echo "Tracy.BlueScreen.loadAjax(", json_encode($session['content']), ', ', json_encode($session['dumps']), ');';
196:                 $session = NULL;
197:             }
198:             return TRUE;
199:         }
200:     }
201: 
202: 
203:     private function renderAssets()
204:     {
205:         $css = array_map('file_get_contents', [
206:             __DIR__ . '/assets/Bar/bar.css',
207:             __DIR__ . '/assets/Toggle/toggle.css',
208:             __DIR__ . '/assets/Dumper/dumper.css',
209:             __DIR__ . '/assets/BlueScreen/bluescreen.css',
210:         ]);
211:         $css = json_encode(preg_replace('#\s+#u', ' ', implode($css)));
212:         echo "(function(){var el = document.createElement('style'); el.className='tracy-debug'; el.textContent=$css; document.head.appendChild(el);})();\n";
213: 
214:         array_map('readfile', [
215:             __DIR__ . '/assets/Bar/bar.js',
216:             __DIR__ . '/assets/Toggle/toggle.js',
217:             __DIR__ . '/assets/Dumper/dumper.js',
218:             __DIR__ . '/assets/BlueScreen/bluescreen.js',
219:         ]);
220:     }
221: 
222: }
223: 
Nette 2.4-20170221 API API documentation generated by ApiGen 2.8.0