From 1428659f88579f6cd0145deb30d4e8cd78fb09ff Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Sat, 31 Mar 2012 17:51:43 -0400 Subject: [PATCH] Moved the fatal error detection to App::shutdown and keeping the fatal error handler cleaner. It helps to be extended by applications/plugins. --- app/Config/core.php | 8 +++--- .../Console/Templates/skel/Config/core.php | 3 ++ lib/Cake/Core/App.php | 28 ++++++++++++++++++- lib/Cake/Core/Configure.php | 1 - lib/Cake/Error/ErrorHandler.php | 25 ++++------------- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/app/Config/core.php b/app/Config/core.php index 1c1283133b4..a36970f1698 100644 --- a/app/Config/core.php +++ b/app/Config/core.php @@ -41,20 +41,20 @@ * * Options: * + * - `handleFatalError` - callback - The callback to handle fatal errors. You can set this to any + * callback type, including anonymous functions. * - `handler` - callback - The callback to handle errors. You can set this to any callback type, * 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( + 'handleFatalError' => 'ErrorHandler::handleFatalError', 'handler' => 'ErrorHandler::handleError', 'level' => E_ALL & ~E_DEPRECATED, - 'trace' => true, - 'handleFatalError' => true + 'trace' => true )); /** diff --git a/lib/Cake/Console/Templates/skel/Config/core.php b/lib/Cake/Console/Templates/skel/Config/core.php index 20c354bc96b..cf22ed415d9 100644 --- a/lib/Cake/Console/Templates/skel/Config/core.php +++ b/lib/Cake/Console/Templates/skel/Config/core.php @@ -41,6 +41,8 @@ * * Options: * + * - `handleFatalError` - callback - The callback to handle fatal errors. You can set this to any + * callback type, including anonymous functions. * - `handler` - callback - The callback to handle errors. You can set this to any callback type, * including anonymous functions. * - `level` - int - The level of errors you are interested in capturing. @@ -49,6 +51,7 @@ * @see ErrorHandler for more information on error handling and configuration. */ Configure::write('Error', array( + 'handleFatalError' => 'ErrorHandler::handleFatalError', 'handler' => 'ErrorHandler::handleError', 'level' => E_ALL & ~E_DEPRECATED, 'trace' => true diff --git a/lib/Cake/Core/App.php b/lib/Cake/Core/App.php index e0817462a0e..fcc495b1815 100644 --- a/lib/Cake/Core/App.php +++ b/lib/Cake/Core/App.php @@ -881,7 +881,8 @@ protected static function _packageFormat() { /** * Object destructor. * - * Writes cache file if changes have been made to the $_map + * Writes cache file if changes have been made to the $_map. Also, check if a fatal + * error happened and call the handler. * * @return void */ @@ -892,6 +893,31 @@ public static function shutdown() { if (self::$_objectCacheChange) { Cache::write('object_map', self::$_objects, '_cake_core_'); } + + self::_checkFatalError(); + } + +/** + * Check if a fatal error happened and trigger the configured handler if configured + * + * @return void + */ + protected static function _checkFatalError() { + $lastError = error_get_last(); + if (!is_array($lastError)) { + return; + } + + list(, $log) = ErrorHandler::mapErrorCode($lastError['type']); + if ($log !== LOG_ERROR) { + return; + } + + $fatalErrorHandler = Configure::read('Error.handleFatalError'); + if (!is_callable($fatalErrorHandler)) { + return; + } + call_user_func($fatalErrorHandler, $lastError); } } diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php index 4340588f031..9d47dd759d9 100644 --- a/lib/Cake/Core/Configure.php +++ b/lib/Cake/Core/Configure.php @@ -345,6 +345,5 @@ protected static function _setErrorHandlers($error, $exception) { 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 79e948e21ef..8a05b6e2c58 100644 --- a/lib/Cake/Error/ErrorHandler.php +++ b/lib/Cake/Error/ErrorHandler.php @@ -186,27 +186,12 @@ public static function handleError($code, $description, $file = null, $line = nu /** * Generate an error page when some fatal error happens. * - * Use Configure::write('Error.handleFatalError', false) to disable this feature - * + * @param array $error Array with error information. See `error_get_last()` function * @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); + public static function handleFatalError($error) { + $logMessage = 'Fatal Error (' . $error['type'] . '): ' . $error['message'] . ' in [' . $error['file'] . ', line ' . $error['line'] . ']'; + CakeLog::write(LOG_ERROR, $logMessage); $exceptionHandler = Configure::read('Exception.handler'); if (!is_callable($exceptionHandler)) { @@ -215,7 +200,7 @@ public static function handleFatalError() { ob_clean(); if (Configure::read('debug')) { - call_user_func($exceptionHandler, new FatalErrorException($lastError['message'], 500, $lastError['file'], $lastError['line'])); + call_user_func($exceptionHandler, new FatalErrorException($error['message'], 500, $error['file'], $error['line'])); } else { call_user_func($exceptionHandler, new InternalErrorException()); }