Packages

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