How can I get useful error messages in PHP?

Viewed 665520

Quite often I will try and run a PHP script and just get a blank screen back. No error message; just an empty screen. The cause might have been a simple syntax error (wrong bracket, missing semicolon), or a failed function call, or something else entirely.

It is very difficult to figure out what went wrong. I end up commenting out code, entering "echo" statements everywhere, etc. trying to narrow down the problem. But there surely must be a better way, right?

Is there a way to get PHP to produce a useful error message, like Java does?

41 Answers

For syntax errors, you need to enable error display in the php.ini. By default these are turned off because you don't want a "customer" seeing the error messages. Check this page in the PHP documentation for information on the 2 directives: error_reporting and display_errors. display_errors is probably the one you want to change. If you can't modify the php.ini, you can also add the following lines to an .htaccess file:

php_flag  display_errors        on
php_value error_reporting       2039

You may want to consider using the value of E_ALL (as mentioned by Gumbo) for your version of PHP for error_reporting to get all of the errors. more info

3 other items: (1) You can check the error log file as it will have all of the errors (unless logging has been disabled). (2) Adding the following 2 lines will help you debug errors that are not syntax errors:

error_reporting(-1);
ini_set('display_errors', 'On');

(3) Another option is to use an editor that checks for errors when you type, such as PhpEd. PhpEd also comes with a debugger which can provide more detailed information. (The PhpEd debugger is very similar to xdebug and integrates directly into the editor so you use 1 program to do everything.)

Cartman's link is also very good: http://www.ibm.com/developerworks/library/os-debug/

You can include the following lines in the file you want to debug:

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

This overrides the default settings in php.ini, which just make PHP report the errors to the log.

There is a really useful extension called "xdebug" that will make your reports much nicer as well.

error_reporting(E_ALL | E_STRICT);

And turn on display errors in php.ini

You can register your own error handler in PHP. Dumping all errors to a file might help you in these obscure cases, for example. Note that your function will get called, no matter what your current error_reporting is set to. Very basic example:

function dump_error_to_file($errno, $errstr) {
    file_put_contents('/tmp/php-errors', date('Y-m-d H:i:s - ') . $errstr, FILE_APPEND);
}
set_error_handler('dump_error_to_file');

open your php.ini, make sure it's set to:

display_errors = On

restart your server.

To turn on full error reporting, add this to your script:

error_reporting(E_ALL);

This causes even minimal warnings to show up. And, just in case:

ini_set('display_errors', '1');

Will force the display of errors. This should be turned off in production servers, but not when you're developing.

In addition to all the wonderful answers here, I'd like to throw in a special mention for the MySQLi and PDO libraries.

In order to...

  1. Always see database related errors, and
  2. Avoid checking the return types for methods to see if something went wrong

The best option is to configure the libraries to throw exceptions.

MySQLi

Add this near the top of your script

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

This is best placed before you use new mysqli() or mysqli_connect().

PDO

Set the PDO::ATTR_ERRMODE attribute to PDO::ERRMODE_EXCEPTION on your connection instance. You can either do this in the constructor

$pdo = new PDO('driver:host=localhost;...', 'username', 'password', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);

or after creation

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

You can enable full error reporting (including notices and strict messages). Some people find this too verbose, but it's worth a try. Set error_reporting to E_ALL | E_STRICT in your php.ini.

error_reporting = E_ALL | E_STRICT

E_STRICT will notify you about deprecated functions and give you recommendations about the best methods to do certain tasks.

If you don't want notices, but you find other message types helpful, try excluding notices:

error_reporting = (E_ALL | E_STRICT) & ~E_NOTICE

Also make sure that display_errors is enabled in php.ini. If your PHP version is older than 5.2.4, set it to On:

display_errors = "On"

If your version is 5.2.4 or newer, use:

display_errors = "stderr"

Aside from error_reporting and the display_errors ini setting, you can get SYNTAX errors from your web server's log files. When I'm developing PHP I load my development system's web server logs into my editor. Whenever I test a page and get a blank screen, the log file goes stale and my editor asks if I want to reload it. When I do, I jump to the bottom and there is the syntax error. For example:

[Sun Apr 19 19:09:11 2009] [error] [client 127.0.0.1] PHP Parse error:  syntax error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or T_NUM_STRING in D:\\webroot\\test\\test.php on line 9

