PHP exceptions thrown in error handler not caught by exception handler - php

I chose this title because I have the exact same problem as stated in here:
PHP exceptions thrown in error handler are not caught by exception handler
The author accepted the answer which said he obviously was doing something wrong.
My error and exception handler were working fine that last two years, but now im facing the exactly same problem.
I did a code update and also a server update (Plesk 11.5 running, the PHP version should be the same and is 5.3.2). I checked my code for the error, but a test made it clear that this cant be the problem:
I wrote the following testfile:
function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
throw new Exception("this was an error");
}
function exceptionHandler($e) {
echo 'exceptionHandler';
}
set_error_handler('errorHandler');
set_exception_handler('exceptionHandler');
// test one:
throw new Exception(); // outputs "exceptionHandler"
// test two - uncomment the first test of course!
$test->blabla();
The second test should also output "exceptionHandler", but it doesn't!
The output is "Fatal error: Call to a member function blabla() on a non-object in ......./exeptiontest.php on line 0"
This problem drives me crazy at the moment. Any suggestions here? Any PHP settings that cause this?

Update (After reading your comment).
After an error handler has been executed program flow would went back to the expression after that where the error occurred. But it is unreliable to pass back program flow to a fatally failed script. That's why error handlers won't get called on fatal errors. The documentation says:
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.
As a workaround (depending on your needs), you may define a shutdown function using register_shutdown_function().
Original Answer (It turned out that this was not the problem here)
You need to read the documentation of set_exception_handler() carefully, especially the code example:
function exception_handler($exception) {
echo "Uncaught exception: " , $exception->getMessage(), "\n";
}
set_exception_handler('exception_handler');
throw new Exception('Uncaught Exception');
echo "Not Executed\n";
Meaning in your case that $test->blabla() will never gets executed.
You might expect that the exception handler function works like a catch block, but that isn't the case. True is, that if an exception occurs and no catch block is defined, the program flow will take over to the exception handler which may gracefully shutdown the script - but not more. If you want to handle exceptions the right way, use try / catch
Just to make it more clear: exception handlers behave different than error handlers. After returning from an exception handler the program will terminate while the program flow wents back to the expression after the error when returning from an error handler.

Related

How do I capture require errors + error_handlers

I am trying to use the set_error_handler function to capture require errors.
while my custom error_handler is being used, the context seems completely off, although the trace is correct.
<?php
function error_handler($errno, $errstr, $errfile, $errline){
throw new Exception($errstr);
}
set_error_handler('error_handler');
try{
trigger_error("somethign",E_USER_NOTICE);
}catch(Exception $e){
echo "I got caught";
}
try{
require "something/that/does/not/exists.php";
}catch(Exception $e){
echo "I got caught";
}
As can be seen, when I trigger the first error, it triggers the error_handler which in turn is throwing an exception. Which is caught in the first try-catch.
The second time, where I try to include an un-existing file, again the error_handler is used, but the exception is not caught.
What is going on here?
I am using php 5.5.*
Tested in CLI mode.
Just read the documentation:
require is identical to include except upon failure it will also
produce a fatal E_COMPILE_ERROR level error. In other words, it will
halt the script
(http://php.net/manual/en/function.require.php)
That means, the script execution is aborted when this error is encountered. Your custom error handler will be used but throw will be ignore because that assumes further execution which is not allowed at this point.
It's important to remember that there's two general types of errors with PHP
Processing errors are caught when your program runs
Compile errors occur when you have bad syntax or when you try to do something impossible
In your case, require is a compile error. It will not execute your user defined function because it will never get that far. The compiler can't include the bad file and will fail out.

PhP Exception message shown despite been caught by the exception handler

I have set an exception handler in my PhP program using set_exception_handler() and it actually works fine. In the sense, it does catch exceptions not otherwise handled by me, and as provided in the handler, logs the exception details. So, why am I complaining? Problem is that in addition to logging the correct details with file name and line number in the exception handler, it also displays the following message in the browser:
Fatal error: Exception thrown without a stack frame in Unknown on line 0
My belief is that perhaps this specific exception message is coming from stdout stream while the exceptions been caught by the handler are from the stderr stream. The other possibility is that the above message is emitted by the error handler module and not the exception handler module of PhP. In any event, I would like all exception messages to go to one handler. I also have a error handler set as follows:
set_error_handler('SS_error_handler', E_ALL);
How are such situations handled? Is the Fatal error message coming from PhP's error message reporting module? If so, is there an overlap between the exception handler and the error handler in the sense that they both get triggered on certain errors/exceptions? If relevant, I would like to add that this specific exception is thrown be a MySQL PDO statement.
Any explanation would be appreciated.
Please reference the docs: http://php.net/manual/en/function.set-error-handler.php
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.
Hence, you cannot use set_error_handler to catch exceptions, you should use proper try { } catch { } blocks.
add # character at the beginning of line that causes errors, that will silence it.
also you can ini_set('display_errors', 0), that will silence everyone :)
but usual people just try{} catch ( e) { trigger_error(e, E_USER_ERROR);}

Catching fatal PHP errors and throwing an exception

