15

I'm confused about how to use set_error_handler() properly, and the php documentation isn't really helping to clarify.

I want it to email me as many errors as possible, with the exception of notices.

I have the following code

<?php

if (TRAP_ERRORS) { 
// True on production, false in development, where errors are just echoed out.
    set_exception_handler('globalExceptionHandler');
    set_error_handler('globalErrorHandler', E_USER_WARNING);
}

function globalExceptionHandler($e) {
    //log and email stuff here
}

function globalErrorHandler($errno, $errstr, $errfile, $errline) {
    switch ($errno) {
        case E_NOTICE:
        case E_USER_NOTICE:
            $errors = "Notice";
            break;
        case E_WARNING:
        case E_USER_WARNING:
            $errors = "Warning";
            break;
        case E_ERROR:
        case E_USER_ERROR:
            $errors = "Fatal Error";
            break;
        default:
            $errors = "Unknown Error";
            break;
    }

    error_log(sprintf("PHP %s:  %s in %s on line %d", $errors, $errstr, $errfile, $errline));
    $msg = "ERROR: [$errno] $errstr\r\n".
        "$errors on line $errline in file $errfile\r\n";

    sendErrorEmail($msg);
    showErrorPage();

    exit(1);
}

function sendErrorEmail($p_errorMsg) {
    // Parse and sent out the error email...
}

function showErrorPage() {
    // Redirect to an error page.
}

?>

Above is my current setting set_error_handler('globalErrorHandler', E_USER_WARNING);, which seems to be wrong in that it doesn't cover trigger_error() errors. I believe that is because the argument is supposed to be a bitmask instead of just a single error level, but I am not sure how to set it to work for the maximum number of errors/information (except notices). I've seen examples that use E_ALL, but that actually directly causes any code that includes the global error handler stuff to error for me.

So anyway, how do I use set_error_handler so that the maximum amount of information can be handled by my custom error handler (so that I can get automatic emails directly when such problems occur, instead of having to review the logs later).

Kzqai
  • 22,588
  • 25
  • 105
  • 137

4 Answers4

16
set_error_handler('some_handler',E_ALL & ~E_NOTICE & ~E_USER_NOTICE);

Or, if you really want all,

set_error_handler('some_handler',-1 & ~E_NOTICE & ~E_USER_NOTICE);

Alternatively, you can just set it to use all errors, and just ignore it if they're not in error_reporting (which you set to the same value as the above line, also, the @ operator works then):

....
if(!($errno & error_reporting())) return true;
switch($errno){
....
Wrikken
  • 69,272
  • 8
  • 97
  • 136
  • Wait, so setting it to be the return value of error_reporting() would work too, right? I think that that's pretty much what I want, since I'm already reporting everything except notices. – Kzqai Jun 02 '11 at 19:18
  • Yup, then you can just omit the second parameter, and just have the check for error_reporting in there. – Wrikken Jun 02 '11 at 19:21
  • 2
    Oh, I meant as the second parameter, e.g. `set_error_handler('some_handler', error_reporting());` – Kzqai Jun 02 '11 at 19:29
3

Leave out the second parameter or pass in the default E_ALL | E_STRICT (all errors AND strictness errors, don't be confused by the bitwise OR here)

Additionally you can 'catch' Fatal errors by doing a register_shutdown_function() and error_get_last() trick demonstrated here: Handle fatal errors in PHP using register_shutdown_function()

Community
  • 1
  • 1
Halcyon
  • 57,230
  • 10
  • 89
  • 128
2

The $error_type is an integer which you set using masking. To use an error handler for everything except E_NOTICE you'd use one of the following:

set_error_handler('globalErrorHandler', E_ALL ^ E_NOTICE);
set_error_handler('globalErrorHandler', E_ALL & ~E_NOTICE);

If you want to also exclude E_USER_NOTICE then:

set_error_handler('globalErrorHandler', E_ALL ^ (E_NOTICE | E_USER_NOTICE));
set_error_handler('globalErrorHandler', E_ALL & ~E_NOTICE & ~E_USER_NOTICE);

Note the use of the bitwise operators "&", "~" and "|", see PHP Bitwise operator manual.

Be careful, some errors will not be picked up if they occur before your set_error_handler call, or are compiler errors (unlikely, but who knows). See PHP set_error_handler documentation.

MGwynne
  • 3,512
  • 1
  • 23
  • 35
0

How about using scheduled tasks to let the server send you the error log files automatically; instead of handling it this way within your application..

Faisal Nasim
  • 253
  • 2
  • 8
  • Already done on a periodic basis via logcheck and logwatch on a cron... ...which means that there is a delay between when an error occurs for a user, and when I would be able to find out about it via logs, which is why I need a more immediate response mechanism for more important issues. – Kzqai Jun 02 '11 at 17:39
  • This is pretty much why I've used custom error handlers -- to manage custom logging (with full backtrace, for example) and notifications. – Wiseguy Jun 02 '11 at 17:41
  • Lets blend it the other way; make a file comparison small script which keeps the copy of the last log and checks it with the new one if there is a change it triggers u an email; otherwise it dosen't. Frequency could be set a little low; like every 15 minutes or so.. A 1kb script wont cause much trouble. Otherwise; for error reporting like above you may use exception handling to catter for all types of errors and do whatever u want to do in exception catch or make an exception class which is parent of all your classes to do that job for you. – Faisal Nasim Jun 02 '11 at 17:43