Advanced PHP Error Handling via PHP
In my previous articles on PHP error handling, I explain the process whereby PHP error handling may be achieved using htaccess. Handling (logging, reporting) PHP errors via htaccess requires the following:
- Access/editing privileges for htaccess files
- A server running PHP via Apache, not CGI (e.g., phpSuExec)1
- Ability to edit/change permissions for files on your server
If you are having trouble handling PHP errors using htaccess, these three items are the first things to check. If it turns out that you are unable to use htaccess to work with PHP errors, don’t despair — this article explains how to achieve the same goals using local
php.ini files. To implement this strategy, the following is required:
- Ability to create/edit a
php.inifile in your
- A server running PHP via CGI (e.g., phpSuExec), not Apache2
- Ability to edit/change permissions for files on your server
- Access/editing privileges for htaccess files (not required)
Assuming satisfaction of the preceding requirements, the remainder of this tutorial explains how to enable global (sitewide) PHP error handling using a custom
php.ini file. After explaining the implementation process for production environments, we will explore several useful functional customizations for both production and development servers3. Excited? Great, let’s begin..
Step 1: Add custom php.ini file to site root directory
Using a text editor, create a file named “php.ini” and add the following PHP directives4:
;;; php error handling for production servers display_startup_errors = off display_errors = off html_errors = off log_errors = on docref_root = 0 docref_ext = 0 error_log = /var/log/php/errors/php_error.log
Here, we are disabling all public error displays and enabling private error logging in the specified file. After editing the path and file name of the error log in the last line, save the file and upload it to the root directory of your domain. Generally, this directory is named “
public_html”, but it may be different on your server. Then, create the specified log file and ensure that it is writable (via
777) by the server.
Step 2: Enable subdirectory inheritance of custom settings
At this point, error logging should be working, but only for the same directory in which you have placed the
php.ini file. Unfortunately, by default, locally specified
php.ini directives only affect the directory in which they are located — they are not inherited by subdirectories as they are for htaccess directives. Thus, each directory for which you would like to log errors requires its own copy of the
php.ini file. Fortunately, if you are able to access and edit your site’s root htaccess file, there is an easy way to enable subdirectory inheritance of your custom
php.ini settings. Simply add the following code to your site’s root htaccess file:
# enable subdirectory inheritance of custom php settings suPHP_ConfigPath /home/path/public_html
This trick takes advantage of htaccess’ inheritance properties by using them to “point” from each subdirectory to the custom
php.ini file in the root (e.g.,
public_html) directory. Note that you may override the root
php.ini directives by placing alternate
php.ini files in the target subdirectory.
Step 3: Secure your custom php.ini and log files
Once everything is working, it is important to protect your domain by securing your newly created files. In addition to setting permissions to
600 for your custom
php.ini file(s), you may also want to add the following directives to your root htaccess file:
# deny access to php.ini <Files php.ini> order allow,deny deny from all satisfy all </Files> # deny access to php error log <Files php_error.log> order allow,deny deny from all satisfy all </Files>
And that’s it — PHP error logging should now be securely enabled on your domain. Now let’s explore some useful functional customizations for both production and development servers..
Controlling the level of PHP error reporting
Using your custom
php.ini file, it is possible to set the level of error reporting to suit your particular needs. The general format for controlling the level of PHP errors is as follows:
;;; general directive for setting php error level error_reporting = integer
There are several common values used for “integer”, including:
- Complete error reporting — for complete PHP error logging, use an error-reporting integer value of “
8191”, which will enable logging of everything except run-time notices5.
- Zend error reporting — to record both fatal and non-fatal compile-time warnings generated by the Zend scripting engine, use an error-reporting integer value of “
- Basic error reporting — to record run-time notices, compile-time parse errors, as well as run-time errors and warnings, use “
8” for the error-reporting integer value.
- Minimal error reporting — to record only fatal run-time errors, use an error-reporting integer value of “
1”, which will enable logging of unrecoverable errors.
Of course, there are many more error-reporting values to use, depending on your particular error-logging needs. For more information on logging PHP errors, refer to the Error Handling and Logging Functions page at php.net.
Setting the maximum file size for your error strings
Using your custom
php.ini file, you may specify a maximum size for your PHP errors. This controls the size of each logged error, not the overall file size. Here is the general syntax:
;;; general directive for setting max error size log_errors_max_len = integer
Here, “integer” represents the maximum size of each recorded error string as measured in bytes. The default value is “
1024” (i.e., 1 kilobyte). To unleash your logging powers to their fullest extent, you may use a zero value, “
0”, to indicate “no maximum” and thus remove all limits. Note that this value is also applied to displayed errors when they are enabled (e.g., during development).
Disable logging of repeated errors
If you remember the last time you examined a healthy (or sick, depending on your point of view) PHP error log, you may recall countless entries of nearly identical errors, where the only difference for each line is the timestamp of the event. If you would like to disable this redundancy, throw down the following code in your custom
;;; disable repeated error logging ignore_repeated_errors = true ignore_repeated_source = true
With these lines in place, repeated errors will not be logged, even if they are from different sources or locations. If you only want to disable repeat errors from the same source or file, simply comment out or delete the last line [note: comments must begin with a semicolon (
; ) in
php.ini files]. Conversely, to ensure that your log file includes all repeat errors, change both of the
true values to
Putting it all together — Production Environment
Having discussed a few of the useful ways to customize our PHP error-logging experience, let’s wrap it all up with a solid,
php.ini-based error-handling strategy for generalized production environments. Here is the code for your custom
;;; php error handling for production servers display_startup_errors = false display_errors = false html_errors = false log_errors = true ignore_repeated_errors = false ignore_repeated_source = false report_memleaks = true track_errors = true docref_root = 0 docref_ext = 0 error_log = /var/log/php/errors/php_error.log error_reporting = 999999999 log_errors_max_len = 0
Or, if you prefer, an explanatory version of the same code, using comments to explain each line:
;;; php error handling for production servers ; disable display of startup errors display_startup_errors = false ; disable display of all other errors display_errors = false ; disable html markup of errors html_errors = false ; enable logging of errors log_errors = true ; disable ignoring of repeat errors ignore_repeated_errors = false ; disable ignoring of unique source errors ignore_repeated_source = false ; enable logging of php memory leaks report_memleaks = true ; preserve most recent error via php_errormsg track_errors = true ; disable formatting of error reference links docref_root = 0 ; disable formatting of error reference links docref_ext = 0 ; specify path to php error log error_log = /var/log/php/errors/php_error.log ; specify recording of all php errors error_reporting = 999999999 ; disable max error string length log_errors_max_len = 0
This PHP error-handling strategy is ideal for a generalized production environment. In a nutshell, this code secures your server by disabling public display of error messages, yet also enables complete error transparency for the administrator via private error log. Of course, you may wish to customize this code to suit your specific needs. As always, please share your thoughts, ideas, tips and tricks with our fellow readers. Now, let’s take a look at a generalized error-handling strategy for development environments..
Putting it all together — Development Environment
During project development, when public access to your project is unavailable, you may find it beneficial to catch PHP errors in real time, where moment-by-moment circumstances continue to evolve. Here is a generalized,
php.ini-based PHP error-handling strategy for development environments. Place this code in your custom
;;; php error handling for production servers display_startup_errors = true display_errors = true html_errors = true log_errors = true ignore_repeated_errors = false ignore_repeated_source = false report_memleaks = true track_errors = true docref_root = 0 docref_ext = 0 error_log = /var/log/php/errors/php_error.log error_reporting = 999999999 log_errors_max_len = 0
For this code, we will forego the line-by-line explanations, as they may be extrapolated from the previous section. This PHP error-handling strategy is ideal for a generalized development environment. In a nutshell, this code enables real-time error-handling via public display of error messages, while also enabling complete error transparency for the administrator via private error log. Of course, you may wish to customize this code to suit your specific needs. As always, please share your thoughts, ideas, tips and tricks with our fellow readers.
Whew! That about does it for this article.. — see you next time!
- 1 To determine if your server is running PHP via phpSuExec (i.e., CGI) instead of Apache, upload a
phpinfo()file and check the “Server API” near the top of the file. If it says “Apache”, PHP is running on Apache; if it says “CGI”, PHP is running via phpSuExec.
- 2 This is important because it is impossible to manipulate
php.inidirectives via htaccess while running PHP on phpSuExec.
- 3 For more information, check out the manual on Error Handling and Logging Functions at php.net
- 4 Many thanks to Jeff N. at A Small Orange for helping with the information provided in this article :)
- 5 Due to the bitwise nature of the various error-reporting values, the value for logging all errors continues to increase. For example, in PHP 5.2.x, its value is
6143, and before that, its value was
2047. Thus, to ensure comprehensive error logging well into the future, it is advisable to set a very large value for
error_reporting, such as
I have a some doubt in the .htaccess file. In my hosting provider they did not enable the php_pdf.dll file. I need to use that php_pdf.dll in my progaram for that i have to include some line in the .htaccess file. in my hosting .htaccess file is present in the www/.htaccess directory. if you know the answer please reply me to my mail.
Hi Bala, I would like to help, but I am unfamiliar with this issue. Hopefully, Google will reveal some useful information..
Thanks for an excellent post. PHP error handling is not something with much info on the Internet.
I was wondering if you could clarify the location of the log file as this part is confusing and is not working for me.
Your example says:
error_log = /var/log/php/errors/php_error.log
My confusion is that the path to the error log is
home/username/public_html/php_error.logon my server.
@Michael West: Yes, that is simply an example of a possible file path. You may use any writable text file on your server, but I would recommend placing it above the root directory.
I’d suggest using “
error_reporting = E_ALL | E_STRICT”, due to the fact that
E_ALLdoes not contain
E_STRICTin PHP < 6.
Great point, Till — thanks for the heads up! :)