Hello All,
I want to make a CD/DVD Library where by an admin can do all the operations while any other norma user can do limited operations (simply browsing and searching). I'm still organizing and doing simple design and I need your opinions on this:
1. What is the best login technique (after storing users and passwords in database?). I can get usernames from database as well as from login forms but I'm not sure how to implement comparison the best way!

2. What is the best way of storing password? (secure way)

3. How do I redirect them to the right page after successful login

4. How do I prevent any unlogged user from accessing the Library script

Any answer to any question is appreciated

Recommended Answers

All 15 Replies

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:<br /><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" /><br />
            Password: <input type="password" name="password" /><br />
            <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:<br /><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" /><br />
            Password: <input type="password" name="password" /><br />
            <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;

?>
commented: Thanks very much for this post, it was very helpful! +1

above code looks nice. try it

Thanks alot KKeith29,
I failed to add to you some reputation points. I wonder why. That option isn't there in your username
Bravo!

does the above code prevents multiple login

No. It can though. It wouldn't be hard to add.

what lines and tables need to be added to prevent multiple logins

lets take this code to the next level

I tried to use the above code for an example and i came across a Deprecated on Call-time pass-by-reference for these following code:

array_map( 'stripslashes',&$_POST ); //Strips slashes
    array_map( 'mysql_real_escape_string',&$_POST ); //Escapes data to protect against sql injection

.

can anyone assist me on this? thanks

Use:

$_POST = array_map( 'mysql_real_escape_string',array_map( 'stripslashes',$_POST ) );

I tried to use the above code for an example and i came across a Deprecated on Call-time pass-by-reference for these following code:

array_map( 'stripslashes',&$_POST ); //Strips slashes
    array_map( 'mysql_real_escape_string',&$_POST ); //Escapes data to protect against sql injection

.

can anyone assist me on this? thanks

Use

array_map('stripslashes,$_POST); 
array_map('mysql_real_escape_string',$_POST);

Here is a quote from php.net .

There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);.

I tried to use the above code for an example and i came across a Deprecated on Call-time pass-by-reference for these following code:

array_map( 'stripslashes',&$_POST ); //Strips slashes
    array_map( 'mysql_real_escape_string',&$_POST ); //Escapes data to protect against sql injection

.

put below code.....

array_map( 'stripslashes',$_POST ); //Strips slashes
    array_map( 'mysql_real_escape_string',$_POST ); //Escapes data to protect against sql injection

I tried to use the above code for an example and i came across a Deprecated on Call-time pass-by-reference for these following code:

array_map( 'stripslashes',&$_POST ); //Strips slashes
    array_map( 'mysql_real_escape_string',&$_POST ); //Escapes data to protect against sql injection

.

can anyone assist me on this? thanks

It is good warning -- That you use later version that Keith's
This works without warning

array_map( 'stripslashes',$_POST ); //Strips slashes
    array_map( 'mysql_real_escape_string',$_POST ); //Escapes data to protect against sql injection

.

Thread is dead old and marked solved!
Start new thread!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.