Commit 37d286ef by Alexander Makarov

Merge branch 'refs/heads/yii-style-fatal-errors'

parents 2c991833 2d5db951
...@@ -97,6 +97,12 @@ class Application extends Module ...@@ -97,6 +97,12 @@ class Application extends Module
private $_language; private $_language;
/** /**
* @var string Used to reserve memory for fatal error handler. This memory
* reserve can be removed if it's OK to write to PHP log only in this particular case.
*/
private $_memoryReserve;
/**
* Constructor. * Constructor.
* @param string $id the ID of this application. The ID should uniquely identify the application from others. * @param string $id the ID of this application. The ID should uniquely identify the application from others.
* @param string $basePath the base path of this application. This should point to * @param string $basePath the base path of this application. This should point to
...@@ -110,6 +116,7 @@ class Application extends Module ...@@ -110,6 +116,7 @@ class Application extends Module
$this->setBasePath($basePath); $this->setBasePath($basePath);
if (YII_ENABLE_ERROR_HANDLER) { if (YII_ENABLE_ERROR_HANDLER) {
ini_set('display_errors', 0);
set_exception_handler(array($this, 'handleException')); set_exception_handler(array($this, 'handleException'));
set_error_handler(array($this, 'handleError'), error_reporting()); set_error_handler(array($this, 'handleError'), error_reporting());
} }
...@@ -142,6 +149,50 @@ class Application extends Module ...@@ -142,6 +149,50 @@ class Application extends Module
$this->_ended = true; $this->_ended = true;
$this->afterRequest(); $this->afterRequest();
} }
if(YII_ENABLE_ERROR_HANDLER) {
$error = error_get_last();
if(isset($error['type']) && in_array($error['type'], ErrorException::getFatalCodes())) {
unset($this->_memoryReserve);
$exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']);
if(function_exists('xdebug_get_function_stack')) {
$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4, -1);
foreach($trace as &$frame) {
if(!isset($frame['function'])) {
$frame['function'] = 'unknown';
}
// XDebug < 2.1.1: http://bugs.xdebug.org/view.php?id=695
if(!isset($frame['type'])) {
$frame['type'] = '::';
}
// XDebug has a different key name
$frame['args'] = array();
if(isset($frame['params']) && !isset($frame['args'])) {
$frame['args'] = $frame['params'];
}
}
$ref = new \ReflectionProperty('Exception', 'trace');
$ref->setAccessible(true);
$ref->setValue($exception, $trace);
}
$this->logException($exception);
if (($handler = $this->getErrorHandler()) !== null) {
$handler->handle($exception);
} else {
$this->renderException($exception);
}
$status = 1;
}
}
if ($exit) { if ($exit) {
exit($status); exit($status);
} }
...@@ -155,6 +206,10 @@ class Application extends Module ...@@ -155,6 +206,10 @@ class Application extends Module
public function run() public function run()
{ {
$this->beforeRequest(); $this->beforeRequest();
// Allocating twice more than required to display memory exhausted error
// in case of trying to allocate last 1 byte while all memory is taken.
$this->_memoryReserve = str_repeat('x', 1024*256);
register_shutdown_function(array($this,'end'),0,false);
$status = $this->processRequest(); $status = $this->processRequest();
$this->afterRequest(); $this->afterRequest();
return $status; return $status;
...@@ -375,12 +430,24 @@ class Application extends Module ...@@ -375,12 +430,24 @@ class Application extends Module
* @param string $message the error message * @param string $message the error message
* @param string $file the filename that the error was raised in * @param string $file the filename that the error was raised in
* @param integer $line the line number the error was raised at * @param integer $line the line number the error was raised at
* @throws \ErrorException the error exception *
* @throws ErrorException
*/ */
public function handleError($code, $message, $file, $line) public function handleError($code, $message, $file, $line)
{ {
if (error_reporting() !== 0) { if (error_reporting() !== 0) {
throw new \ErrorException($message, 0, $code, $file, $line); $exception = new ErrorException($message, $code, $code, $file, $line);
// in case error appeared in __toString method we can't throw any exception
$trace = debug_backtrace(false);
array_shift($trace);
foreach($trace as $frame) {
if($frame['function'] == '__toString') {
$this->handleException($exception);
}
}
throw $exception;
} }
} }
......
<?php
/**
* ErrorException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* ErrorException represents a PHP error.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class ErrorException extends \ErrorException
{
public static function getFatalCodes()
{
return array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING);
}
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
$names = array(
E_ERROR => \Yii::t('yii|Fatal Error'),
E_PARSE => \Yii::t('yii|Parse Error'),
E_CORE_ERROR => \Yii::t('yii|Core Error'),
E_COMPILE_ERROR => \Yii::t('yii|Compile Error'),
E_USER_ERROR => \Yii::t('yii|User Error'),
E_WARNING => \Yii::t('yii|Warning'),
E_CORE_WARNING => \Yii::t('yii|Core Warning'),
E_COMPILE_WARNING => \Yii::t('yii|Compile Warning'),
E_USER_WARNING => \Yii::t('yii|User Warning'),
E_STRICT => \Yii::t('yii|Strict'),
E_NOTICE => \Yii::t('yii|Notice'),
E_RECOVERABLE_ERROR => \Yii::t('yii|Recoverable Error'),
E_DEPRECATED => \Yii::t('yii|Deprecated'),
);
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : \Yii::t('yii|Error');
}
}
...@@ -24,5 +24,4 @@ class Exception extends \Exception ...@@ -24,5 +24,4 @@ class Exception extends \Exception
{ {
return \Yii::t('yii|Exception'); return \Yii::t('yii|Exception');
} }
} }
\ No newline at end of file
...@@ -4,12 +4,13 @@ ...@@ -4,12 +4,13 @@
* @var \yii\base\ErrorHandler $owner * @var \yii\base\ErrorHandler $owner
*/ */
$owner = $this->owner; $owner = $this->owner;
$title = $owner->htmlEncode($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException ? $exception->getName() : get_class($exception));
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title><?php echo get_class($exception)?></title> <title><?php echo $title?></title>
<style> <style>
body { body {
...@@ -50,8 +51,8 @@ $owner = $this->owner; ...@@ -50,8 +51,8 @@ $owner = $this->owner;
</head> </head>
<body> <body>
<h1><?php echo $owner->htmlEncode($exception instanceof \yii\base\Exception ? $exception->getName() : get_class($exception)); ?></h1> <h1><?php echo $title?></h1>
<h2><?php echo nl2br($owner->htmlEncode($exception->getMessage()))?> </h2> <h2><?php echo nl2br($owner->htmlEncode($exception->getMessage()))?></h2>
<p> <p>
The above error occurred while the Web server was processing your request. The above error occurred while the Web server was processing your request.
</p> </p>
......
...@@ -4,12 +4,13 @@ ...@@ -4,12 +4,13 @@
* @var \yii\base\ErrorHandler $owner * @var \yii\base\ErrorHandler $owner
*/ */
$owner = $this->owner; $owner = $this->owner;
$title = $owner->htmlEncode($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException ? $exception->getName().' ('.get_class($exception).')' : get_class($exception));
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title><?php echo get_class($exception)?></title> <title><?php echo $title?></title>
<style> <style>
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent;margin:0;padding:0;} html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent;margin:0;padding:0;}
body{line-height:1;} body{line-height:1;}
...@@ -160,7 +161,7 @@ $owner = $this->owner; ...@@ -160,7 +161,7 @@ $owner = $this->owner;
<body> <body>
<div class="container"> <div class="container">
<h1><?php echo get_class($exception)?></h1> <h1><?php echo $title?></h1>
<p class="message"> <p class="message">
<?php echo nl2br($owner->htmlEncode($exception->getMessage()))?> <?php echo nl2br($owner->htmlEncode($exception->getMessage()))?>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment