Skip to content

Commit

Permalink
Merge branch '2.2-fatal-error' into 2.2
Browse files Browse the repository at this point in the history
  • Loading branch information
jrbasso committed Apr 14, 2012
2 parents f677bfe + 9beaa96 commit 072aee0
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 5 deletions.
2 changes: 1 addition & 1 deletion app/Config/core.php
Expand Up @@ -41,7 +41,7 @@
* *
* Options: * 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. * including anonymous functions.
* - `level` - int - The level of errors you are interested in capturing. * - `level` - int - The level of errors you are interested in capturing.
* - `trace` - boolean - Include stack traces for errors in log files. * - `trace` - boolean - Include stack traces for errors in log files.
Expand Down
2 changes: 1 addition & 1 deletion lib/Cake/Console/Templates/skel/Config/core.php
Expand Up @@ -41,7 +41,7 @@
* *
* Options: * 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. * including anonymous functions.
* - `level` - int - The level of errors you are interested in capturing. * - `level` - int - The level of errors you are interested in capturing.
* - `trace` - boolean - Include stack traces for errors in log files. * - `trace` - boolean - Include stack traces for errors in log files.
Expand Down
28 changes: 27 additions & 1 deletion lib/Cake/Core/App.php
Expand Up @@ -881,7 +881,8 @@ protected static function _packageFormat() {
/** /**
* Object destructor. * 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 * @return void
*/ */
Expand All @@ -892,6 +893,31 @@ public static function shutdown() {
if (self::$_objectCacheChange) { if (self::$_objectCacheChange) {
Cache::write('object_map', self::$_objects, '_cake_core_'); 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());
} }


} }
30 changes: 30 additions & 0 deletions lib/Cake/Error/ErrorHandler.php
Expand Up @@ -158,6 +158,9 @@ public static function handleError($code, $description, $file = null, $line = nu
} }
$errorConfig = Configure::read('Error'); $errorConfig = Configure::read('Error');
list($error, $log) = self::mapErrorCode($code); list($error, $log) = self::mapErrorCode($code);
if ($log === LOG_ERROR) {
return self::handleFatalError($code, $description, $file, $line);
}


$debug = Configure::read('debug'); $debug = Configure::read('debug');
if ($debug) { if ($debug) {
Expand All @@ -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. * Map an error code into an Error word, and log location.
* *
Expand Down
27 changes: 27 additions & 0 deletions lib/Cake/Error/exceptions.php
Expand Up @@ -517,3 +517,30 @@ class XmlException extends CakeException {
*/ */
class ConsoleException 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;
}
}

}
54 changes: 52 additions & 2 deletions lib/Cake/Test/Case/Error/ErrorHandlerTest.php
Expand Up @@ -89,7 +89,6 @@ public static function errorProvider() {
return array( return array(
array(E_USER_NOTICE, 'Notice'), array(E_USER_NOTICE, 'Notice'),
array(E_USER_WARNING, 'Warning'), array(E_USER_WARNING, 'Warning'),
array(E_USER_ERROR, 'Fatal Error'),
); );
} }


Expand Down Expand Up @@ -194,7 +193,7 @@ public function testHandleException() {
} }


/** /**
* test handleException generating a page. * test handleException generating log.
* *
* @return void * @return void
*/ */
Expand Down Expand Up @@ -238,4 +237,55 @@ public function testLoadPluginHanlder() {
CakePlugin::unload(); 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.');
}

} }
35 changes: 35 additions & 0 deletions lib/Cake/View/Errors/fatal_error.ctp
@@ -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.