Report PHP errors in JSON format complying with the regular content-type

2.4k views Asked by At

I use AngularJs for a single page application and communicate with serverside PHP via JSON. The php header sets JSON, but the error reporting from php:

php_flag display_errors 1
php_flag display_startup_errors 1
php_value error_reporting 32767

is html and not matching the content-type header of the regular answer header('Content-Type: application/json;charset=utf-8');
Therefore angularjs constantly throws on php errors. Should I use multicontent types or what to do?

enter image description here

2

There are 2 answers

0
sepehr On BEST ANSWER

If you must return PHP error/exceptions to the client-side, which is not recommended (but I know, it's easier for development), you gonna need a custom error/uncaught-exception handler for PHP. This way you're able to customize how the errors/exceptions are shown.

Here's a sample code that outputs errors and uncaught exceptions as JSON objects.

// Set error handler
set_error_handler('api_error_handler');

function api_error_handler($errno, $errstr) {
    return api_error($errstr, $errno, 500);    
}

// Set uncaught exceptions handler    
set_exception_handler('api_exception_handler');

function api_exception_handler($exception) {
    return api_error($exception->getMessage(), $exception->getCode(), 500);
}

// Error/Exception helper
function api_error($error, $errno, $code) {
    // In production, you might want to suppress all these verbose errors
    // and throw a generic `500 Internal Error` error for all kinds of 
    // errors and exceptions.
    if ($environment == 'production') {
        $errno = 500;
        $error = 'Internal Server Error!';
    }

    http_response_code($code);
    header('Content-Type: application/json');

    return json_encode([
        'success' => false,
        'errno'   => $errno,
        'error'   => $error,
    ]);
}

But that's not all; Since user-defined error handlers are not able to handle fatal errors, fatal error messages will still be displayed. You need to disable displaying errors with a call to ini_set():

ini_set('display_errors', 0);

So how to handle fatal errors? Fatal errors can be handled on shutdown with register_shutdown_function(). In the shutdown handler, we need to get the last error information with a call to error_get_last(). So:

// Set shutdown handler
register_shutdown_function('api_fatal_error_handler');

function api_fatal_error_handler() {
    $error = error_get_last();

    if ($error && error_reporting() && $error['type'] === E_ERROR) {
        return api_error($error['message'], E_CORE_ERROR, 500);
    }
}

Then on the javascript side of things, you have to add an error callback and show the error information to the user.

After all, why not using a mature error/exception handler package instead of implementing all of these? Meet Whoops.

1
Sylter On

Why are you relying on PHP Error for your application? If possible, provide the part of the code that raises the error.

You should never use PHP Error to stop your application, instead do a clean exit if you need to return a JSON result. You can use the try...catch pattern or check the statement that raises the error before actually call it (e.g. check if it is possible to go on with the execution).

Have a look here:

Always remember to turn off the error in your final application: they could leak a lot of information to an attacker (and, moreover, they simply look awful).