Skip to page content or Skip to Accesskey List.

Work

Main Page Content

Creating A Login Script With Php 4 Part Ii

Rated 4.38 (Ratings: 17)

Want more?

  • More articles in Code
 

Jester uk

Member info

User since: 22 Dec 2001

Articles written: 6

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 Off

php_value track_vars On

php_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.

<?php

require_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 contain

the 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

pgsql -> PostgreSQL

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

<?php

require('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.

<?php

require('db_connect.php'); // database connect script.

?>

<html>

<head>

<title>Register an Account</title>

</head>

<body>

<?php

if(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 up

unset($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.'

<?php

require('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>

<?php

if(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.

<?php

require('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 array

session_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:

<?php

require('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:

<?php

require('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)

I just like messing around with web design stuff, just a hobby.

Particularly perl, PHP and SQL.

http://www.free2code.net/

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.org Evolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.