This answer is brought to you by the department of redundancy department.

  1. ini_set() / php.ini / .htaccess / .user.ini

    The settings display_errors and error_reporting have been covered sufficiently now. But just to recap when to use which option:

    • ini_set() and error_reporting() apply for runtime errors only.
    • php.ini should primarily be edited for development setups. (Webserver and CLI version often have different php.ini's)
    • .htaccess flags only work for dated setups (Find a new hoster! Well managed servers are cheaper.)
    • .user.ini are partial php.ini's for modern setups (FCGI/FPM)

    And as crude alternative for runtime errors you can often use:

    set_error_handler("var_dump");   // ignores error_reporting and `@` suppression
    
  2. error_get_last()

    Can be used to retrieve the last runtime notice/warning/error, when error_display is disabled.

  3. $php_errormsg

    Is a superlocal variable, which also contains the last PHP runtime message.

  4. isset() begone!

    I know this will displease a lot of folks, but isset and empty should not be used by newcomers. You can add the notice suppression after you verified your code is working. But never before.

    A lot of the "something doesn't work" questions we get lately are the result of typos like:

    if(isset($_POST['sumbit']))
    #                  ↑↑
    

    You won't get any useful notices if your code is littered with isset/empty/array_keys_exists. It's sometimes more sensible to use @, so notices and warnings go to the logs at least.

  5. assert_options(ASSERT_ACTIVE|ASSERT_WARNING);

    To get warnings for assert() sections. (Pretty uncommon, but more proficient code might contain some.)

    PHP7 requires zend.assertions=1 in the php.ini as well.

  6. declare(strict_types=1);

    Bending PHP into a strictly typed language is not going to fix a whole lot of logic errors, but it's definitely an option for debugging purposes.

  7. PDO / MySQLi

    And @Phil already mentioned PDO/MySQLi error reporting options. Similar options exist for other database APIs of course.

  8. json_last_error() + json_last_error_msg

    For JSON parsing.

  9. preg_last_error()

    For regexen.

  10. CURLOPT_VERBOSE

    To debug curl requests, you need CURLOPT_VERBOSE at the very least.

  11. shell/exec()

    Likewise will shell command execution not yield errors on its own. You always need 2>&1 and peek at the $errno.

PHP Error Handling

Sometimes your application will not run as it supposed to do, resulting in an error. There are a number of reasons that may cause errors, for example:

The Web server might run out of disk space A user might have entered an invalid value in a form field The file or database record that you were trying to access may not exist The application might not have permission to write to a file on the disk A service that the application needs to access might be temporarily unavailable These types of errors are known as run-time errors, because they occur at the time the script runs. They are distinct from syntax errors that need to be fixed before the script will run.

A professional application must have the capabilities to handle such run-time error gracefully. Usually this means informing the user about the problem more clearly and precisely.

Understanding Error Levels

Usually, when there's a problem that prevents a script from running properly, the PHP engine triggers an error. Each error is represented by an integer value and an associated constant. The following table list some of the common error levels:

enter image description here

The PHP engine triggers an error whenever it encounters a problem with your script, but you can also trigger errors yourself to generate more user friendly error messages. This way you can make your application more sofisticated. The following section describes some of common methods used for handling errors in PHP:

Basic Error Handling Using the die() Function

<?php // Try to open a non-existent file
     $file = fopen("sample.txt", "r");
?>

If the file does not exist you might get an error like this: Warning: fopen(sample.txt) [function.fopen]: failed to open stream: No such file or directory in C:\wamp\www\project\test.php on line 2

If we follow some simple steps we can prevent the users from getting such error message:

<?php
if(file_exists("sample.txt")){
    $file = fopen("sample.txt", "r");
} else{
    die("Error: The file you are trying to access doesn't exist.");
}
?>

Now if you run the above script you will get the error message like this: Error: The file you are trying to access doesn't exist.

As you can see by implementing a simple check whether the file exist or not before trying to access it, we can generate an error message that is more meaningful to the user.

The die() function used above simply display the custom error message and terminate the current script if 'sample.txt' file is not found.

Creating a Custom Error Handler

You can create your own error handler function to deal with the run-time error generated by PHP engine. The custom error handler provides you greater flexibility and better control over the errors, it can inspect the error and decide what to do with the error, it might display a message to the user, log the error in a file or database or send by e-mail, attempt to fix the problem and carry on, exit the execution of the script or ignore the error altogether.

The custom error handler function must be able to handle at least two parameters (errno and errstr), however it can optionally accept an additional three parameters (errfile, errline, and errcontext), as described below:

enter image description here

Here's an example of a simple custom error handling function. This handler, customError() is triggered whenever an error occurred, no matter how trivial. It then outputs the details of the error to the browser and stops the execution of the script.

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
?>

You need to tell the PHP to use your custom error handler function — just call the built-in set_error_handler() function, passing in the name of the function.

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}

// Set error handler
set_error_handler("customError");

// Trigger error
echo($test);
?>

Error Logging

Log Error Messages in a Text File

You can also logs details of the error to the log file, like this:

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("calcDivision(): The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
function customError($errno, $errstr, $errfile, $errline, $errcontext){
    $message = date("Y-m-d H:i:s - ");
    $message .= "Error: [" . $errno ."], " . "$errstr in $errfile on line $errline, ";
    $message .= "Variables:" . print_r($errcontext, true) . "\r\n";

    error_log($message, 3, "logs/app_errors.log");
    die("There was a problem, please try again.");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "This will never be printed.";
?>

Trigger an Error

Although the PHP engine triggers an error whenever it encounters a problem with your script, however you can also trigger errors yourself. This can help to make your application more robust, because it can flag potential problems before they turn into serious errors.

To trigger an error from within your script, call the trigger_error() function, passing in the error message that you want to generate:

trigger_error("There was a problem.");

Consider the following function that calculates division of the two numbers.

<?php
function calcDivision($dividend, $divisor){
    return($dividend / $divisor);
}

// Calling the function
echo calcDivision(10, 0);
?>

If a value of zero (0) is passed as the $divisor parameter, the error generated by the PHP engine will look something like this: Warning: Division by zero in C:\wamp\www\project\test.php on line 3

This message doesn't look very informative. Consider the following example that uses the trigger_error() function to generate the error.

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}

// Calling the function
echo calcDivision(10, 0);
?>

Now the script generates this error message: Warning: The divisor cannot be zero in C:\wamp\www\project\error.php on line 4

As you can see the error message generated by the second example explains the problem more clearly as compared to the previous one.

I fixed my entire 500 problem like this:

A. Check php.ini parameters

  1. php.ini >> error_reporting = E_ALL | E_STRICT
  2. php.ini >> display_errors = On
  3. php.ini >> display_startup_errors = Off

B. Update IIS manager parameters

  1. IIS Manager >> Error Pages >> 500 >> Edit feature settings >> detailed errors

in this step, you get 500 errors like this and with no html loading.

enter image description here

  1. IIS Manager >> FastCGI Settings >> php-cgi.exe >> standard error mode >> IgnoreAndReurn200

in this step, you can see html page including php errors like this. enter image description here

AND DONE :)

Related