3

In a page, test.php, I simply activate error reporting, I deactivate the logging, and I call a function test(), which does not exist. As expected, if I run the code I receive the error message:

(!) Fatal error: Uncaught Error: Call to undefined function test() in [path-to]/test.php on line 7
(!) Error: Call to undefined function test() in [path-to]/test.php on line 7
Call Stack
# Time    Memory  Function    Location
1 0.1336  355848  {main}( )   .../test.php:0

Now, in another page, index.php, I have only a button - named testButton. If I press it, an ajax request to the page test.php is performed. In index.php I expected to see that:

  • The error thrown in test.php is handled by the error callback of the ajax request;
  • The error is displayed on screen.

Unfortunately none of this happens. When I press the button:

  • The success callback of the ajax request is called;
  • No error is displayed on screen.

Could you help me find the problem, or identify the bug?

Thank you.


Used system:

  • PHP: 7.1.1
  • Apache Version: 2.2.31
  • Apache API Version: 20051115
  • jQuery: 3.3.1

test.php:

<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 0);

$data = test();

index.php:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
        <meta charset="UTF-8" />
        <!-- The above 3 meta tags must come first in the head -->

        <title>Test: Displaying Errors</title>

        <script src="https://code.jquery.com/jquery-3.3.1.min.js" type="text/javascript"></script>

        <script type="text/javascript">
            $(document).ready(function () {
                $('#testButton').click(function (event) {
                    $.ajax({
                        method: 'post',
                        dataType: 'html',
                        url: 'test.php',
                        data: {},
                        success: function (response, textStatus, jqXHR) {
                            $('#result').html('Successful test... Unfortunately :-)');
                        },
                        error: function (jqXHR, textStatus, errorThrown) {
                            /*
                             * When an HTTP error occurs, errorThrown receives the textual portion of
                             * the HTTP status, such as "Not Found" or "Internal Server Error". This
                             * portion of the HTTP status is also called "reason phrase".
                             */
                            var message = errorThrown;

                            /*
                             * If a response text exists, then set it as message,
                             * instead of the textual portion of the HTTP status.
                             */
                            if (jqXHR.responseText !== null && jqXHR.responseText !== 'undefined' && jqXHR.responseText !== '') {
                                message = jqXHR.responseText;
                            }

                            $('#result').html(message);
                        }
                    });
                });
            });
        </script>
    </head>
    <body>

        <h3>
            Test: Displaying Errors
        </h3>

        <div id="result">
            Hier comes the test result. Since an error is thrown, I expect it to appear hear.
        </div>

        <br/>

        <form method="post" action="">
            <button type="button" id="testButton" name="testButton">
                Start the test
            </button>
        </form>

    </body>
</html>
PajuranCodes
  • 303
  • 3
  • 12
  • 43
  • 1
    Is the `response` in your `success` callback the PHP error text? – Phil Jul 18 '18 at 23:22
  • Thanks, @Phil. Yes, it is! Do you know maybe a way to throw that error inside the `error` callback of the ajax request instead? – PajuranCodes Jul 18 '18 at 23:25
  • Not an exact duplicate (and it's old) but worth linking ~ https://stackoverflow.com/questions/1555862/how-can-i-get-php-to-return-500-upon-encountering-a-fatal-exception – Phil Jul 18 '18 at 23:41
  • On another note, Apache 2.2 is very old. You may want to consider upgrading that if possible. – Mike Jul 19 '18 at 01:02

1 Answers1

2

The success and error functions in your jQuery AJAX call simply checks for the HTTP status code for the request. When PHP produces errors it does not change the status code, and so jQuery triggers the success function. If you want to use the jQuery error, you will have to change the status code. You can do this by catching the Error (PHP >= 7):

try {
    $data = test();
}
catch (\Error $e) {
    http_response_code(500);
    echo $e->getMessage();
}

Or you could keep the status code as 200 (default) and send your response in JSON including the success and error properties you like, as well as any other things you may want to return with the request.

header('Content-type: application/json');
$response['success'] = true;
$response['error'] = null;
try {
    $data = test();
}
catch (\Error $e) {
    $response['success'] = false;
    $response['error'] = $e->getMessage();
}
echo json_encode($response);

And make sure to remove the dataType property from the ajax request to let jQuery automatically determine the type header.

If your program is throwing errors unexpectedly, this probably means you're doing something wrong. If you expect it to throw errors, you need to catch them. This either means wrapping things in try/catch blocks or a combination of set_exception_handler(), set_error_handler() and register_shutdown_function() to accomplish this globally.

Mike
  • 23,542
  • 14
  • 76
  • 87
  • Better to have PHP set the appropriate `Content-type` header for the response and let jQuery determine the data-type dynamically from that – Phil Jul 18 '18 at 23:37
  • Thank you, Mike. Could you explain _"... does not change the status code"_? I mean: if a status code was set at time To (let's say 200) and I run the ajax at time T1 and the php engine throws the error, then the status remains 200? I'll test your answer now. – PajuranCodes Jul 18 '18 at 23:46
  • I tested your solution and it works. But I forgot to mention, that I need a global solution. E.g. one that maintains the ini_set settings unchanged and does change the header to 500, for example, but don't have to be used by me each time I think an error should be thrown in a certain situation. Do you think it's possible? – PajuranCodes Jul 19 '18 at 00:04
  • Thanks again, Mike, I appreciate. Could you please pass your last comment in your answer? – PajuranCodes Jul 19 '18 at 01:00
  • @dakis Sure. Edited. – Mike Jul 19 '18 at 01:08