Join Kevin Skoglund for an in-depth discussion in this video Configure error reporting, part of Creating Secure PHP Websites.
In this movie, we'll learn how to configure error reporting in PHP with security in mind. Which errors we want to see depends entirely on the circumstances. When we're first developing our PHP code, we want to see all errors, so we can address any problems or warnings that appear. But when we finally deploy our PHP code to our production server and make it visible to the public, well, then we want to show no errors. This is part of the principle of security through obscurity. We don't want to give the public any clues about what might have gone wrong and those error notices include lots of valuable information about our code.
So we're going to have two sets of configurations, one for development and one for production. There are four primary configurations for error reporting. The first is simply called error_reporting and it controls what errors are worthy of PHP's attention. The second is display_errors and that controls whether errors should be displayed in a browser to the user. And then there's log_errors, which controls whether errors should be logged to a log file. And error_log, which declares the path to the log file so that PHP can find it and log the errors there.
You want to set each of this values in your php.ini file. They can also be set inside your PHP code itself, but if you do, you may not see all the errors. For example, if there's a parsing error, it would prevent PHP from ever getting to your error configuring commands, so it's better to use php.ini whenever possible. And we'll talk about working in a shared hosting environment in a bit. So let's talk about the first one. How do we tell PHP what errors are worthy of attention? We do that by using some predefined error constants and a full list of these is available on the php.net website.
But I'm going to go over some of the most important ones and the ones we want to concern ourselves with here. All of these are in all capital letters and begin with a capital E and an underscore. After that, we have ERROR, which is for fatal errors. Those are errors that PHP was not able to recover from. It means our script did not finish running. Warnings, which are non-fatal errors. PHP found a problem, it was a big problem, but PHP was able to keep going with the rest of the script anyway. Then there are notices, things that might be possible problems.
There's strict, which is a new type that was introduced in PHP 5, which are suggested improvements. These are things that, if you really want to be picky about your code, you really ought to go ahead and fix. And then there's deprecations, which was introduced in PHP 5.3, and those are warnings about code that's scheduled for removal. There's not actually a problem with your code at the moment. However, if you want to make your code future-proof, you're going to want to address those issues. And then there's ALL, which encompasses all of these different types that you see above.
Only, it hasn't always been the case that ALL included everything. Let me show you what I mean as we talk about the development settings. So in development, we want to see everything, right? So, in PHP before version 5.0, we just simply set error_reporting equals E_ALL and that would tell PHP to show us all of the errors in development. Starting in PHP 5 though, they introduced this new type, STRICT, and for whatever reason, STRICT was not included in ALL.
So if you wanted to have everything, you had to say E_ALL and then use the or-operator. That's that upright pipe. E_ALL or E_STRICT. And that would show you absolutely everything during development. And then starting in 5.4, STRICT was rolled into ALL so that ALL actually did include it and we could once again just go back to saying E_ALL. So depending on your PHP version, you'll want to pick the one that will show you everything during development. Now, it's possible to exclude some things during development if you want and some people do, but that's a less secure approach.
It's best if during development, you're seeing absolutely everything, all the warnings, all the notices, all the stricts, all the deprecations. You want everything to show up during development so that you have the opportunity to make your code as secure as possible. Now, in production, you can also log all errors, and many developers do. However, this means logging every warning, every deprecation, every strict, and it does it every time the code runs. So if you have 1000 people coming to visit your site and use your code, then it's going to log that deprecation 1000 times to the log file and that fills up your log files unnecessarily.
It also makes it harder to find the real errors when they occur. If we've configured it so that all errors are visible during development, then we will have seen and had a chance to address those errors already. We don't need the production server to care about them. We do want the production server to keep track of the big problems, though. And so we can tell it just to notify us about errors, warnings, and parse errors at a minimum. PARSE wasn't listed in errors that we went over earlier, but you can guess what it does. Now we could list only the errors we want, but I think a better approach is to still use that ALL and then list the errors that we don't want included.
And we do that with that caret symbol in between. So this says, show me all errors except the deprecations. If we want to admit more types, we can do that by putting in parentheses and using the or operator again. So, error_reporting equals ALL, but not anything that is STRICT, DEPRECATED or NOTICE. And it's really a matter of personal taste for what you want to leave out there. I think STRICT, DEPRECATED AND NOTICE are good ones. You might decide that you want NOTICEs still left in and only take out the STRICT and the DEPRECATED, but the fundamental idea is the same.
In production, we don't want to log all of the things that we care about during development. We also want to treat errors differently by using display errors. In development, we want display_errors to be On. We want those notices and those warnings to just pop up right in our face in the browser. We want PHP to show them to us so we can fix them. But in production, we don't want to do that. We want to set display_errors to be Off, so that users cannot see those in their browser. Instead, we're going to use log_errors for them.
In development, you typically would have log_errors off. There's no reason to log those errors to a log file if they're popping up in your browser. Now, you can turn it on if you want them logged there, that's your option. For production though, you do want log_errors to be On. You're not going to display them in the browser. Instead, you're just going to discretely log them to a file so that you, the developer, can go onto the server and review those logs later, and see what the problems were. The user doesn't need them, you do, so you put them in the log file. And if we're going to turn on logging, we also have to tell PHP where that error log is located.
In development, we really don't have to provide anything, and you can just comment it out entirely if you want because we have it turned off, so it doesn't matter. But for production, you'd provide the path to find that log file. I've given just an example path, using /private/path/to/errors.log. That would be the full and complete path that PHP needed to find that file on the hard drive. If you're on Windows, you can provide the C and a colon to specify the drive at the front of that.
There's also an additional option. We can provide a keyword here called syslog. And if we tell PHP that the error log is syslog, then PHP will instead turn to the operating system to find out where it should log those files to. So we'll turn to Windows or UNIX and ask, where are you logging your files to, where are your errors going to? That's where I want to put my errors as well. And it would be up to you then to go into the operating system and configure that or to find out where it should be. Remember that if you need help finding your log file, phpinfo is the function that will show you all of your PHP configurations, including the location of the error log
- Cross-site scripting (XSS)
- Cross-site request forgery (CSRF)
- SQL injection
- Encrypting and signing cookies
- Session hijacking and fixation
- Securing uploaded files
- User authentication
- Throttling brute-force attacks
- Blacklisting IPs
- Implementing password reset tokens