Article
Managing Users with PHP Sessions and MySQL
The Access Control Script
For each page that you want to protect with this access control scheme (so that only registered users may view it), your script must follow the procedure described by the flowchart below.

The first time that a protected page is requested, the user will not have entered his or her login details yet. The script detects this and prompts the user for a username and password with a login form instead of displaying the requested page. When that form is submitted, the page is reloaded, this time with a username and password specified. The script sees that the login details have been specified, and registers them as session variables so that they remain available for the rest of the user's visit. Finally, the script checks the database to make sure the username/password combination is valid. If it is, the page requested is displayed. If not, an "access denied" message is displayed with a link inviting the user to try logging in again.
Since this procedure will be identical for all protected pages, it makes sense to implement it as a common include file. This will allow you to protect a page by simply adding the following line at the top of the file:
<?php include 'accesscontrol.php'; ?>
With the objective now clear, I'll walk you through the code for accesscontrol.php. Begin by including your two handy include files:
<?php // accesscontrol.php
include_once 'common.php';
include_once 'db.php';
I use include_once here instead of include just in case the main file also uses these include files. If common.php were included twice, for example, PHP would issue a warning that the error function had been declared twice.
Next, I call session_start to either begin a new session (if this is the first page in the user's visit), or load the variables belonging to the user's current session.
session_start();
At this point, the user's login details should be available whether they were just submitted from a login form (in the $_POST array) or stored in the user's session (in the $_SESSION array). So as a first order of business, the script needs to pull the login credentials out of either the $_POST or the $_SESSION array:
$uid = isset($_POST['uid']) ? $_POST['uid'] : $_SESSION['uid'];
$pwd = isset($_POST['pwd']) ? $_POST['pwd'] : $_SESSION['pwd'];
These two lines use a handy (if confusing) syntax called the ternary operator, which takes this form:
condition ? value_if_true : value_if_false
If condition is true, the expression will equal value_if_true. If not, it will equal value_if_false.
So if you compare this to the first line above, you'll see that if there is a 'uid' value in the $_POST array (isset($_POST['uid'])), $uid will be set to the value of $_POST['uid']. If not, it will be set to the value of $_SESSION['uid']. The same thing happens to create $pwd from the $_POST or $_SESSION array.
If you really aren't comfortable with the ternary operator, here's how you can do the same thing with if statements:
if (isset($_POST['uid']) {
$uid = $_POST['uid'];
} else {
$uid = $_SESSION['uid'];
}
if (isset($_POST['pwd']) {
$pwd = $_POST['pwd'];
} else {
$pwd = $_SESSION['pwd'];
}
As you can see, the ternary operator can save a lot of typing if you can get your head around it!
Now, at this stage, the only case in which the user's ID and password would not be available is if they had not been entered during this visit to the site.
if(!isset($uid)) {
?>
<!DOCTYPE html PUBLIC "-//W3C/DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> Please Log In for Access </title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1" />
</head>
<body>
<h1> Login Required </h1>
<p>You must log in to access this area of the site. If you are
not a registered user, <a href="signup.php">click here</a>
to sign up for instant access!</p>
<p><form method="post" action="<?=$_SERVER['PHP_SELF']?>">
User ID: <input type="text" name="uid" size="8" /><br />
Password: <input type="password" name="pwd" SIZE="8" /><br />
<input type="submit" value="Log in" />
</form></p>
</body>
</html>
<?php
exit;
}
When the login form above is submitted, the page will be reloaded, this time with the $uid and $pwd variables set to the user's ID and password. The next step according to the flowchart above is to register these as session variables, ensuring that they are available to all other protected pages that the user views during this visit. Note that, at this point, the script still doesn't know whether or not the user ID and password that were entered are valid. I'll explain why the script does things in this order shortly.
$_SESSION['uid'] = $uid;
$_SESSION['pwd'] = $pwd;
To find out if the user ID and password are valid, the script searches the database for matching entries. In the SELECT query, I have encoded the $pwd variable using MySQL's PASSWORD function to match it against the stored password, which is also encoded. Be sure to use your own database name here -- I have called mine sessions -- and your own email address in the error message.
dbConnect("sessions");
$sql = "SELECT * FROM user WHERE
userid = '$uid' AND password = PASSWORD('$pwd')";
$result = mysql_query($sql);
if (!$result) {
error('A database error occurred while checking your '.
'login details.\\nIfhis error persists, please '.
'contact you@example.com.');
}
If no matching rows are found in the database, then the login details provided are incorrect. The script checks for this using the mysql_num_rows function, and displays a message denying access to the site, and inviting the user to try logging in again. To make this possible, the script also unregisters the two session variables ($_SESSION['uid'] and $_SESSION['pwd']) so that the next time the script is run it will display the login form. Since the variables were registered earlier in the script before checking their validity, the script doesn't need to check if they're registered before attempting to unregister them.
if (mysql_num_rows($result) == 0) {
unset($_SESSION['uid']);
unset($_SESSION['pwd']);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> Access Denied </title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1" />
</head>
<body>
<h1> Access Denied </h1>
<p>Your user ID or password is incorrect, or you are not a
registered user on this site. To try logging in again, click
<a href="<?=$_SERVER['PHP_SELF']?>">here</a>. To register for instant
access, click <a href="signup.php">here</a>.</p>
</body>
</html>
<?php
exit;
}
Now that the login details have been stored as session variables and checked for validity, the script can safely grant access to the requested page. The last thing I do before ending accesscontrol.php and handing control back to the protected page is to grab the user's full name, which is available from the MySQL result set generated earlier on. This doesn't need to be registered as a session variable, since it will be retrieved again by each protected page using the 'uid' and 'pwd' values stored in the session.
$username = mysql_result($result,0,'fullname');
?>
That completes accesscontrol.php, and with it the access control system! To reiterate, any page can now be restricted to members-only access simply by including accesscontrol.php at the top of the script. Here's a very simple example that makes use of the $username variable to display the user's name:
<?php include 'accesscontrol.php'; ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> Members-Only Page </title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1" />
</head>
<body>
<p>Welcome, <?=$username?>! You have entered a members-only area
of the site. Don't you feel special?</p>
</body>
</html>