Here is something I typed up a while ago. Its a complete login and registration system. Just create the following pages and create the database and tables. After that it should work.
This system is safe from sql injection, spam bots, and cross-site request forgery. It doesn't have any xss holes.
PHP/MYSQL USER REGISTRATION AND LOGIN EXAMPLE
Database table
-------------------------------------------------------------
Todo - Create this table in your database
CREATE TABLE `login` (
`id` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR( 30 ) NOT NULL ,
`password` VARCHAR( 100 ) NOT NULL ,
PRIMARY KEY ( `id` ) ,
UNIQUE ( `username` )
) ENGINE = MYISAM
Database connection page - includes/dbconnect.php
-------------------------------------------------------------
Description - Holds database connection. This is used to get rid of redundant code in each page. It also helps if you change your username/password/database name you won't have to update every page, just one.
Todo - Fill the variables with the proper information
<?php
$host = 'localhost';
$user = '';
$pass = '';
$dbname = '';
$con = mysql_connect( $host,$user,$pass ) or die('Unable to connect');
mysql_select_db( $dbname ) or die('Unable to select database');
?>
Functions page - includes/functions.php
-------------------------------------------------------------
Description - Holds the functions. Used so you don't have to repeat the functions in each page. Also, if you need to update a function, you only will have to do it once.
<?php
function encryptPassword( $pass,$salt=false,$saltLength=4 ) {
if ( $salt === false ) {
$res = '';
for( $i=0;$i<$saltLength;$i++ ) {
$res .= pack( 's',mt_rand() );
}
$salt = substr( base64_encode( $res ),0,$saltLength );
}
return $salt . sha1( $salt . $pass );
}
function checkPassword( $pass,$hash,$saltLength=4 ) {
if ( encryptPassword( $pass,substr( $hash,0,$saltLength ) ) === $hash ) {
return true;
}
return false;
}
?>
Registration page - register.php
-------------------------------------------------------------
Description - Gets username and password from user, validates them, and inserts into database
<?php
session_start();
require('includes/functions.php'); //include functions
require('includes/dbconnect.php'); //include db connection
$min_form_time = 5; //in seconds
$max_form_time = 30; //in seconds
$error = array(); //define $error to prevent error later in script
$message = '';
if ( isset( $_POST['submit'] ) ) {
$error = array();
array_map( 'stripslashes',&$_POST ); //Strips slashes
array_map( 'mysql_real_escape_string',&$_POST ); //Escapes data to protect against sql injection
$user = $_POST['username'];
$pass = $_POST['password'];
$token = $_POST['token'];
if ( $token !== $_SESSION['token'] ) {
$error[] = 'Token is invalid';
}
else {
if ( time() <= ( $_SESSION['time'] + $min_form_time ) ) {
$error[] = 'Form submitted too quickly, please slow down and try again';
}
elseif ( time() >= ( $_SESSION['time'] + $max_form_time ) ) {
$error[] = 'Form has expired';
}
else {
if ( empty( $user ) ) { //check if username is blank
$error[] = 'Username is blank';
}
elseif ( strlen( $user ) > 30 ) { //make sure the username is not longer than 30 chars
$error[] = 'Username is longer than 30 characters';
}
else { //if there aren't any errors with $user at this point, check to make sure no one else has the same username
$query = mysql_query( "SELECT * FROM `login` WHERE `username` = '{$user}'",$con );
if ( mysql_num_rows( $query ) > 0 ) {
$error[] = 'Username already exists';
}
}
if ( empty( $pass ) ) { //check if password is blank
$error[] = 'Password is blank';
}
elseif ( strlen( $pass ) < 9 ) { //make sure password is longer than 8 characters
$error[] = 'Password must be longer than 8 characters';
}
elseif ( !preg_match( "/^.*(?=.{3,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/",$pass ) ) { //check to see if its a valid password
$error[] = 'Password invalid - it must contain at least 1 number, 1 uppercase letter, 1 lowercase letter';
}
if ( count( $error ) == 0 ) { //if there are no errors, then insert into database
$pass = encryptPassword( $pass ); //hash password before inserting into database
$query = mysql_query( "INSERT INTO `login` (`username`,`password`) VALUES ('{$user}','{$pass}')",$con );
$message = 'User registration successful!';
}
}
}
}
$errmsg = '';
if ( count( $error ) > 0 ) { //if there are errors, build the error list to be displayed.
$errmsg = '<div>Errors:<ul>';
foreach( $error as $err ) { //loop through errors and put then in the list
$errmsg .= "<li>{$err}</li>";
}
$errmsg .= '</ul></div>';
}
$token = md5(uniqid(rand(),true));
$_SESSION['token'] = $token;
$_SESSION['time'] = time();
$html =<<<HTML
<html>
<head>
<title>Registration</title>
</head>
<body>
<h3>Member Registration</h3>
{$errmsg}
<div>
<form action="{$_SERVER['PHP_SELF']}" method="post">
Username: <input type="text" name="username" />
Password: <input type="password" name="password" />
<input type="hidden" name="token" value="{$token}" />
<input type="submit" name="submit" value="Register" />
</form>
</div>
<div style="color:#ff0000">{$message}</div>
</body>
</html>
HTML;
echo $html;
?>
Login page - login.php
-------------------------------------------------------------
Description - Gets username and password from user, validates them, and check to see if user is present in database and sets a session.
<?php
session_start(); //start session so we can login
require('includes/functions.php'); //include functions
require('includes/dbconnect.php'); //include database connection
$min_form_time = 5; //in seconds
$max_form_time = 30; //in seconds
$error = array(); //define $error to prevent error later in script.
if ( isset( $_POST['submit'] ) ) {
$error = array();
array_map( 'stripslashes',&$_POST ); //Strips slashes
array_map( 'mysql_real_escape_string',&$_POST ); //Escapes data to protect against sql injection
$user = $_POST['username'];
$pass = $_POST['password'];
$token = $_POST['token'];
if ( $token !== $_SESSION['token'] ) {
$error[] = 'Token is invalid';
}
else {
if ( time() <= ( $_SESSION['time'] + $min_form_time ) ) {
$error[] = 'Form submitted too quickly, please slow down and try again';
}
elseif ( time() >= ( $_SESSION['time'] + $max_form_time ) ) {
$error[] = 'Form has expired';
}
else {
if ( empty( $user ) ) { //check if username is blank
$error[] = 'Username is blank';
}
elseif ( strlen( $user ) > 30 ) { //make sure the username is not longer than 30 chars
$error[] = 'Username is longer than 30 characters';
}
if ( empty( $pass ) ) { //check if password is blank
$error[] = 'Password is blank';
}
elseif ( strlen( $pass ) < 9 ) { //make sure password is longer than 8 characters
$error[] = 'Password must be longer than 8 characters';
}
elseif ( !preg_match( "/^.*(?=.{3,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/",$pass ) ) { //check to see if its a valid password
$error[] = 'Password invalid - it must contain at least 1 number, 1 uppercase letter, 1 lowercase letter';
}
if ( count( $error ) == 0 ) { //if everything is ok so far, keep going (i do this because i don't want to hit the database if the username or password is blank)
$query = mysql_query( "SELECT `id`,`password` FROM `login` WHERE `username` = '{$user}' LIMIT 1",$con );
if ( mysql_num_rows( $query ) !== 1 ) { //checks to see if a row was found with username provided by user
$error[] = 'Username and/or Password incorrect'; //never be specific with errors, makes it hard to crack
}
else {
list( $id,$hash ) = mysql_fetch_row( $query ); //puts the id and password from result into $id and $pass variables
if ( !checkPassword( $pass,$hash ) ) { //check password from user against the hash in the database.
$error[] = 'Username and/or Password incorrect';
}
if ( count( $error ) == 0 ) { //if now errors found, then set session for login
$_SESSION['auth'] = $id;
header('Location: member.php'); //redirect to <strong class="highlight">secure</strong> area
exit; //exit script since we are redirecting anyway
}
}
}
}
}
}
$errmsg = '';
if ( count( $error ) > 0 ) { //if there are errors, build the error list to be displayed.
$errmsg = '<div>Errors:<ul>';
foreach( $error as $err ) { //loop through errors and put then in the list
$errmsg .= "<li>{$err}</li>";
}
$errmsg .= '</ul></div>';
}
$token = md5(uniqid(rand(),true));
$_SESSION['token'] = $token;
$_SESSION['time'] = time();
$html =<<<HTML
<html>
<head>
<title>Login</title>
</head>
<body>
<h3>Member Login</h3>
{$errmsg}
<div>
<form action="{$_SERVER['PHP_SELF']}" method="post">
Username: <input type="text" name="username" />
Password: <input type="password" name="password" />
<input type="hidden" name="token" value="{$token}" />
<input type="submit" name="submit" value="Login" />
</form>
</div>
</body>
</html>
HTML;
echo $html;
?>
Member area - member.php
-------------------------------------------------------------
Description - place where people who are successfully logged in go. Information on this page is only for members to access, no one else can see it.
<?php
session_start(); //start session so we can see if the user is logged in.
if ( !isset( $_SESSION['auth'] ) ) { // if auth is not in the $_SESSION array (meaning they haven't been to the login page where its set) redirect them to the login page
header('Location: login.php');
exit;
}
require('includes/dbconnect.php'); //include database connection
$memid = $_SESSION['auth']; //set member id into $memid.
$query = mysql_query( "SELECT `username` FROM `login` WHERE `id` = {$memid}" ); //
$member = mysql_fetch_assoc( $query );
echo "Welcome, {$member['username']} <a href=\"logout.php\">Logout</a>";
?>
Logout page - logout.php
-------------------------------------------------------------
Description - logs out member and redirects to login page
<?php
session_start(); //start session so we can logout
unset( $_SESSION['auth'] ); //remove auth from the $_SESSION array
header('Location: login.php');
exit;
?>