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