How to catch PHP fatal errors

I can use set_error_handler() to catch most PHP errors, but it does not work with fatal (E_ERROR) errors, such as calling functions that do not exist.Is there another way to catch these errors?

I'm trying to call mail() for all errors and I'm running PHP 5.2.3.

#1st floor

PHP has fatal errors that can be captured.They are defined as E_RECOVERABLE_ERROR.The PHP manual describes E_RECOVERABLE_ERROR as:

Capturable fatal error.It indicates that a potentially dangerous error has occurred, but it does not leave the engine unstable.If the error is not caught by a user-defined handle (see also set_error_handler() ), the application will abort because it is E_ERROR.

You can use the set_error_handler() And check E_RECOVERABLE_ERROR to "catch" these "fatal" errors.I find it useful to throw an exception when capturing this error, then try / catch can be used.

This question and answer provide a useful example: How do I catch "fatal trappable errors" in PHP type hints?

However, you can handle E_ERROR errors, but you cannot recover from them because the engine is in an unstable state.

#2nd floor

I have developed a method to capture all error types in PHP (almost all)!I'm not sure about E_CORE_ERROR (I don't think it applies to this error only)!However, for other fatal errors (E_ERROR, E_PARSE, E_COMPILE...), using only one error handler function will work!There is my solution:

Put the following code in your main file (index.php):

<?php

define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR | 
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

define('ENV', 'dev');

//Custom error handling vars
define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);
define('LOG_ERRORS', TRUE);

register_shutdown_function('shut');

set_error_handler('handler');

//Function to catch no user error handler function errors...
function shut(){

    $error = error_get_last();

    if($error && ($error['type'] & E_FATAL)){
        handler($error['type'], $error['message'], $error['file'], $error['line']);
    }

}

function handler( $errno, $errstr, $errfile, $errline ) {

    switch ($errno){

        case E_ERROR: // 1 //
            $typestr = 'E_ERROR'; break;
        case E_WARNING: // 2 //
            $typestr = 'E_WARNING'; break;
        case E_PARSE: // 4 //
            $typestr = 'E_PARSE'; break;
        case E_NOTICE: // 8 //
            $typestr = 'E_NOTICE'; break;
        case E_CORE_ERROR: // 16 //
            $typestr = 'E_CORE_ERROR'; break;
        case E_CORE_WARNING: // 32 //
            $typestr = 'E_CORE_WARNING'; break;
        case E_COMPILE_ERROR: // 64 //
            $typestr = 'E_COMPILE_ERROR'; break;
        case E_CORE_WARNING: // 128 //
            $typestr = 'E_COMPILE_WARNING'; break;
        case E_USER_ERROR: // 256 //
            $typestr = 'E_USER_ERROR'; break;
        case E_USER_WARNING: // 512 //
            $typestr = 'E_USER_WARNING'; break;
        case E_USER_NOTICE: // 1024 //
            $typestr = 'E_USER_NOTICE'; break;
        case E_STRICT: // 2048 //
            $typestr = 'E_STRICT'; break;
        case E_RECOVERABLE_ERROR: // 4096 //
            $typestr = 'E_RECOVERABLE_ERROR'; break;
        case E_DEPRECATED: // 8192 //
            $typestr = 'E_DEPRECATED'; break;
        case E_USER_DEPRECATED: // 16384 //
            $typestr = 'E_USER_DEPRECATED'; break;

    }

    $message = '<b>'.$typestr.': </b>'.$errstr.' in <b>'.$errfile.'</b> on line <b>'.$errline.'</b><br/>';

    if(($errno & E_FATAL) && ENV === 'production'){

        header('Location: 500.html');
        header('Status: 500 Internal Server Error');

    }

    if(!($errno & ERROR_REPORTING))
        return;

    if(DISPLAY_ERRORS)
        printf('%s', $message);

    //Logging error on php file error log...
    if(LOG_ERRORS)
        error_log(strip_tags($message), 0);

}

ob_start();

@include 'content.php';

ob_end_flush();

?>

Hope to help a lot of people!I have been searching for this solution for too long to find it!And then I developed one!

#3rd floor

If you are using php> = 5.1.0, you only need to do the following for the ErrorException class:

<?php
//define an error handler
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
//set ur error handle
set_error_handler("exception_error_handler");

/* Trigger exception */
try
{
  //try to do something like finding the end of the internet
}
catch(ErrorException $e)
{
  //anything you want to do with $e
}

?>

#4th floor

In some cases, even fatal errors should be caught (you may need some cleanup to exit gracefully, not just to die.).I've implemented a pre_system hook on my codeigniter application to get fatal errors via e-mail, which helps me find unreported errors (or errors reported after fixing because I already know them:).Sendemail checks to see if the error has been reported so that spam with known errors is not sent to you multiple times.

class PHPFatalError {

    public function setHandler() {
        register_shutdown_function('handleShutdown');
    }

}

function handleShutdown() {
    if (($error = error_get_last())) {
        ob_start();
        echo "<pre>";
        var_dump($error);
        echo "</pre>";
        $message = ob_get_clean();
        sendEmail($message);
        ob_start();
        echo '{"status":"error","message":"Internal application error!"}';
        ob_flush();
        exit();
    }
}

#5th floor

A good technique for getting the current error_handler method=)

<?php
register_shutdown_function('__fatalHandler');
function __fatalHandler()
{
    $error      = error_get_last();

    //check if it's a core/fatal error, otherwise it's a normal shutdown
    if($error !== NULL && $error['type'] === E_ERROR) {
        //Bit hackish, but the set_exception_handler will return the old handler
        function fakeHandler() { }
        $handler = set_exception_handler('fakeHandler');
        restore_exception_handler();
        if($handler !== null) { 
            call_user_func($handler, new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
        }
        exit;
    }
}
?>

I wouldn't notice if you called

<?php
ini_set('display_errors', false);
?>

PHP stops displaying errors or the error text will be sent to the client before the error handler

Tags: PHP

Posted on Sat, 11 Jan 2020 22:51:57 -0500 by charlieholder