Securing PHP Files using HTTP Authentication
By Peter McNulty : 15-01-2005
Protecting Single and Multiple Files
We are going to start off adding password protection to a single file, and then modify that so we add it to multiple files. The way HTTP authentication works, is by using HTTP headers which the browser and the web server (Apache) both understand. By using the correct headers we can produce a page which asks for the user to login. If the entered information is correct, we show the page, otherwise we show a nice error message.
As I mentioned, the basis of HTTP authentication is using HTTP headers, which are accessible by using the PHP header() function. This specifics of this function have been explained before in great detail in Speed Limit File Downloads. However, for the sake of drilling it into your brains, the most important thing about the header() function is that there can be no output to the browser before calling header(). If there is, you will receive a nasty error and the script will cease to function.
Here's the code:
This code contains all the important aspects of HTTP authentication that you need to get started. First thing to notice is that there is no output before header() calls. Secondly, notice that we have two special variables inside the $_SERVER superglobal. These are PHP_AUTH_USER and PHP_AUTH_PW and they represent the current HTTP authenticated username and password. As they may not exist when we call our script, I have placed an 'at' symbol (@) before both of these variables. The @ symbol tells PHP to suppress any errors that may arise in the specified statement. Hence, we know that an error might occur because these variables may not yet exist, so we use @ to suppress it.
The way the headers are written are very important using this method of authentication, as very slight changes can result in the login procedure not working and everyone having access to your file(s). It is important that the orders of the headers are correct and that the actual content is correct. For example, for maximum compatibility, the B in Basic must be capital, as well as the text in realm being surrounded in double quotes, not single.
In the first header, we have a realm option. This is where we can place some text that will go on our username / password request form. You shouldn't place too much text here, just a basic description of what the user is logging in to.
The usage of this script is a little strange to visualize, because first we check if the user is logged in, and if not, then we send some headers and then end the script. If actual usage, after the headers are sent, the browser waits from the input from the user. Once the user clicks on the OK button, it will then reload the script, to check if the username and password combination are correct. If not it will display the login again (up to three times), and then upon failure will show the error page. If the username is correct, it skips the headers section, and just displays the normal content of your script.
Securing Multiple Files
Most of the time when you are password protecting an area on your website, you will need to secure more than one page. What you would then do, if move all the above code into an include file, and then include the file on any page that you want to password protect. This could become cumbersome, especially if you are already including many files. The alternative is to convert this into a function, so that you can add it into a function library file (which you might already have). This way, the code is always available, and we can make it a little more reuseable.
Now we have a function called validateUser which takes two parameters; $fUsername and $fPassword. These are the username and password that you want the user to login with. I have also added default values so that if you do not specify a username or password (maybe you forget to), then the user can log in with the default values.
This function can then be added to a library file of functions. These are used to hold commonly used functions in your programs and are usually necessary if you are writing a lot of scripts. Commonly, I use global.php for my library functions.
Here I have assumed that you have placed the function into a file called globa.php so that we can include it. I have used require_once() to include the file, so that if PHP cannot find the file, the script will exit and also the file will not be included more than once. Now to run the authentication routine, we just make a simple call to validateUser() with the username and password we expect the user to log in with.
These examples are useful if you only have one or two people logging into your site and they share the same username. However, sometimes you may want to allow a multitude of people to access this area. For this, it is common to use databases.