Namespaces

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

Classes

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

Interfaces

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