Handle fatal errors in PHP using register_shutdown_function()
This works for me:
function shutdown() {
$error = error_get_last();
if ($error['type'] === E_ERROR) {
// fatal error has occured
}
}
register_shutdown_function('shutdown');
spl_autoload_register('foo');
// throws a LogicException which is not caught, so triggers a E_ERROR
However, you probably know it already, but just to make sure: you can't recover from a E_ERROR in any way.
As for the backtrace, you can't... :( In most cases of a fatal error, especially Undefined function errors, you don't really need it. Pinpointing the file/line where it occured is enough. The backtrace is irrelevant in that case.
Can register_shutdown_function() and set_error_handler() catch the same error?
The shutdown function will be executed when the script execution is finished whether there is an error, exception or not. It has nothing to do with errors or exceptions, errors or exceptions don't trigger it , and it does not catch them, it will be called anyway at the end of the script, so it is useful if you want to do some work even if an exception or fatal error happened because error handler function does not get executed if Fatal error or exception happened.
The error handler function will be executed when error is triggered. This is quoted from the manual
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.
<?php
function shutdownFunction(){
echo "shutdownFunction is called \n";
}
function errorHandlerFunction(){
echo "errorHandlerFunction is called \n";
}
register_shutdown_function('shutdownFunction');
set_error_handler('errorHandlerFunction');
//echo "foo\n"; // scenario 1 no errors
//echo $undefinedVar; //scenario 2 error is triggered
//undefinedFunction(); //scenario 3 Fatal error is triggered
//throw new \Exception(); //scenario 4 exception is thrown
scenario 1 (no errors) outputs
foo
shutdownFunction is called
scenario 2(error is triggered) outputs
errorHandlerFunction is called
shutdownFunction is called
scenario 3 (Fatal error is triggered) outputs
Fatal error: Call to undefined function undefinedFunction() in /tmp/execpad-b2a446c7f6a6/source-b2a446c7f6a6 on line 15
shutdownFunction is called
scenario 4 (exception is thrown) outputs
Fatal error: Uncaught exception 'Exception' in /tmp/execpad-0b3a18f0ea06/source-0b3a18f0ea06:16
Stack trace:
#0 {main}
thrown in /tmp/execpad-0b3a18f0ea06/source-0b3a18f0ea06 on line 16
shutdownFunction is called
see for yourself https://eval.in/1073642
How to Handle Parse error using register_shutdown_function() in php?
Parse errors can only be caught if they occur in scripts included or required. (also see https://stackoverflow.com/a/1900272/2123530)
So, sorry, this won't work the way you did it but can work this way :
<?php
register_shutdown_function('ShutDown');
include 'include.php';
function catchError($errno, $errstr, $errfile = '', $errline = ''){
echo "Eroor Type : " .$errno. "<br>";
echo "Eroor Message : " . $errstr . "<br>";
echo "Line Number : " . $errline;
exit();
}
function ShutDown(){
$lasterror = error_get_last();
if(in_array($lasterror['type'],Array( E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_CORE_WARNING, E_COMPILE_WARNING, E_PARSE))){
catchError($lasterror['type'],$lasterror['message'],$lasterror['file'],$lasterror['line']);
}
}
?>
Content of include.php
<?php
echo "Hi" // generate error == Parse error: syntax error, unexpected 'echo' (T_ECHO), expecting ',' or ';' in file_naem on line 5;
echo "Hello";
?>
Fatal error catched by register_shutdown_function and update json_encode
Why move one array to another array and then echo the second array.
Why not just do this
function shutdown(){
$error = error_get_last();
echo json_encode($error);
}
Or even this
function shutdown(){
echo json_encode(error_get_last());
}
Apart form the use of an unnecessary array, this will give you all the information available from get_last_error()
Of course it could be that the error_get_last()
information is just not available at this late stage in the shutdown process. If this is the case then you can pass extra parameters to the shutdown function and this may be what you need to do.
register_shutdown_function('shutdown', get_last_error());
and
function shutdown($last_error){
echo json_encode($last_error);
}
EDITED:
First I have added error_reporting(~E_ERROR); // don't report fatal errors
The first one worked for me I mean
error_reporting(~E_ERROR); // don't report fatal
register_shutdown_function('shutdown');
function shutdown(){
$error = error_get_last();
if ($error['type'] === 1){
echo json_encode($error);
}
For my needs I wrote:
function shutdown(){
$error = error_get_last();
if ($error['type'] === 1){ // 1 means fatal error
$res['message'] = $error['message'];
$res['success'] = true;
header('Content-Type: application/json');
echo json_encode($res);
}
}
How do I handle parse and fatal errors?
If it can't parse your script, it won't be able to parse your custom error handler.
You should have display_errors
off in your php.ini
and also set error_reporting
to none when your site is in production.
Also, I believe set_error_handler()
can handle fatal errors.
PHP Pass Variables to register_shutdown_function - Fatal Error Handler
See the docs :
Working directory of the script can change inside the shutdown
function under some web servers, e.g. Apache.
So be sure to use an absolute path when doing this, i.e
file_put_contents('<absolute-path-to>/resultLogs/log.txt', $write, FILE_APPEND);
As you wrote "All my logs are saved in a different folder than the .php file", and I guess that your problem is, that you are having the $file
constant relative to that .php
file but the directory changes upon error..
Why does fopen fail within a register shutdown function?
Are you using a relative path to your custom error log? If so, this note on the register_shutdown_function
page might be relevant:
Working directory of the script can change inside the shutdown function under some web servers, e.g. Apache.
In fact, the second comment says:
If you want to do something with files in function, that registered in register_shutdown_function(), use ABSOLUTE paths to files instead of relative. Because when script processing is complete current working directory chages to ServerRoot (see httpd.conf)
Other things I'll mention:
Your variable $error
, and the logic if ($error) { ...
is misleading. See, when you register a function using register_shutdown_function
, you are telling PHP to invoke that function every single time your script finishes executing - regardless of whether or not there was an error. This means that fatalHandler
is invoked even when your script finishes with a non-fatal error, or even no error at all!
Since you have an alternative method for dealing with non-fatal errors (using set_error_handler
), you should specifically check for fatal errors in fatalHandler
:
function fatalHandler() {
if( $error !== NULL && $error['type'] == E_ERROR) {
errorHandler($error["type"], $error["message"], $error["file"], $error["line"]);
header("HTTP/1.1 500 Internal Server Error");
exit();
}
}
See the list of PHP error levels here.
You may not be aware of this, but PHP has a built-in error-logging function. By default, it writes to the file specified for error_log
in your php.ini
.
If you are interested in more advanced logging, and generally taking your PHP-fu to the next level, I suggest looking into the Monolog package. It is more or less considered the universal standard for logging in professional PHP communities.
Related Topics
How to Delete Object from Array Inside Foreach Loop
How to Re-Save the Entity as Another Row in Doctrine 2
Configure Multiple Databases in Zf2
Is My Understanding of PHP Sessions Correct
Magic _Get Getter for Static Properties in PHP
Pass Extra Parameters to Usort Callback
Getting a Checkbox Array Value from Post
Allow Only [A-Z][A-Z][0-9] in String Using PHP
How to "Validate" Human Names in Cakephp
PHP Carbon, Get All Dates Between Date Range
Laravel Catch Tokenmismatchexception
Encrypt Files Using Pgp in PHP
Download Files from Server PHP
Convert Month from Name to Number
Php: Static and Non Static Functions and Objects