Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • Bar
  • BlueScreen
  • Debugger
  • FireLogger
  • Helpers
  • Logger

Interfaces

  • IBarPanel
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Diagnostics;
 13: 
 14: use Nette;
 15: 
 16: 
 17: 
 18: /**
 19:  * Debugger: displays and logs errors.
 20:  *
 21:  * Behavior is determined by two factors: mode & output
 22:  * - modes: production / development
 23:  * - output: HTML / AJAX / CLI / other (e.g. XML)
 24:  *
 25:  * @author     David Grudl
 26:  */
 27: final class Debugger
 28: {
 29:     /** @var bool in production mode is suppressed any debugging output */
 30:     public static $productionMode;
 31: 
 32:     /** @var bool in console mode is omitted HTML output */
 33:     public static $consoleMode;
 34: 
 35:     /** @var int timestamp with microseconds of the start of the request */
 36:     public static $time;
 37: 
 38:     /** @var bool is AJAX request detected? */
 39:     private static $ajaxDetected;
 40: 
 41:     /** @var string  requested URI or command line */
 42:     public static $source;
 43: 
 44:     /** @var string URL pattern mask to open editor */
 45:     public static $editor = 'editor://open/?file=%file&line=%line';
 46: 
 47:     /** @var string command to open browser (use 'start ""' in Windows) */
 48:     public static $browser;
 49: 
 50:     /********************* Debugger::dump() ****************d*g**/
 51: 
 52:     /** @var int  how many nested levels of array/object properties display {@link Debugger::dump()} */
 53:     public static $maxDepth = 3;
 54: 
 55:     /** @var int  how long strings display {@link Debugger::dump()} */
 56:     public static $maxLen = 150;
 57: 
 58:     /** @var bool display location? {@link Debugger::dump()} */
 59:     public static $showLocation = FALSE;
 60: 
 61:     /** @var array */
 62:     public static $consoleColors = array(
 63:         'bool' => '1;33',
 64:         'null' => '1;33',
 65:         'int' => '1;36',
 66:         'float' => '1;36',
 67:         'string' => '1;32',
 68:         'array' => '1;31',
 69:         'key' => '1;37',
 70:         'object' => '1;31',
 71:         'visibility' => '1;30',
 72:         'resource' => '1;37',
 73:     );
 74: 
 75:     /********************* errors and exceptions reporting ****************d*g**/
 76: 
 77:     /** server modes {@link Debugger::enable()} */
 78:     const DEVELOPMENT = FALSE,
 79:         PRODUCTION = TRUE,
 80:         DETECT = NULL;
 81: 
 82:     /** @var BlueScreen */
 83:     public static $blueScreen;
 84: 
 85:     /** @var bool|int determines whether any error will cause immediate death; if integer that it's matched against error severity */
 86:     public static $strictMode = FALSE; // $immediateDeath
 87: 
 88:     /** @var bool disables the @ (shut-up) operator so that notices and warnings are no longer hidden */
 89:     public static $scream = FALSE;
 90: 
 91:     /** @var array of callables specifies the functions that are automatically called after fatal error */
 92:     public static $onFatalError = array();
 93: 
 94:     /** @var bool {@link Debugger::enable()} */
 95:     private static $enabled = FALSE;
 96: 
 97:     /** @var mixed {@link Debugger::tryError()} FALSE means catching is disabled */
 98:     private static $lastError = FALSE;
 99: 
100:     /********************* logging ****************d*g**/
101: 
102:     /** @var Logger */
103:     public static $logger;
104: 
105:     /** @var FireLogger */
106:     public static $fireLogger;
107: 
108:     /** @var string name of the directory where errors should be logged; FALSE means that logging is disabled */
109:     public static $logDirectory;
110: 
111:     /** @var string email to sent error notifications */
112:     public static $email;
113: 
114:     /** @deprecated */
115:     public static $mailer;
116: 
117:     /** @deprecated */
118:     public static $emailSnooze;
119: 
120:     /********************* debug bar ****************d*g**/
121: 
122:     /** @var Bar */
123:     public static $bar;
124: 
125:     /** @var DefaultBarPanel */
126:     private static $errorPanel;
127: 
128:     /** @var DefaultBarPanel */
129:     private static $dumpPanel;
130: 
131:     /********************* Firebug extension ****************d*g**/
132: 
133:     /** {@link Debugger::log()} and {@link Debugger::fireLog()} */
134:     const DEBUG = 'debug',
135:         INFO = 'info',
136:         WARNING = 'warning',
137:         ERROR = 'error',
138:         CRITICAL = 'critical';
139: 
140: 
141: 
142:     /**
143:      * Static class - cannot be instantiated.
144:      */
145:     final public function __construct()
146:     {
147:         throw new Nette\StaticClassException;
148:     }
149: 
150: 
151: 
152:     /**
153:      * Static class constructor.
154:      * @internal
155:      */
156:     public static function _init()
157:     {
158:         self::$time = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(TRUE);
159:         self::$consoleMode = PHP_SAPI === 'cli';
160:         self::$productionMode = self::DETECT;
161:         if (self::$consoleMode) {
162:             self::$source = empty($_SERVER['argv']) ? 'cli' : 'cli: ' . implode(' ', $_SERVER['argv']);
163:         } else {
164:             self::$ajaxDetected = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
165:             if (isset($_SERVER['REQUEST_URI'])) {
166:                 self::$source = (isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https://' : 'http://')
167:                     . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''))
168:                     . $_SERVER['REQUEST_URI'];
169:             }
170:         }
171: 
172:         self::$logger = new Logger;
173:         self::$logDirectory = & self::$logger->directory;
174:         self::$email = & self::$logger->email;
175:         self::$mailer = & self::$logger->mailer;
176:         self::$emailSnooze = & Logger::$emailSnooze;
177: 
178:         self::$fireLogger = new FireLogger;
179: 
180:         self::$blueScreen = new BlueScreen;
181:         self::$blueScreen->addPanel(function($e) {
182:             if ($e instanceof Nette\Templating\FilterException) {
183:                 return array(
184:                     'tab' => 'Template',
185:                     'panel' => '<p><b>File:</b> ' . Helpers::editorLink($e->sourceFile, $e->sourceLine)
186:                     . '&nbsp; <b>Line:</b> ' . ($e->sourceLine ? $e->sourceLine : 'n/a') . '</p>'
187:                     . ($e->sourceLine ? BlueScreen::highlightFile($e->sourceFile, $e->sourceLine) : '')
188:                 );
189:             } elseif ($e instanceof Nette\Utils\NeonException && preg_match('#line (\d+)#', $e->getMessage(), $m)) {
190:                 if ($item = Helpers::findTrace($e->getTrace(), 'Nette\Config\Adapters\NeonAdapter::load')) {
191:                     return array(
192:                         'tab' => 'NEON',
193:                         'panel' => '<p><b>File:</b> ' . Helpers::editorLink($item['args'][0], $m[1]) . '&nbsp; <b>Line:</b> ' . $m[1] . '</p>'
194:                             . BlueScreen::highlightFile($item['args'][0], $m[1])
195:                     );
196:                 } elseif ($item = Helpers::findTrace($e->getTrace(), 'Nette\Utils\Neon::decode')) {
197:                     return array(
198:                         'tab' => 'NEON',
199:                         'panel' => BlueScreen::highlightPhp($item['args'][0], $m[1])
200:                     );
201:                 }
202:             }
203:         });
204: 
205:         self::$bar = new Bar;
206:         self::$bar->addPanel(new DefaultBarPanel('time'));
207:         self::$bar->addPanel(new DefaultBarPanel('memory'));
208:         self::$bar->addPanel(self::$errorPanel = new DefaultBarPanel('errors')); // filled by _errorHandler()
209:         self::$bar->addPanel(self::$dumpPanel = new DefaultBarPanel('dumps')); // filled by barDump()
210:     }
211: 
212: 
213: 
214:     /********************* errors and exceptions reporting ****************d*g**/
215: 
216: 
217: 
218:     /**
219:      * Enables displaying or logging errors and exceptions.
220:      * @param  mixed         production, development mode, autodetection or IP address(es) whitelist.
221:      * @param  string        error log directory; enables logging in production mode, FALSE means that logging is disabled
222:      * @param  string        administrator email; enables email sending in production mode
223:      * @return void
224:      */
225:     public static function enable($mode = NULL, $logDirectory = NULL, $email = NULL)
226:     {
227:         error_reporting(E_ALL | E_STRICT);
228: 
229:         // production/development mode detection
230:         if (is_bool($mode)) {
231:             self::$productionMode = $mode;
232: 
233:         } elseif ($mode !== self::DETECT || self::$productionMode === NULL) { // IP addresses or computer names whitelist detection
234:             $list = is_string($mode) ? preg_split('#[,\s]+#', $mode) : (array) $mode;
235:             if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
236:                 $list[] = '127.0.0.1';
237:                 $list[] = '::1';
238:             }
239:             self::$productionMode = !in_array(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n'), $list, TRUE);
240:         }
241: 
242:         // logging configuration
243:         if (is_string($logDirectory)) {
244:             self::$logDirectory = realpath($logDirectory);
245:             if (self::$logDirectory === FALSE) {
246:                 echo __METHOD__ . "() error: Log directory is not found or is not directory.\n";
247:                 exit(254);
248:             }
249:         } elseif ($logDirectory === FALSE) {
250:             self::$logDirectory = FALSE;
251: 
252:         } elseif (self::$logDirectory === NULL) {
253:             self::$logDirectory = defined('APP_DIR') ? APP_DIR . '/../log' : getcwd() . '/log';
254:         }
255:         if (self::$logDirectory) {
256:             ini_set('error_log', self::$logDirectory . '/php_error.log');
257:         }
258: 
259:         // php configuration
260:         if (function_exists('ini_set')) {
261:             ini_set('display_errors', !self::$productionMode); // or 'stderr'
262:             ini_set('html_errors', FALSE);
263:             ini_set('log_errors', FALSE);
264: 
265:         } elseif (ini_get('display_errors') != !self::$productionMode && ini_get('display_errors') !== (self::$productionMode ? 'stderr' : 'stdout')) { // intentionally ==
266:             echo __METHOD__ . "() error: Unable to set 'display_errors' because function ini_set() is disabled.\n";
267:             exit(254);
268:         }
269: 
270:         if ($email) {
271:             if (!is_string($email)) {
272:                 echo __METHOD__ . "() error: Email address must be a string.\n";
273:                 exit(254);
274:             }
275:             self::$email = $email;
276:         }
277: 
278:         if (!defined('E_DEPRECATED')) {
279:             define('E_DEPRECATED', 8192);
280:         }
281: 
282:         if (!defined('E_USER_DEPRECATED')) {
283:             define('E_USER_DEPRECATED', 16384);
284:         }
285: 
286:         if (!self::$enabled) {
287:             register_shutdown_function(array(__CLASS__, '_shutdownHandler'));
288:             set_exception_handler(array(__CLASS__, '_exceptionHandler'));
289:             set_error_handler(array(__CLASS__, '_errorHandler'));
290:             self::$enabled = TRUE;
291:         }
292:     }
293: 
294: 
295: 
296:     /**
297:      * Is Debug enabled?
298:      * @return bool
299:      */
300:     public static function isEnabled()
301:     {
302:         return self::$enabled;
303:     }
304: 
305: 
306: 
307:     /**
308:      * Logs message or exception to file (if not disabled) and sends email notification (if enabled).
309:      * @param  string|Exception
310:      * @param  int  one of constant Debugger::INFO, WARNING, ERROR (sends email), CRITICAL (sends email)
311:      * @return string logged error filename
312:      */
313:     public static function log($message, $priority = self::INFO)
314:     {
315:         if (self::$logDirectory === FALSE) {
316:             return;
317: 
318:         } elseif (!self::$logDirectory) {
319:             throw new Nette\InvalidStateException('Logging directory is not specified in Nette\Diagnostics\Debugger::$logDirectory.');
320:         }
321: 
322:         if ($message instanceof \Exception) {
323:             $exception = $message;
324:             $message = ($message instanceof Nette\FatalErrorException
325:                 ? 'Fatal error: ' . $exception->getMessage()
326:                 : get_class($exception) . ": " . $exception->getMessage())
327:                 . " in " . $exception->getFile() . ":" . $exception->getLine();
328: 
329:             $hash = md5($exception );
330:             $exceptionFilename = "exception-" . @date('Y-m-d-H-i-s') . "-$hash.html";
331:             foreach (new \DirectoryIterator(self::$logDirectory) as $entry) {
332:                 if (strpos($entry, $hash)) {
333:                     $exceptionFilename = $entry;
334:                     $saved = TRUE;
335:                     break;
336:                 }
337:             }
338:         }
339: 
340:         self::$logger->log(array(
341:             @date('[Y-m-d H-i-s]'),
342:             trim($message),
343:             self::$source ? ' @  ' . self::$source : NULL,
344:             !empty($exceptionFilename) ? ' @@  ' . $exceptionFilename : NULL
345:         ), $priority);
346: 
347:         if (!empty($exceptionFilename)) {
348:             $exceptionFilename = self::$logDirectory . '/' . $exceptionFilename;
349:             if (empty($saved) && $logHandle = @fopen($exceptionFilename, 'w')) {
350:                 ob_start(); // double buffer prevents sending HTTP headers in some PHP
351:                 ob_start(function($buffer) use ($logHandle) { fwrite($logHandle, $buffer); }, 4096);
352:                 self::$blueScreen->render($exception);
353:                 ob_end_flush();
354:                 ob_end_clean();
355:                 fclose($logHandle);
356:             }
357:             return strtr($exceptionFilename, '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
358:         }
359:     }
360: 
361: 
362: 
363:     /**
364:      * Shutdown handler to catch fatal errors and execute of the planned activities.
365:      * @return void
366:      * @internal
367:      */
368:     public static function _shutdownHandler()
369:     {
370:         if (!self::$enabled) {
371:             return;
372:         }
373: 
374:         // fatal error handler
375:         static $types = array(
376:             E_ERROR => 1,
377:             E_CORE_ERROR => 1,
378:             E_COMPILE_ERROR => 1,
379:             E_PARSE => 1,
380:         );
381:         $error = error_get_last();
382:         if (isset($types[$error['type']])) {
383:             self::_exceptionHandler(new Nette\FatalErrorException($error['message'], 0, $error['type'], $error['file'], $error['line'], NULL));
384:         }
385: 
386:         // debug bar (require HTML & development mode)
387:         if (self::$bar && !self::$productionMode && self::isHtmlMode()) {
388:             self::$bar->render();
389:         }
390:     }
391: 
392: 
393: 
394:     /**
395:      * Handler to catch uncaught exception.
396:      * @param  \Exception
397:      * @return void
398:      * @internal
399:      */
400:     public static function _exceptionHandler(\Exception $exception)
401:     {
402:         if (!headers_sent()) { // for PHP < 5.2.4
403:             $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
404:             header($protocol . ' 500', TRUE, 500);
405:         }
406: 
407:         try {
408:             if (self::$productionMode) {
409:                 try {
410:                     self::log($exception, self::ERROR);
411:                 } catch (\Exception $e) {
412:                     echo 'FATAL ERROR: unable to log error';
413:                 }
414: 
415:                 if (self::$consoleMode) {
416:                     echo "ERROR: the server encountered an internal error and was unable to complete your request.\n";
417: 
418:                 } elseif (self::isHtmlMode()) {
419:                     require __DIR__ . '/templates/error.phtml';
420:                 }
421: 
422:             } else {
423:                 if (self::$consoleMode) { // dump to console
424:                     echo "$exception\n";
425:                     if ($file = self::log($exception)) {
426:                         echo "(stored in $file)\n";
427:                         if (self::$browser) {
428:                             exec(self::$browser . ' ' . escapeshellarg($file));
429:                         }
430:                     }
431: 
432:                 } elseif (self::isHtmlMode()) { // dump to browser
433:                     self::$blueScreen->render($exception);
434:                     if (self::$bar) {
435:                         self::$bar->render();
436:                     }
437: 
438:                 } elseif (!self::fireLog($exception, self::ERROR)) { // AJAX or non-HTML mode
439:                     $file = self::log($exception);
440:                     if (!headers_sent()) {
441:                         header("X-Nette-Error-Log: $file");
442:                     }
443:                 }
444:             }
445: 
446:             foreach (self::$onFatalError as $handler) {
447:                 call_user_func($handler, $exception);
448:             }
449: 
450:         } catch (\Exception $e) {
451:             if (self::$productionMode) {
452:                 echo self::isHtmlMode() ? '<meta name=robots content=noindex>FATAL ERROR' : 'FATAL ERROR';
453:             } else {
454:                 echo "FATAL ERROR: thrown ", get_class($e), ': ', $e->getMessage(),
455:                     "\nwhile processing ", get_class($exception), ': ', $exception->getMessage(), "\n";
456:             }
457:         }
458: 
459:         self::$enabled = FALSE; // un-register shutdown function
460:         exit(254);
461:     }
462: 
463: 
464: 
465:     /**
466:      * Handler to catch warnings and notices.
467:      * @param  int    level of the error raised
468:      * @param  string error message
469:      * @param  string file that the error was raised in
470:      * @param  int    line number the error was raised at
471:      * @param  array  an array of variables that existed in the scope the error was triggered in
472:      * @return bool   FALSE to call normal error handler, NULL otherwise
473:      * @throws Nette\FatalErrorException
474:      * @internal
475:      */
476:     public static function _errorHandler($severity, $message, $file, $line, $context)
477:     {
478:         if (self::$scream) {
479:             error_reporting(E_ALL | E_STRICT);
480:         }
481: 
482:         if (self::$lastError !== FALSE && ($severity & error_reporting()) === $severity) { // tryError mode
483:             self::$lastError = new \ErrorException($message, 0, $severity, $file, $line);
484:             return NULL;
485:         }
486: 
487:         if ($severity === E_RECOVERABLE_ERROR || $severity === E_USER_ERROR) {
488:             if (Helpers::findTrace(debug_backtrace(FALSE), '*::__toString')) {
489:                 $previous = isset($context['e']) && $context['e'] instanceof \Exception ? $context['e'] : NULL;
490:                 self::_exceptionHandler(new Nette\FatalErrorException($message, 0, $severity, $file, $line, $context, $previous));
491:             }
492:             throw new Nette\FatalErrorException($message, 0, $severity, $file, $line, $context);
493: 
494:         } elseif (($severity & error_reporting()) !== $severity) {
495:             return FALSE; // calls normal error handler to fill-in error_get_last()
496: 
497:         } elseif (!self::$productionMode && (is_bool(self::$strictMode) ? self::$strictMode : ((self::$strictMode & $severity) === $severity))) {
498:             self::_exceptionHandler(new Nette\FatalErrorException($message, 0, $severity, $file, $line, $context));
499:         }
500: 
501:         static $types = array(
502:             E_WARNING => 'Warning',
503:             E_COMPILE_WARNING => 'Warning', // currently unable to handle
504:             E_USER_WARNING => 'Warning',
505:             E_NOTICE => 'Notice',
506:             E_USER_NOTICE => 'Notice',
507:             E_STRICT => 'Strict standards',
508:             E_DEPRECATED => 'Deprecated',
509:             E_USER_DEPRECATED => 'Deprecated',
510:         );
511: 
512:         $message = 'PHP ' . (isset($types[$severity]) ? $types[$severity] : 'Unknown error') . ": $message";
513:         $count = & self::$errorPanel->data["$message|$file|$line"];
514: 
515:         if ($count++) { // repeated error
516:             return NULL;
517: 
518:         } elseif (self::$productionMode) {
519:             self::log("$message in $file:$line", self::ERROR);
520:             return NULL;
521: 
522:         } else {
523:             $ok = self::fireLog(new \ErrorException($message, 0, $severity, $file, $line), self::WARNING);
524:             return !self::isHtmlMode() || (!self::$bar && !$ok) ? FALSE : NULL;
525:         }
526: 
527:         return FALSE; // call normal error handler
528:     }
529: 
530: 
531: 
532:     /**
533:      * Handles exception thrown in __toString().
534:      * @param  \Exception
535:      * @return void
536:      */
537:     public static function toStringException(\Exception $exception)
538:     {
539:         if (self::$enabled) {
540:             self::_exceptionHandler($exception);
541:         } else {
542:             trigger_error($exception->getMessage(), E_USER_ERROR);
543:         }
544:     }
545: 
546: 
547: 
548:     /**
549:      * Starts catching potential errors/warnings.
550:      * @return void
551:      */
552:     public static function tryError()
553:     {
554:         if (!self::$enabled && self::$lastError === FALSE) {
555:             set_error_handler(array(__CLASS__, '_errorHandler'));
556:         }
557:         self::$lastError = NULL;
558:     }
559: 
560: 
561: 
562:     /**
563:      * Returns catched error/warning message.
564:      * @param  \ErrorException  catched error
565:      * @return bool
566:      */
567:     public static function catchError(& $error)
568:     {
569:         if (!self::$enabled && self::$lastError !== FALSE) {
570:             restore_error_handler();
571:         }
572:         $error = self::$lastError;
573:         self::$lastError = FALSE;
574:         return (bool) $error;
575:     }
576: 
577: 
578: 
579:     /********************* useful tools ****************d*g**/
580: 
581: 
582: 
583:     /**
584:      * Dumps information about a variable in readable format.
585:      * @param  mixed  variable to dump
586:      * @param  bool   return output instead of printing it? (bypasses $productionMode)
587:      * @return mixed  variable itself or dump
588:      */
589:     public static function dump($var, $return = FALSE)
590:     {
591:         if (!$return && self::$productionMode) {
592:             return $var;
593:         }
594: 
595:         $output = "<pre class=\"nette-dump\">" . Helpers::htmlDump($var) . "</pre>\n";
596: 
597:         if (!$return) {
598:             $trace = debug_backtrace(FALSE);
599:             $item = Helpers::findTrace($trace, 'dump') ?: Helpers::findTrace($trace, __CLASS__ . '::dump');
600:             if (isset($item['file'], $item['line']) && is_file($item['file'])) {
601:                 $lines = file($item['file']);
602:                 preg_match('#dump\((.*)\)#', $lines[$item['line'] - 1], $m);
603:                 $output = substr_replace(
604:                     $output,
605:                     ' title="' . htmlspecialchars((isset($m[0]) ? "$m[0] \n" : '') . "in file {$item['file']} on line {$item['line']}") . '"',
606:                     4, 0);
607: 
608:                 if (self::$showLocation) {
609:                     $output = substr_replace(
610:                         $output,
611:                         ' <small>in ' . Helpers::editorLink($item['file'], $item['line']) . ":{$item['line']}</small>",
612:                         -8, 0);
613:                 }
614:             }
615:         }
616: 
617:         if (self::$consoleMode) {
618:             if (self::$consoleColors && substr(getenv('TERM'), 0, 5) === 'xterm') {
619:                 $output = preg_replace_callback('#<span class="php-(\w+)">|</span>#', function($m) {
620:                     return "\033[" . (isset($m[1], Debugger::$consoleColors[$m[1]]) ? Debugger::$consoleColors[$m[1]] : '0') . "m";
621:                 }, $output);
622:             }
623:             $output = htmlspecialchars_decode(strip_tags($output), ENT_QUOTES);
624:         }
625: 
626:         if ($return) {
627:             return $output;
628: 
629:         } else {
630:             echo $output;
631:             return $var;
632:         }
633:     }
634: 
635: 
636: 
637:     /**
638:      * Starts/stops stopwatch.
639:      * @param  string  name
640:      * @return float   elapsed seconds
641:      */
642:     public static function timer($name = NULL)
643:     {
644:         static $time = array();
645:         $now = microtime(TRUE);
646:         $delta = isset($time[$name]) ? $now - $time[$name] : 0;
647:         $time[$name] = $now;
648:         return $delta;
649:     }
650: 
651: 
652: 
653:     /**
654:      * Dumps information about a variable in Nette Debug Bar.
655:      * @param  mixed  variable to dump
656:      * @param  string optional title
657:      * @return mixed  variable itself
658:      */
659:     public static function barDump($var, $title = NULL)
660:     {
661:         if (!self::$productionMode) {
662:             $dump = array();
663:             foreach ((is_array($var) ? $var : array('' => $var)) as $key => $val) {
664:                 $dump[$key] = Helpers::clickableDump($val);
665:             }
666:             self::$dumpPanel->data[] = array('title' => $title, 'dump' => $dump);
667:         }
668:         return $var;
669:     }
670: 
671: 
672: 
673:     /**
674:      * Sends message to FireLogger console.
675:      * @param  mixed   message to log
676:      * @return bool    was successful?
677:      */
678:     public static function fireLog($message)
679:     {
680:         if (!self::$productionMode) {
681:             return self::$fireLogger->log($message);
682:         }
683:     }
684: 
685: 
686: 
687:     private static function isHtmlMode()
688:     {
689:         return !self::$ajaxDetected && !self::$consoleMode
690:             && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list()));
691:     }
692: 
693: 
694: 
695:     /** @deprecated */
696:     public static function addPanel(IBarPanel $panel, $id = NULL)
697:     {
698:         return self::$bar->addPanel($panel, $id);
699:     }
700: 
701: }
702: 
Nette Framework 2.0.7 API API documentation generated by ApiGen 2.8.0