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.ini
file in yourpublic_html
directory - 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 755
or 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 “
128
”. - 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 php.ini
file:
;;; 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 false
.
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.ini
file:
;;; 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.ini
file:
;;; 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!
Footnotes
- 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.ini
directives 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 was2047
. Thus, to ensure comprehensive error logging well into the future, it is advisable to set a very large value forerror_reporting
, such as2147483647
.
7 responses to “Advanced PHP Error Handling via PHP”
Hi,
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.
Thanks
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.log
on 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 thatE_ALL
does not containE_STRICT
in PHP < 6.Great point, Till — thanks for the heads up! :)