Building an Authentication System

The rest of this lesson walks you through building an authentication mechanism using PHP sessions.

How the System Works

There are two main components of the authentication system you're going to build now. First, you need a login processor that checks the validity of the username and password entered in the form. You also need a piece of code that can be put at the top of each script to check the session and make sure the user is authenticated before continuing.

Login Forms You need to make sure you always use the POST method for login forms. Submitting a username and password by using the GET method causes these values to appear in the URL of the next page for anyone to see!

You should split off the session-checking code into an include file,, so that it is simple to protect a page by simply putting the following statement at the top of the script:

 include ""; 

You can use a single session variable to store the username of the logged-in user. If the variable contains a username, that user is logged in; logging a user out is as simple as deleting this session variable. As long as nobody else shares the domain on which your website is hosted and could create a conflicting session, this is adequately secure. Knowing this, can really be as simple as the following:

 session_start(); if (!isset($_SESSION["auth_username"])) {   echo "You must be logged in to view this page";   exit; } 

Here you simply display a message and exit the script if the user is not logged in. You will see later on how you can improve this for usability, but you need to create the login process itself first.

Authenticating a Login

The login form, at its heart, needs to contain just two fieldsusername and passwordand a submit button. As long as these are present, the form's layout is up to you. For now, you can keep it fairly plain, in a simple table layout. Listing 15.1 shown the basic login form.

Listing 15.1. A Basic Login Form
 <FORM ACTION="login.php" METHOD="POST"> <TABLE BORDER=0> <TR>   <TD>Username:</TD>   <TD><INPUT TYPE="TEXT" SIZE=10 NAME="username"></TD> </TR> <TR>   <TD>Password:</TD>   <TD><INPUT TYPE="PASSWORD" SIZE=10 NAME="password"></TD> </TR> </TABLE> <INPUT TYPE=SUBMIT VALUE="Log in"> </FORM> 

Password Fields The PASSWORD type input works exactly the same way as a TEXT type, but the characters entered are obscured as they are typed. The only restriction on a password field is that it cannot be given a VALUE attribute for a default value.

The form handler script, login.php, needs to check the submitted username and password values against the list of valid users. In most cases, you would check the values against a user database. You will learn about database access in PHP in Lessons 19, "Using a MySQL Database," and 20, "Database Abstraction," and for now you can just use a simple array of users who are permitted to use the site. Listing 15.2 shows how to do this.

Listing 15.2. A Login Processor Script
 <?php session_start(); $passwords = array("chris"   => "letmein",                    "damon"   => "thisisme",                    "shelley" => "mypassword",                    "vanessa" => "opensesame"); if (!$_POST["username"] or !$_POST["password"]) {   echo "You must enter your username and password";   exit; } if ($_POST["password"] == $passwords[$_POST["username"]]) {   echo "Login successful";   $_SESSION["auth_username"] = $_POST["username"]; } else {   echo "Login incorrect"; } ?> 

First, an associative array of passwords is built, using the usernames as keys. The script first checks that both the username and password have been entered and exits immediately if that information is missing.

Then the submitted password is compared to the array element whose key is the submitted username. If the two passwords match, the user is logged in, and the auth_username session variable is initialized. Otherwise, a message is displayed that the login failed.

After a user's session has been validated, he or she can view a protected page without interrupting the script's progress.

Encrypting Passwords

In the previous example, the passwords are stored in plain text. You probably suspected that this is not particularly secure; anyone who can view the source code of this script can see the passwords for every user.

Prying Eyes Even if your server security is airtight, can you be sure that nobody is looking over your shoulder? You should always try to prevent unencrypted passwords from being displayed onscreen.

The crypt function in PHP provides a simple but effective one-way encryption algorithm. The same kind of encryption is used by htpasswd and even Unix system passwords. To encrypt a password, you pass the password to crypt, along with $saltanother string around which the encryption is based:

 $crypt_password = crypt($password, $salt); 

Although the encrypted string cannot be decoded back to the original password, every time you run crypt on the same password with the same salt, the result is the same. Knowing this, you can store only the encrypted version of the password and compare it to the freshly encrypted user input.

Salts If you do not specify a salt, a random one is chosen so subsequent calls to crypt will product different results. A two-character salt, as used by Unix password files and htpasswd, is sufficient.

How a string encoded using crypt looks may vary between different web servers as a system-level encryption library is used. Encrypted passwords are not guaranteed to be portable between different systems. The revised login.php file is shown in Listing 15.3, but be aware that the encrypted passwords shown may not be valid for your system.

Listing 15.3. A Login Processor Script with Encrypted Passwords
 <?php session_start(); $passwords = array("chris"   => "ZXsDiRf.VBlWQ",                    "damon"   => "bQLXBRzdBci7M",                    "shelley" => "KkTH39mVsoclc",                    "vanessa" => "69SvRIB9QVukk"); if (!$_POST["username"] or !$_POST["password"]) {   echo "You must enter your username and password";   exit; } $salt = substr($passwords[$_POST["username"]], 0, 2); if (crypt($_POST["password"], $salt)           == $passwords[$_POST["username"]]) {   echo "Login successful";   $_SESSION["auth_username"] = $_POST["username"]; } else {   echo "Login incorrect"; } ?> 

The salt is always found in the first two characters of the encrypted string, so you assign these two characters to $salt to use in the call to crypt. Other than this, the process is identical to using plain-text passwords.

Usability Considerations

The mechanism you have implemented so far is fairly crude. Any login error results in a message being displayed and the script ending. Even when a login is successful, the flow ends, and the user needs to revisit a protected page directly.

The ideal login mechanism interrupts a hit to a protected web page and displays its login form. Then, after successfully authenticating, it forwards the user to the page he or she was originally trying to access.

One way to add this enhancement is to check the name of the script that the user attempted to access in; the script name and the query string, if there was one, can be found in $_SERVER["REQUEST_URI"]. The login form would then be displayed by itself, rather than being a separate page.

If you add the following hidden input to the login form, the login processor itself will know which script the user came from, and then you can send the user back to the page he or she was trying to access.

 <INPUT TYPE="HIDDEN" NAME="destination"        VALUE="<?php print $_SERVER["REQUEST_URI"];?>"> 

When authentication is successful, rather than print a message to screen, you can forward the user to his or her destination by using the following statement:

 header("Location: $_POST["destination"]); 

    Sams Teach Yourself PHP in 10 Minutes
    Sams Teach Yourself PHP in 10 Minutes
    ISBN: 0672327627
    EAN: 2147483647
    Year: 2005
    Pages: 151
    Authors: Chris Newman

    Similar book on Amazon © 2008-2017.
    If you may any questions please contact us: