Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get all PHP errors/warnings/... that occurred during the current request

Setting the directive display_errors to true (while having error_reporting set to E_ALL) prints all errors that occured during the current request bofore returing the PHP output.

Since I'm sending headers in my PHP code, I get several more errors (sending header after content has been sent is not possible).

Now I'd like to add the error messages to the end of my page. There I'd like to show all errors that occurred (until then). Unfortunately error_get_last only returns the last error that occurred.

I first thought that set_error_handler might solve the problem, but I'm afraid that my error-logging does not work anymore:

It is important to remember that the standard PHP error handler is completely bypassed for the error types specified by error_types unless the callback function returns FALSE.

Besides that:

The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.

But maybe they are also not available in error_get_last()

So is there a way to print all errors after the output of the generated content?

like image 377
Edward Avatar asked Apr 05 '16 11:04

Edward


3 Answers

Referring to your first concern

The error handling will still work as long as the:

callback function returns FALSE

function myErrorHandler($error_level, $error_message, $error_file, $error_line, $error_context) {
    // Do your stuff here, e.g. saving messages to an array

    // Tell PHP to also run its error handler
    return false;
}

One solution to store all error-numbers (in an outside array $error_list) could be:

$error_list = array();

$myErrorHandler = function ($error_level, $error_message, $error_file, $error_line, $error_context) use (&$error_list) {
    $error_list[] = $error_level;
    // Tell PHP to also run its error handler
    return false;
};
// Set your own error handler
$old_error_handler = set_error_handler($myErrorHandler);

Another approach is to use Exceptions. There is a nice example in the comments for the function set_error_handler()

Also see:

  • Are global variables in PHP considered bad practice? If so, why?
  • PHP: Callback function using variables calculated outside of it

Referring to your second concern:

As Egg already mentioned: using register_shutdown_function() is a way to go, and the code in the answer https://stackoverflow.com/a/7313887/771077 shows you how.

But keep in mind, that

  • Registering the shutdown- and error-handling functions should be the first thing in code (I fool once had an error in a config file, which was not handled correct, since I registered the error handler afterwards).
  • Parse errors might not be handled correctly (See comment in https://stackoverflow.com/a/7313887/771077)
like image 56
R_User Avatar answered Nov 11 '22 13:11

R_User


There is a discussion about this here and here (amongst others), with the second answer on the latter list using a mix of set_error_handler() with register_shutdown_function() being a good solution.

like image 4
Egg Avatar answered Nov 11 '22 12:11

Egg


Fuller example that catches all the errors (exceptions and errors), pumps to a log file and remembers in a static class; at the end you query the static class to get the error.

I use similar to this for all projects to get full control over all errors.

function customErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
    ErrorHandler($errno, $errmsg, $filename, $linenum, $vars, true);
}

function nullErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
    ErrorHandler($errno, $errmsg, $filename, $linenum, $vars, false);
}

function customExceptionHandler($exception) {
    if (is_a($exception, 'exceptionError')) {
        echo $exception->output();
    } else {
        ErrorHandler(E_ERROR, $exception->getMessage() . '(' . $exception->getCode() . ')', $exception->getFile(), $exception->getLine(), null, true);
    }
}

function nullExceptionHandler($exception) {
    if (is_subclass_of($exception, 'exceptionError')) {
        $exception->output();
    } else {
        ErrorHandler(E_WARNING, $exception->getMessage() . '(' . $exception->getCode() . ')', $exception->getFile(), $exception->getLine(), null, false);
    }
}


function ErrorHandler($errno, $errmsg, $filename, $linenum, $vars, $fatal) {
    $errortype = array (
            E_ERROR              => 'Error',
            E_WARNING            => 'Warning',
            E_PARSE              => 'Parsing Error',
            E_NOTICE             => 'Notice',
            E_CORE_ERROR         => 'Core Error',
            E_CORE_WARNING       => 'Core Warning',
            E_COMPILE_ERROR      => 'Compile Error',
            E_COMPILE_WARNING    => 'Compile Warning',
            E_DEPRECATED         => 'Deprecated',
            E_USER_ERROR         => 'User Error',
            E_USER_WARNING       => 'User Warning',
            E_USER_NOTICE        => 'User Notice',
            E_USER_DEPRECATED    => 'User Deprecated',
            E_STRICT             => 'Runtime Notice',
            E_RECOVERABLE_ERROR  => 'Catchable Fatal Error'
            );


    // Pushed into error log
    if (error_reporting() > 0) {
        $message = ': ' . $errmsg . ' in ' . $filename . ' on line ' . $linenum;
        error_log('PHP ' . $errortype[$errno] . $message);

        errorLogger::log($message);

        if ($fatal) {
            echo $errortype[$errno] . ': ' . $message;
            exit();
        }
    }
}


class errorLogger {

    private static $aErrors = array();

    // ******************* Timing functions *********************************

    public static function log($message) {
        self::$aErrors[] = $message;
    }

    public static function getErrors() {
        return self::$aErrors;
    }

}

Usage Example

// Custom error handler. Can cope with the various call mechanisms
$old_error_handler = set_error_handler('nullErrorHandler');
$old_exception_handler = set_exception_handler('nullExceptionHandler');

// Do your stuff
// *
// *
// *
// *
// *

$old_error_handler = set_error_handler('customErrorHandler');   // Set to 'nullErrorHandler' to allow it to continue
$old_exception_handler = set_exception_handler('customExceptionHandler');   // Set to 'nullExceptionHandler' to allow it to continue

// At end
$errors = errorLogger::getErrors();
foreach($errors as $errorMessage) {
    echo $errorMessage;
}
like image 1
Robbie Avatar answered Nov 11 '22 12:11

Robbie