Skip to content
Happy Programming Guide
Start learning
PHP

PHP Errors Not Showing in the Browser: display_errors and error_reporting

A blank white page and no error anywhere is PHP hiding the problem on purpose. Here is how to see errors in development, find the log in production, and configure it properly.

A laptop with a cup of coffee beside it

PHP hides errors by default on most server installs, because showing them to visitors leaks information. The result for a developer is the white screen: something failed, and nothing says what. Two settings control it, display_errors and error_reporting, and there is always a log somewhere even when the screen is blank. This article covers turning errors on where you should, finding the log where you should not, and the handful of cases where errors are hidden even with everything on.

Quick fix during development#

At the very top of the script, before anything else:

PHP
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

Reload. Notices, warnings and most fatal errors now print with a file and line number. This is the fastest way to find out what is wrong, and it has one limit covered below: it cannot show errors that happen before that line runs.

The two settings#

error_reporting decides which errors count. E_ALL is everything. Older tutorials suggest E_ALL & ~E_NOTICE to hide notices; do not, because notices are often the first sign of a real bug.

display_errors decides whether counted errors are printed in the output. On, they appear on the page. Off, they go only to the log.

A third, log_errors, decides whether they are written to the log at all, and error_log says where. In production: display off, log on.

Where to set them permanently#

php.ini#

The proper place. Find the file the web server is using — not necessarily the one the command line uses:

PHP
<?php phpinfo();     // look for "Loaded Configuration File"
Terminal
php --ini            # the CLI's file, which is often a different one

Edit the loaded file:

Output
display_errors = On          ; development only
display_startup_errors = On
error_reporting = E_ALL
log_errors = On
error_log = /var/log/php_errors.log

Restart Apache or PHP-FPM afterwards; php.ini is read at start-up.

.htaccess (Apache with mod_php)#

Output
php_flag display_errors on
php_value error_reporting -1

Works only when PHP runs as an Apache module. Under PHP-FPM, these lines cause a 500 error — which is itself a common reason for a page that shows nothing. Remove them and use php.ini or a .user.ini file instead.

.user.ini (PHP-FPM and shared hosting)#

Output
display_errors = On
error_reporting = E_ALL

Placed in the site’s root, picked up within a few minutes without a restart. This is usually the only option on shared hosting.

Errors that happen before your code runs#

A parse error — a missing semicolon, an unclosed bracket — stops PHP before it executes anything, including your ini_set line. The screen stays blank even with the quick fix in place. Two ways round it:

Terminal
php -l broken.php          # lint: reports syntax errors without running the file

Or put the settings in php.ini or .user.ini, which apply before parsing. The same applies to fatal errors inside a file that is included before the settings line; move the settings to the very first file that runs.

Finding the log#

When display is off, the error is still recorded. Where depends on the setup:

Setup Log location
XAMPP on Windows C:\xampp\php\logs\php_error_log and C:\xampp\apache\logs\error.log
XAMPP on macOS /Applications/XAMPP/logs/php_error_log
Ubuntu, Apache mod_php /var/log/apache2/error.log
Ubuntu, PHP-FPM /var/log/php8.3-fpm.log and the site’s Apache or nginx error log
Docker official image Container stderr: docker logs container-name
Shared hosting An error_log file next to the script, or the control panel’s log viewer
Terminal
tail -f /var/log/apache2/error.log       # watch it live while you reload the page

If nothing appears anywhere, log_errors is off or error_log points somewhere unwritable. Set both explicitly in php.ini.

Frameworks#

Laravel, Symfony and WordPress each layer their own handling on top:

  • Laravel: APP_DEBUG=true in .env shows the full error page; logs are in storage/logs/laravel.log.
  • Symfony: APP_ENV=dev enables the debug toolbar and detailed errors; logs in var/log.
  • WordPress: define('WP_DEBUG', true); and define('WP_DEBUG_LOG', true); in wp-config.php write to wp-content/debug.log.

With a framework, use its switch rather than ini_set; the framework may override the raw settings.

Production#

Display off, log on, and read the log. A good production setup:

Output
display_errors = Off
log_errors = On
error_reporting = E_ALL
error_log = /var/log/php/app.log

Combine it with a custom error handler or a framework’s logging so that errors reach somewhere you actually look — a monitoring service, or at least an email. A log nobody reads is not much better than no log.

Questions people ask#

Why do I see a 500 error instead of the PHP error?

A fatal error with display off produces a bare 500 from the server. The detail is in the PHP or web-server log. A 500 caused by a bad .htaccess line is in the Apache log only.

Errors show on one site and not another on the same server.

A .user.ini, .htaccess or framework setting in the second site is overriding php.ini. Check the site’s root and its config.

Does error_reporting(E_ALL) slow the site down?

No. Reporting affects what is recorded, not how the code runs. Displaying and logging thousands of notices does have a cost, which is a reason to fix the notices.

What is the difference between a warning and a notice?

Both let execution continue. A warning signals something likely wrong, such as a missing file; a notice signals something sloppy, such as an undefined variable. Since PHP 8, many former notices are warnings, and some warnings are now exceptions.

Where to go next#

Handling errors and exceptions in PHP, properlyRead next

Keep reading

PHP

PHP Security Best Practices

The security work that actually matters in PHP: prepared statements, output escaping, CSRF tokens, password hashing, file uploads and session handling.

6 min read

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *