Reputation: 1653
So in php.ini I've set:
error_reporting = E_ERROR
and I've written a handler:
register_shutdown_function( "fatal_handler" );
function fatal_handler() {
$errfile = "unknown file";
$errstr = "shutdown";
$errno = E_CORE_ERROR;
$errline = 0;
$error = error_get_last();
if( $error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
if($errno == E_ERROR){
$html = 'some html here';
print($html);
die();
}
}
}
What I did to test it is put a sleep longer than the max_execution_time in one script. For some reason this also kills other pages if I open up a new one in a different tab while loading the intentionally broken one. That's fine, whatever, but when the second page crashes, it's giving me a warning for error_get_last(). But I set error_reporting to 1! Why is it showing me a warning? It doesn't log it, but it causes me to fail to catch the error resulting a white screen, the exact thing this code is supposed to avoid!
Upvotes: 0
Views: 1810
Reputation: 1653
So basically I've taken Evan's answer and combine it with this question's answer, I have what appears to be a workable solution. myHandler captures errors/warnings and logs them if the error_reporting is set to log them. Then it returns true, which will prevent warnings from getting into error_get_last(). So now the error_get_last() call should only return [things that bypass error handlers], such as E_ERROR.
register_shutdown_function('fatal_handler');
set_error_handler('myHandler');
function myHandler($errno, $errstr, $errfile, $errline, $errctx){
if((error_reporting() & $errno) && ini_get('log_errors') == 'On'){
error_log(getFriendlyErrorType($errno) . ': ' . $errstr . ' in ' . $errfile . ' on line ' . $errline);
}
return true;
}
function fatal_handler() {
$error = error_get_last();
if($error !== NULL) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
if($errno == E_ERROR){
$html = '[some html]';
print($html);
die();
}
}
}
function getFriendlyErrorType($type)
{
switch($type)
{
case E_ERROR: // 1 //
return 'PHP Error';
case E_WARNING: // 2 //
return 'PHP Warning';
case E_PARSE: // 4 //
return 'PHP Parse';
case E_NOTICE: // 8 //
return 'PHP Notice';
case E_CORE_ERROR: // 16 //
return 'PHP Core Error';
case E_CORE_WARNING: // 32 //
return 'PHP Core Warning';
case E_CORE_ERROR: // 64 //
return 'PHP Compile Error';
case E_CORE_WARNING: // 128 //
return 'PHP Compile Warning';
case E_USER_ERROR: // 256 //
return 'PHP User Error';
case E_USER_WARNING: // 512 //
return 'PHP User Warning';
case E_USER_NOTICE: // 1024 //
return 'PHP User Notice';
case E_STRICT: // 2048 //
return 'PHP Strict Standards';
case E_RECOVERABLE_ERROR: // 4096 //
return 'PHP Recoverable Error';
case E_DEPRECATED: // 8192 //
return 'PHP Deprecated';
case E_USER_DEPRECATED: // 16384 //
return 'PHP User Deprecated';
}
return '';
}
Upvotes: 1
Reputation: 1966
Neither shutdown handlers nor error_get_last honor error_reporting.
The shutdown handler will always be called, regardless of any error or it's level (unless you throw an exception inside of a custom error handler)
error_get_last just gives you the last error, regardless of it's level.
Instead of using a shutdown handler, why not use an error handler? In that case, you could check the error level and return FALSE if you want to ignore errors of that level. (returning FALSE tells PHP to proceed as normal)
set_error_handler("fatal_handler");
function fatal_handler($errno, $errstr, $errfile, $errline, $errctx)
{
$reptLevel = error_reporting();
if ($reptLevel > 0) //if $reptLevel = 0 then it means the code that caused the error was preceded by a supressor (example: $x = @someFunction())
{
if ($errno == E_ERROR)
{
$html = 'some html here';
print($html);
die();
} else {
return false;
}
}
}
Upvotes: 3