10

I must be missing something in my understanding of handling PHP errors, specifically suppressing their output. When a fatal error occurs, I expect my shutdown handler function to process it gracefully and terminate script execution. This works as expected. However, I can't seem to prevent PHP from outputting the information about the fatal error.

My php.ini file contains the following directives:

error_reporting = E_ALL | E_STRICT
display_errors = Off

I set error_reporting to report everything and I use a custom error handler to throw exceptions. My expectation is that display_errors = Off will prevent ANY error messages from being displayed.

Anyway, when a fatal error occurs the custom error handler is bypassed (because script execution stops immediately) and the shutdown handler executes.

Now, on to my simplified code:

error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'Off');

function shutdown_handler()
{
  $err = error_get_last();
  $fatal = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR);
  if ($err && in_array($err['type'], $fatal)) {
    echo "\n\ntest fatal error output\n\n";
  }
  exit();
}

register_shutdown_function('shutdown_handler');

To test it I generate an "Allowed memory size exhausted" fatal error like so:

// max out available memory
$data = '';
while(true) {
  $data .= str_repeat('#', PHP_INT_MAX);
}

Because i have display_errors = Off I expect this to only produce the following output (as per the shutdown handler):

test fatal error output

But instead I continue to receive:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 2147483648 bytes) in /home/daniel/mydev/php/test0.php on line 24
PHP Stack trace:
PHP   1. {main}() /home/daniel/mydev/php/test0.php:0
PHP   2. str_repeat() /home/daniel/mydev/php/test0.php:24

test fatal error output

What am I missing that will prevent this error trace from outputting?


CONCLUSION

It appears, as @Cthos sagely noted, that "E_ERROR and display_errors don't play nicely together."

This is also the case for E_PARSE (and I assume E_CORE_ERROR/E_COMPILE_ERROR, but I didn't break my PHP installation to test it). I suppose it makes sense that PHP would force the error traceback into STDOUT in these cases because if it didn't you might never know if/why things were going wrong.

So a solution in this case would be:

  1. As @Cthos suggested, silence E_ERROR notifications in php.ini: error_reporting = (E_ALL & ~ E_ERROR) or at runtime using error_reporting(E_ALL & ~ E_ERROR);
  2. Update the shutdown handler to check if the last error was of type E_ERROR and perform the appropriate actions if so.

As for the other fatals like E_PARSE, E_CORE_ERROR, etc. you just have to make sure your code is correct and that your PHP works. If you try to silence E_PARSE errors and handle them in your shutdown function it won't work because parse errors prevent PHP from ever getting that far.

So, an updated/working shutdown handler looks like this:

error_reporting(E_ALL & ~ E_ERROR);

function shutdown_handler()
{
  $err = error_get_last();
  if ($err && $err['type'] == E_ERROR) {
    $msg = 'PHP Fatal Error: '.$err['message'].' in '.$err['file'].
      ' on line '.$err['line'];
    echo $msg, PHP_EOL;
  }
  exit();
}
12
  • Mayhap you should have a custom error handler instead? php.net/manual/en/function.set-error-handler.php Commented Dec 15, 2011 at 20:21
  • @Cthos -- as the question states, I already use a custom error handler. When a fatal error occurs script execution stops immediately and a custom error handler doesn't get called. A custom shutdown handler, however, can still run. Commented Dec 15, 2011 at 20:23
  • Hrm, I failed at reading comprehension then, however I had thought Fatals would still go to said handler. Experimentation time. Commented Dec 15, 2011 at 20:26
  • @Cthos No worries on that front, I'm the worst at that. I'm definitely good for a downvote from time to time because of my A.D.D. :) ... and yeah, I've been experimenting with this on the command line for half an hour trying to make it work. Commented Dec 15, 2011 at 20:28
  • This works for me, so perhaps it is your error reporting level? gist.github.com/1482749 Commented Dec 15, 2011 at 20:32

2 Answers 2

3

The unwanted error information is due to the error logging configuration (log_errors and error_log), and is completely independent of the display_errors configuration. The default php.ini configuration logs error details to stderr when running scripts from the command-line. Under Apache, they show up in /etc/httpd/logs/error_log.

Check out the php_error_cb function in main.c of the PHP source. In particular, line 1056 makes it clear that any messages of the format "PHP %s: %s in %s on line %d" are due to the error logging configuration (error information due to display_errors will not have the "PHP: " prefix).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a ton. This has been an annoyance for me for a while.
3

Couple of possible solutions, answering because the comments section was getting angry at me.

Edit #3 with solution:

Apparently E_ERROR and display_errors don't play nicely together

You could set error_reporting to E_ALL & ~E_ERROR, and just let your shutdown handler handle the fatal (since it is the last thing that should be called anyhow).

Additionally, E_ALL does not encompass E_DEPRECATED prior to PHP 5.4.0, so if you want to catch that too - use ~0 & ~E_ERROR


display_errors may be bugged

Here's a gist on how you can get it to spit out errors even though you told it not to: https://gist.github.com/1483028

If you set display_errors to 0 via ini_set() it will still display Fatal Errors

Although display_errors may be set at runtime (with ini_set()), it won't have any affect if the script has fatal errors. This is because the desired runtime action does not get executed.

Additionally you can send it to stderr as well, so that's awesome.

http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-errors

Edit 2: Make sure you've changed the proper php.ini

Just thought of this, and commented as such, but there is more than one php.ini file. If you're doing this on the command line, you'll need to edit the cli one (/etc/php5/cli/php.ini on Ubuntu), and not the web one (/etc/php5/apache2/php.ini)

I'd guess you just need to set php.ini to have display_errors 0.

5 Comments

Yeah -- that's what I was thinking too, but I still get the error output (weird) and that's why I ended up posting the question ... could it be a bug? I wonder ...
Possibly. Which php.ini are you editing? If you're on ubuntu, there are 2: /etc/php5/cli/php.ini and /etc/php5/apache2/php.ini. If you edited one but not the other.. (But you probably know this, just running through ideas).
Sadly, I'm definitely using the correct (and the only one in my fedora distro) php.ini ...
@rdlowrey - What version of php?
Well, I can dupe when changing the error_reporting....I suspect those are the same setting...(well not the same setting, but I think you know what I mean)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.