Main Page Content
Creating A Login Script With Php 4 Part Ii
There was a fair bit of interest in my previous article which showed you how to create a crude login script included in each document. This article is an update offering better coding, a user database, sign-up script, login/logout scripts and a little script we will use to check a user's login status. Let's get started.
Notes
There are a few things you should know before you attempt to use this script. The next release of PHP will have register_globals set to Off by default. You're encouraged to write your scripts with this in mind, in this article we won't be using normal variables, we will be using $_POST
, $_GET
... etc.
We will also be using sessions with PHP, if you don't understand sessions, or don't know what they are it would be a good idea to read the page so you can understand the coding, and edit it to your needs.
I will be using the PEAR::DB classes to access the database, so you can easily make the scripts work with whatever database you are using. If you are unfamiliar with PEAR::DB read this great article: Abstract PHP's database code with PEAR::DB.
With this in mind, I recommend using a .htaccess
file (if you use apache) to set some PHP values, use the following, if relevant.
php_value register_globals Offphp_value track_vars Onphp_value arg_separator.output "&"php_value arg_separator.input "&"
Planning
We want a system that will allow a user to 'login', preserve that user's login data across multiple requests, allow them access to certain areas only when they are logged in, and allow them to be able to logout. So let's think logically, what do we need?
- User database, containing their password, username, and some personal information to create a community feel.
- Allow them to 'sign up' if they aren't a member.
- A method of checking whether or not the user is 'logged in.'
- Allow them to 'log in' if they're not.
- Allow them to 'log out' when they are done.
Now we need to turn that logic into code, so let us continue....
User database
We need a place to store user information. We need to be able to extract this data to authenticate them and insert new data for new members. This article will use an SQL database for this. We need to design the user database, but first of all we need to connect to the database.
Connecting
We are using the PEAR::DB classes for more portable database coding, rather than using database-specific functions.
<?phprequire_once 'DB.php'; //require the PEAR::DB classes.$db_engine = 'mysql';
$db_user = 'jester';$db_pass = 'password';$db_host = 'localhost';$db_name = 'database';$datasource = $db_engine.'://'.$db_user.':'.$db_pass.'@'.$db_host.'/'.$db_name;
$db_object = DB::connect($datasource, TRUE);
/* assign database object in $db_object, if the connection fails $db_object will containthe error message. */if(DB::isError($db_object)) {
die($db_object->getMessage()); // If $db_object contains an error print out the} // error and exit.$db_object->setFetchMode(DB_FETCHMODE_ASSOC);
include('check_login.php'); // we write this later on, ignore for now.
?>
There we have it, that script will create a connection object which we can use in other scripts to do stuff with the database. This script should be put outside your document tree, or in a protected directory to prevent people accessing it directly. There are various things you need to customise.
- $db_engine - Your database engine, a list of possible values is below.
- $db_user - Your username to access the database.
- $db_pass - Your password.
- $db_host - The host of the database server.
- $db_name - The name of the database to connect to.
A list of possible database engine values are:
mysql -> MySQL
ibase -> InterBase
msql -> Mini SQL
mssql -> Microsoft SQL Server
oci8 -> Oracle 7/8/8i
odbc -> ODBC (Open Database Connectivity)
sybase -> SyBase
ifx -> Informix
fbsql -> FrontBase
So now we have our connection to the database, save this file as db_connect.php
. Next we need to design the database, I am providing a script that will create this table for you.
Our Table
<?phprequire('db_connect.php'); // require above script, change the path to match wherever you put it.$table = "CREATE TABLE users (
id int(10) DEFAULT '0' NOT NULL auto_increment, username varchar(40),password varchar(50), regdate varchar(20),email varchar(100),website varchar(150),location varchar(150),show_email int(2) DEFAULT '0',last_login varchar(20),PRIMARY KEY(id))";$create = $db_object->query($table); // perform query
if(DB::isError($create)) {
die($create->getMessage()); // check is query was successful} // if not error and exit.else{ echo 'Table created successfully.';}$db_object->disconnect();?>
That script will create a table in the database you specified, once you have executed this script you can take it out of your document tree so others cannot run it. We will use this table to store user information, retrieve it and check it. Now we need to allow users to become members.
Allow Them To 'Sign Up'
A user database is no good unless we have users in it, so we need to allow users to add themselves, we use a simple form to allow them to pick a username, password, enter their e-mail address and any other information they choose, and then insert this data into the database.
<?phprequire('db_connect.php'); // database connect script.?>
<html><head><title>Register an Account</title></head><body><?phpif(isset($_POST['submit'])) { // if form has been submitted /* check they filled in what they supposed to, passwords matched, username isn't already taken, etc. */ if(!$_POST['uname'] !$_POST['passwd'] !$_POST['passwd_again'] !$_POST['email']) { die('You didn't fill in a required field.'); } // check if username exists in database. if(!get_magic_quotes_gpc()) { $_POST['uname'] = addslashes($_POST['uname']); } $name_check = $db_object->query("SELECT username FROM users WHERE username = '".$_POST['uname']."'"); if(DB::isError($name_check)) { die($name_check->getMessage()); } $name_checkk = $name_check->numRows();if($name_checkk != 0) {
die('Sorry, the username: '.$_POST['uname'].' is already taken, please pick another one.'); } // check passwords match if($_POST['passwd'] != $_POST['passwd_again']) { die('Sorry your password and confirmation password did not match, please try again.'); } // check e-mail format if(!preg_match("/.*\@.*\..*/", $_POST['email']) preg_match("/(\< \>)/", $_POST['email'])) { die('Sorry the e-mail address you submitted was of invalid format.'); } // no HTML tags in username, website, location, password if(preg_match("/(\< \>)/", $_POST['uname']) preg_match("/(\< \>)/", $_POST['passwd']) preg_match("/(\< \>)/", $_POST['website']) preg_match("/(\< \>)/", $_POST['location'])) { die('Invalid input, no HTML tags are allowed.'); } // check show_email data if($_POST['show_email'] != 0 & $_POST['show_email'] != 1) { die('Nope.'); } /* the rest of the information is optional, the only thing we need to check is if they submitted a website, and if so, check the format is ok. */ if($_POST['website'] != '' & !preg_match("/^(http ftp):\/\//", $_POST['website'])) { $_POST['website'] = 'http://'.$_POST['website']; } // now we can add them to the database. // encrypt password $_POST['passwd'] = md5($_POST['passwd']); if(!get_magic_quotes_gpc()) { $_POST['passwd'] = addslashes($_POST['passwd']); $_POST['email'] = addslashes($_POST['email']); $_POST['website'] = addslashes($_POST['website']); $_POST['location'] = addslashes($_POST['location']); } $regdate = date('m d, Y'); $insert = "INSERT INTO users (username, password, regdate, email, website, location, show_email, last_login) VALUES ('".$_POST['uname']."', '".$_POST['passwd']."', '$regdate', '".$_POST['email']."', '".$_POST['website']."', '".$_POST['location']."', '".$_POST['show_email']."', 'Never')"; $add_member = $db_object->query($insert); if(DB::isError($add_member)) { die($add_member->getMessage()); } $db_object->disconnect();?><h1>Registered</h1><p>Thank you, your information has been added to the database, you may now <a href="login.php" title="Login">log in</a>.</p><?php}else { // if form hasn't been submitted?><h1>Register</h1><form action="<?=$HTTP_SERVER_VARS['PHP_SELF']?>" method="post"><table align="center" border="1" cellspacing="0" cellpadding="3"><tr><td>Username*:</td><td><input type="text" name="uname" maxlength="40"></td></tr><tr><td>Password*:</td><td><input type="password" name="passwd" maxlength="50"></td></tr><tr><td>Confirm Password*:</td><td><input type="password" name="passwd_again" maxlength="50"></td></tr><tr><td>E-Mail*:</td><td><input type="text" name="email" maxlength="100"></td></tr><tr><td>Website:</td><td><input type="text" name="website" maxlength="150"></td></tr><tr><td>Location</td><td><input type="text" name="location" maxlength="150"></td></tr><tr><td>Show E-Mail?</td><td><select name="show_email"><option value="1" selected="selected">Yes</option><option value="0">No</option></select></td></tr><tr><td colspan="2" align="right"><input type="submit" name="submit" value="Sign Up"></td></tr></table></form><?php}?></body></html>
The above script allows the user to register an account, inserting their data into the database, we must perform various checks before we allow this. Checking if the username has been taken, if their passwords matched, and a few security checks. We also encrypt the password in the database for extra security. If all checks are okay we insert the data. Now the user is in the database, we still have to allow them to login, but first we need to write the script that will check if they are logged in or not.
Check if they are logged in
This script will assign a variable, $logged_in
to either 1
(if they are logged in), or 0
if they aren't. We can then use this variable in our scripts. A few points:
- We are going to use
$_SESSION['username']
for our user's username and$_SESSION['password']
for their password. $_SESSION['password']
will be encrypted.- We need to start our session somewhere, here is a good place.
<?php/* check login script, included in db_connect.php. */session_start();
if(!isset($_SESSION['username']) !isset($_SESSION['password'])) {
$logged_in = 0; return;}else {// remember, $_SESSION['password'] will be encrypted.if(!get_magic_quotes_gpc()) {
$_SESSION['username'] = addslashes($_SESSION['username']);}// addslashes to session username before using in a query.$pass = $db_object->query("SELECT password FROM users WHERE username = '".$_SESSION['username']."'");
if(DB::isError($pass)) { $logged_in = 0; unset($_SESSION['username']); unset($_SESSION['password']); // kill incorrect session variables.}$db_pass = $pass->fetchRow();// now we have encrypted pass from DB in $db_pass['password'], stripslashes() just incase:$db_pass['password'] = stripslashes($db_pass['password']);
$_SESSION['password'] = stripslashes($_SESSION['password']);//compare:if($_SESSION['password'] == $db_pass['password']) { // valid password for username
$logged_in = 1; // they have correct info in session variables.}else { $logged_in = 0; unset($_SESSION['username']); unset($_SESSION['password']); // kill incorrect session variables.}}// clean upunset($db_pass['password']);$_SESSION['username'] = stripslashes($_SESSION['username']);?>
What we did here was:
If session variables aren't set, they're not logged in. If they are set, fetch the password row from the database where the username is equal to the session variable username. If password cannot be fetched, the username mustn't exist, kill bad session variables. If the password is fetched, username is correct, compare the encrypted password from the database to the session variable password, if it matches log them in, if not the password is incorrect. Don't set them as logged in and kill bad session variables.
So now we have our database connection, users can register accounts, we are capable of checking whether they are logged in or not. We can use $logged_in
in our scripts now. All that is left is to allow users to log in and log out.
Allow them to 'log in'
Now we need to create the script that will allow the user to submit their username and password, check if they are correct and, if so, register them as session variables. Once we register the session variables the user will be deemed as "logged in", $logged_in
will be true until they 'log out.'
<?phprequire('db_connect.php'); // database connect script.if($logged_in == 1) { die('You are already logged in, '.$_SESSION['username'].'.');}?><html><head><title>Login</title></head><body><?phpif(isset($_POST['submit'])) { // if form has been submitted /* check they filled in what they were supposed to and authenticate */ if(!$_POST['uname'] !$_POST['passwd']) { die('You didn't fill in a required field.'); } // authenticate. if(!get_magic_quotes_gpc()) { $_POST['uname'] = addslashes($_POST['uname']); } $check = $db_object->query("SELECT username, password FROM users WHERE username = '".$_POST['uname']."'"); if(DB::isError($check)) { die('That username doesn't exist in our database.'); } $info = $check->fetchRow(); // check passwords match $_POST['passwd'] = stripslashes($_POST['passwd']); $info['password'] = stripslashes($info['password']); $_POST['passwd'] = md5($_POST['passwd']); if($_POST['passwd'] != $info['password']) { die('Incorrect password, please try again.'); }// if we get here username and password are correct, register session variables and set
// last login time. $date = date('m d, Y'); $update_login = $db_object->query("UPDATE users SET last_login = '$date' WHERE username = '".$_POST['uname']."'"); $_POST['uname'] = stripslashes($_POST['uname']); $_SESSION['username'] = $_POST['uname']; $_SESSION['password'] = $_POST['passwd']; $db_object->disconnect();?><h1>Logged in</h1><p>Welcome back <?=$_SESSION['username']?>, you are logged in.</p><?php}else { // if form hasn't been submitted?><h1>Login</h1><form action="<?=$HTTP_SERVER_VARS['PHP_SELF']?>" method="post"><table align="center" border="1" cellspacing="0" cellpadding="3"><tr><td>Username:</td><td><input type="text" name="uname" maxlength="40"></td></tr><tr><td>Password:</td><td><input type="password" name="passwd" maxlength="50"></td></tr><tr><td colspan="2" align="right"><input type="submit" name="submit" value="Login"></td></tr></table></form><?php}?></body></html>
Now we have our 'log in' script. When the user loads this page they are presented with a form that allows them to submit their username and password. We then check if thatsuers is in the database, if it is we take the password associated with that username and compare it with the user's submitted password, if they match the user submitted the correct information. We can register the username and password (encrypted) as session variables. Now these session variables will be subject to inspection by the check_login.php
script, authenticating the user each time a page is loaded, allowing us to use our $logged_in
variable to check for a correct log in. When the user has done, it's a good idea to allow them to "log out".
Allow them to 'log out'
To log a user out we simply destroy their session variables and their session.
<?phprequire('db_connect.php'); // database connect script.if($logged_in == 0) { die('You are not logged in so you cannot log out.');}unset($_SESSION['username']);
unset($_SESSION['password']); // kill session variables$_SESSION = array(); // reset session arraysession_destroy(); // destroy session.header('Location: index.php'); // redirect them to anywhere you like.?>
That script is very simple, once the session variables are unset the check_login.php
script will set $logged_in
to zero, so they will not be classed as "logged in".
Usage
Now we have the base of a login system, so let's look at a practical usage of these scripts. A page would look like so:
<?phprequire('db_connect.php'); // require our database connection // which also contains the check_login.php // script. We have $logged_in for use.if($logged_in == 0) {
die('Sorry you are not logged in, this area is restricted to registered members. Click here to log in.');}// show content
$db_object->disconnect(); // when you are done.
?>
This makes it very easy to restrict access to a document, only a person whose information has been authenticated by check_login.php
will be able to view the page, the others will be offered a link to 'log in.'
More...
There are various ways we can jazz up this little member system, such as a user online script, a member list, member profiles, instant message system... the list goes on and on. This is the bear minumum, it's up to you to edit it to your needs, if you need any help use the comments system below and someone will answer.
We can use $_SESSION['username']
to interact with the database row associated with the current logged in user, $logged_in
to check for a positive login, we can do just about anything now. We could do this:
<?phprequire('db_connect.php');if($logged_in == 1) {
echo 'Logged in as '.$_SESSION['username'].', logout';}else { echo 'Not logged in. Login';}?>
Showing the user what name they are logged in as and offering a link to logout, while they are logged in, or telling them they aren't logged in and offering them a link to do so, if they're not logged in.
The list really is endless, I cannot really include more, this article is long enough, if you would like to see a how-to on a few things you can do with this, leave a comment below, if there is enough interest I will find the time to write it.
Conclusion
Remember this script isn't ready-to-go, you will need to do some editing. The layout of each page leaves a lot to be desired, jazz them up, you can add more to the user table, create different user levels so members have different access rights depending on their rank -- be creative. Just rememeber to include the db_connect.php
script in any document that is part of the member system.
Here are a few links that may help you get to grips with the features discussed in this article.
These scripts have been tested and worked fine for me, if you have any problems feel free to comment, certain databases may require the system to be edited slightly. This article is somewhat discursive, if anyone is confused by my rambling feel free to drop me an e-mail and I'll be happy to elaborate on the areas in which you are having difficulties.
-Jester (contact)