Protecting Multiple Files with a Session-based Login
If you've got more than one file - such as a script control panel - that you want protecting, my Secure Login Page is more hassle than is needed to get an adequate level of protection. Using a similiar no-database concept though, we can make use of sessions to help protect our files.
Firstly, we need to create our config file. This is where we'll stick our usernames/passwords and a random 'salt' (I've started using things like hashed dates, which obviously change with time giving increased security). To enable us to have multiple logins, we can use an array to hold all the data as neatly as possible:
<?php
$users = array(
"username" => "password",
"another" => "theirpass"
);
$salt = substr(md5(date("F")), 8);
?>
For each new login add a new line in the format: "username" => "password", adding a comma to the previous line as a separator. This creates an array with the username as the key and password as the value. I highly recommend you hash the passwords using an MD5 hashing tool before putting them in the file. For example:
<?php
$users = array(
"username" => "5f4dcc3b5aa765d61d8327deb882cf99",
"another" => "85103ecee5a5e98c2923978385e514a2"
);
// this takes the month, hashes it then cuts it down to 8 characters
$salt = substr(md5(date("F")), 8);
?>
I will continue the tutorial assuming the passwords are hashed.
Once you've set this up, save the file as something like users.php and create a new file called login.php — in this we'll put our login script. This will include the form, the initial session creation and storing of the username/password. For the sake of speed, I've coded the basics of an HTML form already (if you need this explaining to you, this tutorial is probably not for you):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Login Form</title>
</head>
<body>
<form method="post" action="login.php">
Username:<br>
<input type="text" name="username"><br>
Password:<br>
<input type="password" name="password"><br>
<input type="submit" name="submit" value="Login">
</form>
</body>
</html>
We'll use this to gather our login details, and direct the user back to login.php (by which point we'll have put in our magic PHP.) We can start by checking the request method of the page... if it's POST (rather than GET) there's a pretty good chance our potential user has filled out the form, so we can process the details. Validation of the data that we've received is a good start, so we'll check for special characters in the username and hash the contents of the password ready for comparison:
<?php
if ($_SERVER['REQUEST_METHOD'] == "POST") {
if (!ereg("^[A-Za-z0-9]", $_POST['username']))
exit("<p>Invalid characters in the username.</p>");
$username = $_POST['username'];
$password = md5($_POST['password']);
}
?>
At this point we've got our 'clean' username, and hashed password, assigned to relevant variables. Of course, just because the username doesn't contain anything dodgy doesn't mean it's correct. Now we need to call our file with the usernames in (users.php) and check to see if the username and password are a valid combination. We can use array_key_exists() to check for the existance of our username (remember: our usernames are stored as keys) and if it's there, we can check the value of the key (our password) against the submitted password:
require('users.php');
if (array_key_exists($username, $users)) {
// at this point we know the username exists
// let's compare the submitted password to value of the array key (the right password)
if ($password == $users[$username]) {
// password is correct
} else {
exit("<p>Invalid password.</p>");
}
} else {
exit("<p>Invalid username.</p>");
}
At this stage we know whether or not the password is correct, and can start working with our sessions. We need to call session_start(), and create a session variable that we'll be checking later on each time a user tries to access a page. Once this is done we can redirect our user to a page of your choosing (generally one that is going to be protected by the script):
session_start();
$_SESSION['loggedin'] = md5($username.$password.$salt);
header("Location: your-page.php");
exit;
So, all together, our login script is as follows:
<?php
if ($_SERVER['REQUEST_METHOD'] == "POST") {
if (!ereg("^[A-Za-z0-9]", $_POST['username']))
exit("<p>Invalid characters in the username.</p>");
$username = $_POST['username'];
$password = md5($_POST['password']);
require('users.php');
if (array_key_exists($username, $users)) {
// at this point we know the username exists
// let's compare the submitted password to value of the array key (the right password)
if ($password == $users[$username]) {
// password is correct
session_start();
$_SESSION['loggedin'] = md5($username.$password.$salt);
header("Location: your-page.php");
exit;
} else {
exit("<p>Invalid password.</p>");
}
} else {
exit("<p>Invalid username.</p>");
}
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Login Form</title>
</head>
<body>
<form method="post" action="login.php">
Username:<br>
<input type="text" name="username"><br>
Password:<br>
<input type="password" name="password"><br>
<input type="submit" name="submit" value="Login">
</form>
</body>
</html>
At this stage we now have the capacity to log a person in, but nothing protecting our actual files. We need to create another file — check.php — which will contain the important session checking which will need to be included at the top of any page that needs protecting. We'll start by checking that the session variable we created on login exists:
<?php
session_start();
if (!isset($_SESSION['loggedin'])) {
header("Location: login.php");
exit;
} else {
// the session variable exists
}
?>
If the variable exists, we can check that it contains what it should. To refresh your memory: the variable should contain the username, hashed password and 8 character salt from users.php all hashed together. We'll loop through our users array to find a username and password that matches the session variable and chuck them out if it doesn't:
// the session variable exists, let's check it's valid:
require('users.php');
$userexists = false;
foreach($users as $username => $password) {
if (md5($username.$password.$salt) == $_SESSION['loggedin'])
$userexists = true;
}
if ($userexists !== true) {
exit('<p>Invalid session: please <a href="login.php">login</a>.</p>');
}
Put it together:
<?php
session_start();
if (!isset($_SESSION['loggedin'])) {
header("Location: login.php");
exit;
} else {
// the session variable exists, let's check it's valid:
require('users.php');
$userexists = false;
foreach($users as $username => $password) {
if (md5($username.$password.$salt) == $_SESSION['loggedin'])
$userexists = true;
}
if ($userexists !== true) {
exit('<p>Invalid session: please <a href="login.php">login</a>.</p>');
}
}
?>
This can now be included at the top of any file that needs protecting (before any other HTML/PHP content), and it will force any user who's not logged in properly to "exit()". Here's an example page with the check.php file included:
<?php require('check.php'); ?>
<p>If you can see this you're logged in :3</p>
That's it - we're done. Add and remove users as necessary (don't forget to hash those passwords), and protect as many files as you want.
Tags:
php, sessions, login, security,
Last Updated On: 05th September 07 by Jem
Bookmark At: StumbleUpon, Digg

Handy Stuff
Downloads
Friends of 'TT'
Resources