Search code examples
phpiisinternal-server-error

Get form data on 500 error


I'm attempting to gather information when our sites encounter an internal server error. We have many applications that were never set up with proper error logging and when an issue occurs our clients don't give us the best information to work with. What I would like to do is that when a 500 happens, I would like to collect data about where the issue happened such as:

  • The page the user was on
  • Any data associated with the page ($_GET, $_POST, etc)

I've set up custom error pages on our server (IIS 7) with the following config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpErrors errorMode="Custom">
            <remove statusCode="500" />
            <error statusCode="500" path="/error.php?code=500" responseMode="ExecuteURL" />
        </httpErrors>
    </system.webServer>
</configuration>

And on that page I'm just var_dump-ing $_POST and $_GET to see if anything in those gets through to the error page, but it doesn't. My goal on a 500 error would be:

  • Gather data about the page/user at time of error
  • Send email to support team about issue containing the gathered data

Is there any way to collect that data and have the custom error page see it?

error.php:

switch($ErrorCode){
    case '500':
         var_dump($_REQUEST, $_POST, $_GET);
         echo "internal server error";
         break;
}

In all cases $_POST is empty even though I submitted a form to get this error and $_GET contains this (which makes sense):

array(2) {
  ["code"]=>
  string(3) "500"
  ["500;http://icom-sbs/test_php"]=>
  string(0) ""
}

4/19 Update

I played with some ideas, and the main one being storing useful data in a session variable. I attempted to store some form data in a session variable on the test page that gives the error, but it never gets into the session. It seems like the server detects that an error will occur on the page so it never even executes any code on the page and immediately executes the error page.


Solution

  • If your server started to interpret php file and after this 500 error occurred this means some fatal error happened in your code. It might be anything, from simple typo to execution time limit reached.

    The best and only way to catch fatal errors in PHP is with register_shutdown_function. You should define it on top of your working file:

    function handle_fatal() {
        $error = error_get_last(); // PHP 5.2+
        if($error !== NULL){
            $error_landing_page = '[FATAL] '.$error['message'].' in '.$error['file'].':'.$error['line'] . '<br/>GET:<br/>' . print_r($_GET, true) . '<br/>POST:<br/>' . print_r($_POST, true);
            // mail here if you need that and include $_GET, $_POST variables - this will be the last state before error occurred
            exit($error_landing_page);
        }
    }
    
    register_shutdown_function('handle_fatal');
    

    Simple test case:

    // put handling function at the very beginning
    function handle_fatal() {/*...*/}
    register_shutdown_function('handle_fatal');
    
    // now do some logic
    if($_GET['page'] == 'dupa'){
        $_POST['subpage'] = 1; // more and more logic
        $obj = new Dupa(); // class not found exception
    }
    

    This is what I get with my handle_fatal from example:

    [FATAL] Class 'Dupa' not found in /var/www/index.php:22
    GET:
    Array ( [page] => dupa )
    POST:
    Array ( [subpage] => 1 ) 
    

    After all you should know that catching such errors is not always best idea and you should be careful about it.