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
  • PHP

Classes

  • NDebugBar
  • NDebugBlueScreen
  • NDebugger
  • NDebugHelpers
  • NFireLogger
  • NLogger

Interfaces

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