Section 13.2. PHP and HTTP Authentication


13.2. PHP and HTTP Authentication

PHP can use authentication from the Apache web server. PHP sends a header request to the browser requesting an authentication dialog on the client's browser. You'll recognize this prompt as a standard browser login prompt. Because the authentication head must come before any other HTML output, this works only with the module-based PHP installation, not the CGI version.

Example 13-4 shows how to use HTTP authentication.

Example 13-4. Using HTTP authentication with a PHP script

 <?php if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) { header('WWW-Authenticate: Basic realm="Member Area"'); header("HTTP/1.0 401 Unauthorized"); echo "Please login with a valid username and password."; exit; } else { echo "You entered a username of: ".$_SERVER['PHP_AUTH_USER']." "; echo "and a password of: ".$_SERVER['PHP_AUTH_PW']."."; } ?> 

The code from Example 13-4 displays a prompt like the one in Figure 13-2.

Figure 13-2. The prompt for authentication to the Member Area realm


If the user clicks Cancel, he'll see Figure 13-3.

Figure 13-3. Clicking Cancel causes a message that the user must log in


That's a fairly simple example. We checked to see if the username and password were set, then displayed them to the user. The realm field provides a way for grouping related pages together for access restrictions. Any PHP page that presents the authentication headers within the same realm as the login page is accessible after a successful login. This spares the user from having to re-authenticate for each PHP page.

Example 13-5 validates the username and password retrieved from an authentication prompt. If they don't match, access to all pages in that realm is denied.

Example 13-5. Checking the values returned from the authentication prompt

 <?php $username = 'jon_doe'; $password = 'MyNameIsJonDoe'; if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) { header('WWW-Authenticate: Basic realm="Member Area"'); header("HTTP/1.0 401 Unauthorized"); echo "You must enter in a username and password combination!"; exit; } elseif (strcmp($_SERVER['PHP_AUTH_USER'], $username) !== 0 || strcmp($_SERVER['PHP_AUTH_PW'], $password) !== 0) { header('WWW-Authenticate: Basic realm="Member Area"'); header("HTTP/1.0 401 Unauthorized"); echo "Your username and password combination was incorrect!"; exit; } echo("You have successfully logged in!"); ?> 

Example 13-5 checks that the authentication was set. If it wasn't, request a username and password. The elseif clause checks to see whether the strings are equal to each other.

This is different than simply comparing two strings with the equality (==) operator. When comparing input, the == operator can cause unexpected results. Therefore, use the strcmp function. The strcmp function returns 0 only when the two strings are identical. If either the username or password comparison returns a value other than 0, you deny access; otherwise, access is granted. If they don't match, request another authentication prompt from the user by sending authentication headers again. They then must come before any other output.

13.2.1. Storing a Username and Password in a Database

Let's revisit some of the knowledge you picked up back in Chapter 5. We're going to create a new table for users. Instead of comparing a username and password to values that are set in your PHP script, you'll check them against a database table called USERS. As explained in Chapter 5, you'll want to log into the command prompt and create a table using the syntax in Example 13-6.

Example 13-6. Creating the users table to store login information

 CREATE TABLE `users` ( `user_id` INT NOT NULL AUTO_INCREMENT, `first_name` VARCHAR(100), `last_name` VARCHAR(100), `username` VARCHAR(45), `password` CHAR(32), PRIMARY KEY (`user_id`)); 

This code returns:

 Query OK, 0 rows affected (0.23 sec) 

To add a user, you create an entry in the database for a user with an encrypted password, as shown in Example 13-7.

Example 13-7. Creating the entry in the database for a user with an encrypted password

 INSERT INTO users (`first_name`, `last_name`, `username`, `password`) VALUES ('Michele','Davis', 'mdavis', MD5('secret')); 

This yields:

 Query OK, 1 row affected (0.01 sec) 

To check that your row was created and see what the MD5 encoding function returned, you query the users table:

 SELECT * FROM users; 

Presto:

 +---------+------------+-----------+----------+----------------------------------+ | user_id | first_name | last_name | username | password | +---------+------------+-----------+----------+----------------------------------+ |       1 | Michele    | Davis     | mdavis   | 5ebe2294ecd0e0f08eab7690d2a6ee69 | +---------+------------+-----------+----------+----------------------------------+ 1 row in set (0.00 sec) 

Now that you've created the table, let's set up the login script to test a username and password. You encoded the password using MD5 to provide an extra layer of security. The password that created the encoded string cannot be determined from the stored string. This means that even if a malicious user finds out another user's encoded password, she can't use it to log in. However, this method is for testing only, and more secure options will be discussed later in the book.

Example 13-10 reuses much of the same code from the example in the previous section, so don't worry about having to rewrite too much! The major difference is that instead of using the strcmp command to check the username and password, you place them into a query and use the database to check for a match.

Don't forget that you still need your database login information in a file called db_login.php, shown in Example 13-8.

Example 13-8. The database login details

 <?php $db_host='localhost'; $db_database='test'; $db_username='test'; $db_password='yourpass'; ?> 

The values from Example 13-8 are used in Example 13-9.

Example 13-9. Verifying a username and password against the database

 <?php require_once('db_login.php'); require_once('DB.php'); if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) { header('WWW-Authenticate: Basic realm="Member Area"'); header("HTTP/1.0 401 Unauthorized"); echo "You must enter in a username and password combination!"; exit; } $web_username = $_SERVER['PHP_AUTH_USER']; $web_password = $_SERVER['PHP_AUTH_PW']; $connection = DB::connect("mysql://$db_username:$db_password@$db_host/$db_database"); if (DB::isError($connection)){ die ("Could not connect to the database: <br />". DB::errorMessage($connection)); } $query = "SELECT `user_id`, `username` FROM `users` WHERE `username`='".$web_username."' AND `password`=MD5('".$web_password."') LIMIT 1"; $result = $connection->query($query); if (DB::isError($result)){ die("Could not query the database: <br />".$query." ".DB::errorMessage($result)); } if (!$row = $result->fetchRow(DB_FETCHMODE_ASSOC)) { header('WWW-Authenticate: Basic realm="Member Area"'); header("HTTP/1.0 401 Unauthorized"); echo "Your username and password combination was incorrect!"; exit; } echo("You have successfully logged in as ".$row['username']."!"); ?> 

You may have to change display_errors = Off in the php.ini file if you get the following error.

 Warning:  headers already sent message causing the message box not to display. 

This may be a little too much to consume at the moment, but save the script and run it, which displays the screen in Figure 13-4. Then try logging in with the username of mdavis and a password of secret.

Figure 13-4. Prompting for username and password before checking the database


You should see that the script handles the login, shown in Figure 13-5, with the database because there is a successful match of data.

Figure 13-5. A successful match with the database's credentials


If you entered something invalid, you'll see an unauthorized page such as Figure 13-6 telling you that the username and password are incorrect.

Figure 13-6. An invalid username and password causes this message to display




Learning PHP and MySQL
Learning PHP and MySQL
ISBN: 0596101104
EAN: 2147483647
Year: N/A
Pages: 135

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net