The entry point (front controller) for our software is wrapped in a try catch block which catches exceptions and then includes a PHP file to show a friendly error page, as well as emailing us about the exception. This work perfectly, however it misses PHP fatal errors which just show a HTTP 500 response. I'm trying to catch those errors in the same way as exceptions.
At the moment, we have this in the application's entry point:
try {
// Register a shutdown handler for fatal errors
register_shutdown_function(function() {
$error = error_get_last();
// Did this request throw an error that wasn't handled?
if ($error !== null) {
throw new Exception('PHP fatal error!');
}
});
// ...normal front controller stuff
} catch (Exception $e) {
// show fancy error screen with debug information
include 'themes/error/500.php';
}
Here, I'm throwing an exception when PHP throws a fatal error in the hopes that it gets handled by the normal exception handling procedure. However, the exception never gets caught:
Fatal error: Uncaught exception 'Exception' with message 'PHP fatal error!'
How can I achieve what I want to do here?
You should not use register_shutdown_function() for that - it makes no sense since you're already at stage when script is exiting. PHP allow you to handle errors via set_error_handler() function.
But note, you can not handle fatal errors with that (such as calling undefined functions) - and, of cause, parse error as well:
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.

Is it possible to catch all PHP errors occured in a file

I want to catch all PHP errors (E_ERROR, E_WARNING, E_NOTICE,..) in a page and log it to MongoDB in order to read and comment better on it.
I found a way to catch last occured error with 'error_get_last' and send it to anywhere i want with 'register_shutdown_function' Handle fatal errors in PHP using register_shutdown_function()
But what if my file have more than one errors, like warnings and notices, how can i get all errors in a file? Is this possible? What i need is something like 'error_get_all'.
Here you can find my code, this code has one fatal error, two warning and one notice:
function shutdown() {
$error = error_get_last();
if ($error['type'] === E_ERROR || $error['type'] === E_WARNING || $error['type'] === E_NOTICE) {
var_dump($error);
}
}
register_shutdown_function('shutdown');
spl_autoload_register('foo');
$x = 5;
$y = 0;
echo 'x/y: ' . $x / $y . '<br/>';
foreach ($noarray as $noelement) {
echo 'no element: ' . $noelement . '<br/>';
}
The answer is to combine solutions:
Use 'set_error_handler' to catch all possible errors it can (see http://php.net/manual/en/function.set-error-handler.php), as well as using the described register_shutdown_function to log the errors which are missed by this.
By doing this, non-fatal errors during runtime will be caught by the custom handler, continuing on until end of script or a fatal error occurs which would be caught by either the custom or the shutdown function depending on type.
Use set_error_handler.
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.
For catching fatal errors and parsing errors you're using right funciton
register_shutdown_function
But when application reach fatal error, or parsing or any error E_ERROR the process of execution ending at that point of the script, so in this case you can catch only one such a error in script.
I will suggest you to use register_shutdown_function just in case to catch fatal errors, and other errors catch with function set_error_handler to catch other errors as warning etc, for exceptions set_exception_handler by that you can easy track all errors in system and validate them also.
If you will write object for error handling then the logic for you can be:
$handler = new Handler();
$handler->handleExceptions(); //using set_exception_handler exceptions
$handler->handleError(E_ALL); //using set_error_handler all other errors
$handler->handleShutdown(); //using register_shutdown_function fatals, parsing
By that you will have options to turn off/on errors and store errors where you need them or send by email from one place, also simple way to get full error for debuging.
May be you want to use a framework like this:
http://code.google.com/p/lagger/
Fatal errors past the first one encountered are impossible to catch, as the PHP interpreter never reaches them (the script terminates after it executes your shutdown handler). Non-fatal errors can be caught (you will need a separate error_handler installed for them in addition to your shutdown handler), PHP won't terminate the script so if you don't terminate it in your error handler either, execution will continue after each non-fatal error and you will catch them all. If you want to still terminate after the entire file has been executed, you might want to keep a flag somewhere, clear it before you include the file and raise it in case of error; after the file has been included, you can test this flag and see if any error has been caught. Keep in mind that the included file will have fully executed at that point (if it did not have any fatal errors) or you might never reach that point (if it has fatal errors).
If you're running untrusted user code, you might be interested in Runkit Sandboxes. You can also take a look at runkit_lint_file() for some pre-include validation.

Ensure PHP shutdown function is called

I'm trying to catch as many errors as possible in PHP and properly handle them in a non-default way. My question is best illustrated in this example:
<?php
function errorHandler($errno, $errstr, $errfile, $errline){
echo "Error handler here <br>\n";
//throw new Exception($errstr);
}
function shutdownFunction() {
echo "Hi I'm in here <br>\n";
}
set_error_handler("errorHandler");
register_shutdown_function("shutdownFunction");
try {
$undefined->ok(); // causes some error
} catch(Exception $e) {
echo "Caught the exception <br>\n";
}
The result of running this code as a PHP program will indicate that errorHandler() is run, a PHP error is printed (if "display_errors" is set to "On"), and then shutdownFunction() is run.
The problem I'm having arises if I uncomment out that exception throw; I want to throw exceptions on PHP errors as often as possible. If I uncomment the throw statement out, then the error handler is called, which throws an exception thus causing a further error which results in shutdownFunction() not to be called.
It is my understanding that I can't make this error into a catchable exception; however, I would at least like to ensure that the shutdown function is called without restricting my ability to catch at least some php errors as exceptions (meaning I don't want to remove that throw statement in errorHandler()).
Is there some check in the errorHandler that I can do to check whether or not throwing it will cause shutdownFunction() to be bypassed?
Throw an exception from the error handler, then use set_exception_handler to handle uncaught exceptions.
So the way I'm solving this is to check if the $errstr parameter starts with "Undefined variable" - and if it does, then I'm not throwing the exception. I suppose if there are any other errors that have a similar issue, i'll do the same thing with those. I can't find a comprehensive list of php errors and what their affects are though, so it'll have to be ad hoc

Categories