Yii中的致命错误处理

4

有没有一种方法可以通过Yii框架来发送/记录PHP致命错误的电子邮件?

例如,可以配置Yii发送“未定义变量”错误的电子邮件,但是致命错误只能由单独的、不与框架集成的代码监视,这并不理想。

1个回答

8
在php中,可以使用 register_shutdown_function() 函数拦截致命错误。
首先,在index.php中添加“早期”致命解析错误处理程序。此代码的目的是捕获在控制器启动之前可能发生的错误。由于我们正在捕获可能在应用程序初始化期间发生的错误,因此最好使用简单的php而不依赖于任何外部库:
// Early fatal errors handler, it will be replaced by a full featured one in Controller class
// (given it does not have any parse or fatal errors of its own)
function earlyFatalErrorHandler($unregister = false)
{
    // Functionality for "unregistering" shutdown function
    static $unregistered;
    if ($unregister) $unregistered = true;
    if ($unregistered) return;

    // 1. error_get_last() returns NULL if error handled via set_error_handler
    // 2. error_get_last() returns error even if error_reporting level less then error
    $error = error_get_last();

    // Fatal errors
    $errorsToHandle = E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING;

    if ((!defined('APP_PRODUCTION_MODE') || APP_PRODUCTION_MODE) && !is_null($error) && ($error['type'] & $errorsToHandle))
    {
        $message = 'FATAL ERROR: ' . $error['message'];
        if (!empty($error['file'])) $message .= ' (' . $error['file'] . ' :' . $error['line']. ')';

        mail('errors@YOURDOMAIN.COM', $message, print_r($error, 1));

        // Tell customer that you are aware of the issue and will take care of things
        // echo "Apocalypse now!!!"; 
    }
}

register_shutdown_function('earlyFatalErrorHandler');

在这个阶段,我们仍然没有使用Yii错误处理程序或日志记录。为了开始,我们需要注册另一个关闭函数,它是我们基础控制器的一部分,并且可以使用Yii框架提供的标准错误处理和错误日志记录(感谢vitalets在http://habrahabr.ru/post/136138/中提出的想法和大部分代码)。
请注意,只要它们不是实际控制器文件中的解析错误,而是在模型、助手、视图等外部文件中的解析错误,此函数将通知有关解析错误。如果解析错误在控制器中,则早期处理程序将处理它。
此外,此函数允许呈现更漂亮的错误页面,而不是转储致命错误文本或显示空白屏幕(如果关闭display_errors)。
/**
 * Controller is the customized base controller class.
 * All controller classes for this application should extend from this base class.
 */
class Controller extends CController
{
    // ...

    public function init()
    {
        register_shutdown_function(array($this, 'onShutdownHandler'));
        earlyFatalErrorHandler(true); // Unregister early hanlder
    }

    public function onShutdownHandler()
    {
        // 1. error_get_last() returns NULL if error handled via set_error_handler
        // 2. error_get_last() returns error even if error_reporting level less then error
        $error = error_get_last();

        // Fatal errors
        $errorsToHandle = E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING;

        if (!is_null($error) && ($error['type'] & $errorsToHandle))
        {
            // It's better to set errorAction = null to use system view "error.php" instead of
            // run another controller/action (less possibility of additional errors)
            Yii::app()->errorHandler->errorAction = null;

            $message = 'FATAL ERROR: ' . $error['message'];
            if (!empty($error['file'])) $message .= ' (' . $error['file'] . ' :' . $error['line']. ')';

            // Force log & flush as logs were already processed as the error is fatal
            Yii::log($message, CLogger::LEVEL_ERROR, 'php');
            Yii::getLogger()->flush(true);

            // Pass the error to Yii error handler (standard or a custom handler you may be using)
            Yii::app()->handleError($error['type'], 'Fatal error: ' . $error['message'], $error['file'], $error['line']);
        }
    }

    // ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接