Permalink
Browse files

Merge branch '2.2-fatal-error' into 2.2

  • Loading branch information...
jrbasso committed Apr 14, 2012
2 parents f677bfe + 9beaa96 commit 072aee0a0f83a10263928f00d0eedf48c1a826e7
View
@@ -41,7 +41,7 @@
*
* Options:
*
- * - `handler` - callback - The callback to handle errors. You can set this to any callback type,
+ * - `handler` - callback - The callback to handle errors. You can set this to any callable 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.
@@ -41,7 +41,7 @@
*
* Options:
*
- * - `handler` - callback - The callback to handle errors. You can set this to any callback type,
+ * - `handler` - callback - The callback to handle errors. You can set this to any callable 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.
View
@@ -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;
+ }
+
+ $errorHandler = Configure::read('Error.handler');
+ if (!is_callable($errorHandler)) {
+ return;
+ }
+ call_user_func($errorHandler, $lastError['type'], $lastError['message'], $lastError['file'], $lastError['line'], array());
}
}
@@ -158,6 +158,9 @@ public static function handleError($code, $description, $file = null, $line = nu
}
$errorConfig = Configure::read('Error');
list($error, $log) = self::mapErrorCode($code);
+ if ($log === LOG_ERROR) {
+ return self::handleFatalError($code, $description, $file, $line);
+ }
$debug = Configure::read('debug');
if ($debug) {
@@ -183,6 +186,33 @@ public static function handleError($code, $description, $file = null, $line = nu
}
}
+/**
+ * Generate an error page when some fatal error happens.
+ *
+ * @param integer $code Code of error
+ * @param string $description Error description
+ * @param string $file File on which error occurred
+ * @param integer $line Line that triggered the error
+ * @return boolean
+ */
+ public static function handleFatalError($code, $description, $file, $line) {
+ $logMessage = 'Fatal Error (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']';
+ CakeLog::write(LOG_ERROR, $logMessage);
+
+ $exceptionHandler = Configure::read('Exception.handler');
+ if (!is_callable($exceptionHandler)) {
+ return false;
+ }
+
+ ob_clean();
+ if (Configure::read('debug')) {
+ call_user_func($exceptionHandler, new FatalErrorException($description, 500, $file, $line));
+ } else {
+ call_user_func($exceptionHandler, new InternalErrorException());
+ }
+ return false;
+ }
+
/**
* Map an error code into an Error word, and log location.
*
@@ -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;
+ }
+ }
+
+}
@@ -89,7 +89,6 @@ public static function errorProvider() {
return array(
array(E_USER_NOTICE, 'Notice'),
array(E_USER_WARNING, 'Warning'),
- array(E_USER_ERROR, 'Fatal Error'),
);
}
@@ -194,7 +193,7 @@ public function testHandleException() {
}
/**
- * test handleException generating a page.
+ * test handleException generating log.
*
* @return void
*/
@@ -238,4 +237,55 @@ public function testLoadPluginHanlder() {
CakePlugin::unload();
}
+/**
+ * test handleFatalError generating a page.
+ *
+ * @return void
+ */
+ public function testHandleFatalErrorPage() {
+ $this->skipIf(file_exists(APP . 'app_error.php'), 'App error exists cannot run.');
+
+ $originalDebugLevel = Configure::read('debug');
+ $line = __LINE__;
+
+ ob_start();
+ Configure::write('debug', 1);
+ ErrorHandler::handleFatalError(E_ERROR, 'Something wrong', __FILE__, $line);
+ $result = ob_get_clean();
+ $this->assertContains('Something wrong', $result, 'message missing.');
+ $this->assertContains(__FILE__, $result, 'filename missing.');
+ $this->assertContains((string)$line, $result, 'line missing.');
+
+ ob_start();
+ Configure::write('debug', 0);
+ ErrorHandler::handleFatalError(E_ERROR, 'Something wrong', __FILE__, $line);
+ $result = ob_get_clean();
+ $this->assertNotContains('Something wrong', $result, 'message must not appear.');
+ $this->assertNotContains(__FILE__, $result, 'filename must not appear.');
+ $this->assertContains('An Internal Error Has Occurred', $result);
+
+ Configure::write('debug', $originalDebugLevel);
+ }
+
+/**
+ * test handleException generating log.
+ *
+ * @return void
+ */
+ public function testHandleFatalErrorLog() {
+ $this->skipIf(file_exists(APP . 'app_error.php'), 'App error exists cannot run.');
+
+ if (file_exists(LOGS . 'error.log')) {
+ unlink(LOGS . 'error.log');
+ }
+
+ ob_start();
+ ErrorHandler::handleFatalError(E_ERROR, 'Something wrong', __FILE__, __LINE__);
+ ob_clean();
+
+ $log = file(LOGS . 'error.log');
+ $this->assertContains(__FILE__, $log[0], 'missing filename');
+ $this->assertContains('[FatalErrorException] Something wrong', $log[1], 'message missing.');
+ }
+
}
@@ -0,0 +1,35 @@
+<?php
+/**
+ *
+ * PHP 5
+ *
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://cakephp.org CakePHP(tm) Project
+ * @package Cake.View.Errors
+ * @since CakePHP(tm) v 2.2.0
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+?>
+<h2><?php echo __d('cake_dev', 'Fatal Error'); ?></h2>
+<p class="error">
+ <strong><?php echo __d('cake_dev', 'Error'); ?>: </strong>
+ <?php echo h($error->getMessage()); ?>
+ <br>
+
+ <strong><?php echo __d('cake_dev', 'File'); ?>: </strong>
+ <?php echo h($error->getFile()); ?>
+ <br>
+
+ <strong><?php echo __d('cake_dev', 'Line'); ?>: </strong>
+ <?php echo h($error->getLine()); ?>
+</p>
+<p class="notice">
+ <strong><?php echo __d('cake_dev', 'Notice'); ?>: </strong>
+ <?php echo __d('cake_dev', 'If you want to customize this error message, create %s', APP_DIR . DS . 'View' . DS . 'Errors' . DS . 'fatal_error.ctp'); ?>
+</p>

0 comments on commit 072aee0

Please sign in to comment.