Packages

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

Classes

  • Debugger
  • FireLogger
  • Logger

Interfaces

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