diff --git a/app/Config/core.php b/app/Config/core.php index 044dba4be..1c1283133 100644 --- a/app/Config/core.php +++ b/app/Config/core.php @@ -45,13 +45,16 @@ * including anonymous functions. * - `level` - int - The level of errors you are interested in capturing. * - `trace` - boolean - Include stack traces for errors in log files. + * - `handleFatalError` - boolean - Enable the CakePHP fatal error handler, generating custom + * pages for fatal errors instead of show broke pages. * * @see ErrorHandler for more information on error handling and configuration. */ Configure::write('Error', array( 'handler' => 'ErrorHandler::handleError', 'level' => E_ALL & ~E_DEPRECATED, - 'trace' => true + 'trace' => true, + 'handleFatalError' => true )); /** diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php index 9d47dd759..4340588f0 100644 --- a/lib/Cake/Core/Configure.php +++ b/lib/Cake/Core/Configure.php @@ -345,5 +345,6 @@ class Configure { if (!empty($exception['handler'])) { set_exception_handler($exception['handler']); } + register_shutdown_function('ErrorHandler::handleFatalError'); } } diff --git a/lib/Cake/Error/ErrorHandler.php b/lib/Cake/Error/ErrorHandler.php index 55c78bebe..79e948e21 100644 --- a/lib/Cake/Error/ErrorHandler.php +++ b/lib/Cake/Error/ErrorHandler.php @@ -183,6 +183,44 @@ class ErrorHandler { } } +/** + * Generate an error page when some fatal error happens. + * + * Use Configure::write('Error.handleFatalError', false) to disable this feature + * + * @return void + */ + public static function handleFatalError() { + if (Configure::read('Error.handleFatalError') !== true) { + return; + } + + $lastError = error_get_last(); + if (!is_array($lastError)) { + return; + } + + list($error, $log) = self::mapErrorCode($lastError['type']); + if ($log !== LOG_ERROR) { + return; + } + + $logMessage = $error . ' (' . $lastError['type'] . '): ' . $lastError['message'] . ' in [' . $lastError['file'] . ', line ' . $lastError['line'] . ']'; + CakeLog::write($log, $logMessage); + + $exceptionHandler = Configure::read('Exception.handler'); + if (!is_callable($exceptionHandler)) { + return; + } + + ob_clean(); + if (Configure::read('debug')) { + call_user_func($exceptionHandler, new FatalErrorException($lastError['message'], 500, $lastError['file'], $lastError['line'])); + } else { + call_user_func($exceptionHandler, new InternalErrorException()); + } + } + /** * Map an error code into an Error word, and log location. * diff --git a/lib/Cake/Error/exceptions.php b/lib/Cake/Error/exceptions.php index 6b6d1e26b..a64eee932 100644 --- a/lib/Cake/Error/exceptions.php +++ b/lib/Cake/Error/exceptions.php @@ -517,3 +517,30 @@ class XmlException extends CakeException { */ class ConsoleException extends CakeException { } + +/** + * Represents a fatal error + * + * @package Cake.Error + */ +class FatalErrorException extends CakeException { + +/** + * Constructor + * + * @param string $message + * @param integer $code + * @param string $file + * @param integer $line + */ + public function __construct($message, $code = 500, $file = null, $line = null) { + parent::__construct($message, $code); + if ($file) { + $this->file = $file; + } + if ($line) { + $this->line = $line; + } + } + +} diff --git a/lib/Cake/View/Errors/fatal_error.ctp b/lib/Cake/View/Errors/fatal_error.ctp new file mode 100644 index 000000000..d7c6e7606 --- /dev/null +++ b/lib/Cake/View/Errors/fatal_error.ctp @@ -0,0 +1,35 @@ + +
+
+ :
+ getMessage()); ?>
+
+
+ :
+ getFile()); ?>
+
+
+ :
+ getLine()); ?>
+
+ : + +