Packages

  • 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

Classes

Interfaces

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