View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
403 | Exception_DefaultHandler | All | public | 8 Feb 2012 15:48 | 2 Jan 2014 10:49 |
Reporter | mrosenquist | Assigned To | timj | ||
Priority | normal | Severity | feature | Reproducibility | have not tried |
Status | closed | Resolution | fixed | ||
Product Version | 0.8.1 | ||||
Target Version | 1.0.0 | Fixed in Version | 1.0.0 | ||
Summary | 403: Support handling of serious errors (e.g. call to non-existent functions) which skip the normal error handling | ||||
Description | Add a way to support handing for errors that php dosen't send to the set_error_handler callback | ||||
Tags | No tags attached. | ||||
Attached Files | bug-403.patch (2,860 bytes)
Index: DefaultHandler.php =================================================================== --- DefaultHandler.php (revision 54105) +++ DefaultHandler.php (working copy) @@ -202,6 +202,63 @@ } /** + * Try and handle PHP errors that are not passed to the error_handler. To use this, + * set error handling as follows: + * + * register_shutdown_function(array('Exception_DefaultHandler','handleShutdown')); + * + * This function will pass the last error that could not be handled as php does not sent + * it to the defined "set_error_handler()" + * + * Error output will not be show if display errors are on as there is no clean (ob buffering can be used) + * way of suppressing the normal php output and there is no point in duplicating the same message + */ + public static function handleShutdown() + { + if ($error = error_get_last()){ + switch($error['type']){ + case E_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + $debug_backtrace = debug_backtrace(); + + // Clear the first element, which refers to the call to this class + unset($debug_backtrace[0]); + + $backtrace = self::getBacktraceOutput($debug_backtrace); + $errtype = self::getPHPErrorDescription($error['type']); + + $error_hash[] = strtoupper(substr(md5($error['type'] . $error['message']), 0, 4)); + $error_hash[] = self::locationHash($error['file'], $error['line'], $debug_backtrace); + $error_hash = implode('/', $error_hash); + + $additional_environment = "PHP Error Type: $errtype\n"; + $additional_environment .= "PHP Error Details: " . $error['message'] . "\n"; + $additional_environment .= "Script location: " . $error['file'] . "\n"; + $additional_environment .= "Line Number: " . $error['line'] . "\n"; + self::writeLog($errtype, $error['message'], $error['file'], $error['line'], $backtrace); + self::sendEmail($backtrace, $additional_environment, $errtype, $error_hash); + + /* + * Only show errors if the errors have not already been show (diplay_errors is off) + * and errors should not be suppressed + */ + $disp_err = ini_get('display_errors'); + settype($disp_err, 'string'); // seems to always return string, but be sure + $disp_err = strtolower(trim($disp_err)); + if ($disp_err !== '1' && $disp_err !== 'on' && !self::suppressErrorDisplay()) { + // This are always terminiation errors + self::showOutput($errtype.' #'.$error_hash, $error['message'], $error['file'], $error['line'], $backtrace, true); + } + break; + default: + break; + } + } + } + + /** * Get a unique(ish) hash for a given exception, which merely serves to * tie together related errors when looking at a whole load of errors * The returned hash is in two parts: YYYY/ZZZZ where YYYY is only test6.php (323 bytes)
<?php // This test is to show a fatel error, display errors are turn off so some output will be shown ini_set('display_errors', false); require_once 'Exception/DefaultHandler.php'; register_shutdown_function(array('Exception_DefaultHandler','handleShutdown')); // Force an error to occur callFunctionThatDoesNotExist(); | ||||
|
Thanks! Looks like a nice feature. Just a few points: 1) Can you give examples of errors that it will catch that are not caught by the normal error handler? 2) Linked to (1), it would be good to have a test case. Although there are not currently proper unit tests, there are at least some manual tests for key functionality - see http://svn.timj.co.uk/Exception_DefaultHandler/library/Exception_DefaultHandler/trunk/tests/ - and I would like to improve the tests by adding at least some example for all features. 3) Instead of calling ini_get('display_errors') and checking the value, there is a cleaner way, call self::getDisplayErrors() (or is there a reason why this doesn't work in the shutdown function?) |
|
1) An example case: (sorry I did write a test case but is not in the patch) Is where there is a run time error that causes an E_ERROR best example is trying to use a function that does not exist <?php someFakeFunction(); //or class a { } $a = new a(); $a->someFakeMethod(); ?> While it should never happen, I would like to get emails about it if it ever did 2) Added the test case 3) I should have added a comment the self::getDisplayErrors() internally calls self::suppressErrorDisplay() and return false if true the logic needed is not display error and not suppress error display, hum ... thinking about it, it would be fine to use self::getDisplayErrors() as we check for self::suppressErrorDisplay() independetly, couldn't think through the login at the time ;-) |
|
There may need to be a test case for what happens with the following <?php @someFakeFunction(); |
|
Great thanks, another thing is that it uses error_get_last(), which makes it only work on >=PHP 5.2. Not sure yet if this is a big deal or not. |
|
If there is a comment in the code then is would only matter if someone set up the shutdown function in a pre PHP 5.2, php will not error unless that code is run, it will not check code that is not visited could have a warning in the code to check, but that could get circular errors, |
|
Hi Tim, can you try and review this patch and release a new version soon. This is the one type of errors we know absolutely nothing about at the moment and it is a real pain to try and work out application problems that were caused by fatal errors happening somewhere else in the system. With using error_get_last() and 5.2+ => maybe you make this one feature only available in 5.2+ (so the whole handler would not need 5.2 but using the shutdown function would)... Just a thought. Cheers, Michal |
|
If someone wants to update the patch/test case according to the following then this can get in the release :-) 1. clean up as per comment 403:436 point 3 2. make it safe for PHP <5.2 (e.g. use function_exists() to check before calling error_get_last()) with a unit test for this 3. rewrite the existing test to be a proper PHPT unit test, like the existing ones in SVN trunk (e.g. http://svn.timj.co.uk/Exception_DefaultHandler/library/Exception_DefaultHandler/trunk/tests/test1a-errors.phpt) |
|
Fixed in SVN r2260 |
Date Modified | Username | Field | Change |
---|---|---|---|
8 Feb 2012 15:48 | mrosenquist | New Issue | |
8 Feb 2012 15:49 | mrosenquist | File Added: bug-403.patch | |
8 Feb 2012 18:09 | timj | Note Added: 435 | |
8 Feb 2012 18:14 | mrosenquist | File Added: test6.php | |
8 Feb 2012 18:20 | mrosenquist | Note Added: 436 | |
8 Feb 2012 18:21 | mrosenquist | Note Added: 437 | |
8 Feb 2012 18:33 | timj | Note Added: 438 | |
8 Feb 2012 18:43 | mrosenquist | Note Added: 439 | |
3 May 2012 14:03 | mkierat | Note Added: 449 | |
8 May 2012 00:44 | timj | Note Added: 450 | |
17 Jul 2012 12:09 | timj | Status | new => confirmed |
17 Jul 2012 12:09 | timj | Summary | Add a way to support handing for errors that php dosen't send to the set_error_handler callback => Support handling of serious errors (e.g. call to non-existent functions) which skip the normal error handling |
18 Jul 2012 20:33 | timj | Note Added: 462 | |
18 Jul 2012 20:33 | timj | Assigned To | => timj |
18 Jul 2012 20:33 | timj | Status | confirmed => resolved |
18 Jul 2012 20:33 | timj | Resolution | open => fixed |
18 Jul 2012 20:33 | timj | Fixed in Version | => 0.8.3a |
18 Jul 2012 20:33 | timj | Target Version | => 0.8.3a |
2 Jan 2014 10:49 | timj | Fixed in Version | 0.8.3a => 1.0.0 |
2 Jan 2014 10:49 | timj | Target Version | 0.8.3a => 1.0.0 |
2 Jan 2014 10:49 | timj | Status | resolved => closed |