So, our last post on creating login admin and logout seems to be pretty backdated. We decided to come up with a new post under the same topic. So, to start with, let us see what you will be able to do after following this tutorial:
- Create a MySQL database for managing admin users. Use SHA1 encryption method to store the password in database. Also insert data into it.
- Create your own login/logout system in PHP using Cookie and Session along with remember me option. We shall md5 the SHA1 password in cookie for better protection.
- Understand the PHP code behind the scene. How we have stored the encrypted password in the cookie.
- Implementing the whole thing in OOP (Object Oriented Programming).
In this tutorial we will do only the basic stuffs, there will be no CSS/HTML styling. In our next release, we will provide you a package with HTML5 admin, from where you can download and use it directly in your projects. This tutorial is intended to explain the basic mechanism used in Login Systems and how cookies and sessions work to provide the administrator security. We will discuss the file and directory structure, the database structure, we will see how we’ve used MySQL in PHP to connect to database and how we actually authenticate the user for a single session or for multiple session (in case the remember me option is selected). Check out below to get the codes straight away if you know how to do this already and just want to get the code.
As for the so called licensing stuffs, this whole thing is just FREE. You download, fork, modify, redistribute, use in your project, or do whatever you want. Although a credit will be appreciated, but in this open world of internet, it is completely upto you.
So, let us start with the directory structure and understand which file does what.
#0: File and directory structure:
- directory – admin: The root directory of all your admin files. It contains all the classes, login/logout files etc that we need to get the system running.
- admin-class.php – The main library class of the admin. It contains the several library functions that we need for user authentication, password checking etc.
- index.php – The main admin file which should be restricted to the logged in administrator only. If not logged in, then this should redirect to the login page.
- login-action.php – The action file which processes the user submitted username and password and authenticates on success. On failure, it redirects to the login page.
- login.php – The login form where users are asked to enter their username, password etc along with the a nice remember me option.
- logout.php – The logout script which should clear the authentication data and send back the user to the login page.
- directory – db: The root directory for the database connection files. We have used ezSQLto code our application. It gives several query abstractions for faster access.
- db.php – It includes the library files ez_sql_core.php & ez_sql_mysql.php and initializes a global variable $db for all the database connections. We shall look more about this later.
- ez_sql_core.php – The core ez_sql file as downloaded from the link above.
- ez_sql_mysql.php – The MySQL extension for the ezSQL.
#1.1: Creating the database:
We shall start by creating a new database for our application. If you are on linux and have MySQL installed, just open up terminal and hit mysql (you need to access with super user privilege if you have not changed the mysql root, su mysql or sudo mysql) and enter the following sql queries.
CREATE DATABASE login_test; USE login_test; CREATE TABLE `user` ( `id` INT NOT NULL auto_increment, `username` VARCHAR(50) NOT NULL default '', `nicename` VARCHAR(255) NOT NULL default '', `email` VARCHAR(255) NOT NULL default '', `password` VARCHAR(255) NOT NULL default '', UNIQUE KEY `user_n` (`username`), UNIQUE KEY `user_e` (`email`), PRIMARY KEY (`id`) ); INSERT INTO `user` (`username`, `nicename`, `email`, `password`) VALUES ( 'swashata', 'Swashata Ghosh', 'abc@domain.com', SHA1('pass') );
Let us see what it does:
- Creates a database named login_test.
- Use that database.
- Create a table user with id, username, nicename, email and password as fields. Set usename and email as unique keys and id as primary key.
- Insert a user named swashata with nicename Swashata Ghosh, email as above and password as pass.
- Note that we have encrypted the password ‘pass‘ using the SHA1 encryption method provided my MySQL. In this way our password is stored in encrypted form. But that also means, you will never be able to see it in original form again. So, how do you reset it? Simple, by querying the database directly. Just
Now, if you run a SELECT * query, then you will see something like this.
All done, now let us code the PHP backend.
#1.2: Connecting the database with PHP: – db.php
Now, we need to connect this database to our script. To do this, we will be using ezSQL as mentioned before. So, inside our db.php file, we place the following code:
<?php /** * The db.php file which initiates a connection to the database * and gives a global $db variable for access * @author Swashata <swashata@intechgrity.com> * @uses ezSQL MySQL */ /** edit your configuration */ $dbuser = 'db_user'; $dbname = 'db_name'; $dbpassword = 'db_password'; $dbhost = 'localhost'; /** Stop editing from here, else you know what you are doing ;) */ /** defined the root for the db */ if(!defined('ADMIN_DB_DIR')) define('ADMIN_DB_DIR', dirname(__FILE__)); require_once ADMIN_DB_DIR . '/ez_sql_core.php'; require_once ADMIN_DB_DIR . '/ez_sql_mysql.php'; global $db; $db = new ezSQL_mysql($dbuser, $dbpassword, $dbname, $dbhost);
As you can see, it creates a global $db object which connects to the database from the credential above. To use it, we just need to include this file and declare $db as global.
#2: Creating the Login form: – login.php
So, we have used a plain and simple login form with valid xhtml markup. You can add your own css to it to make it look better. The things to notice are
- The name and id of the fields should not change.
- The form method should be post and action should be login-action.php.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Login to admin</title> </head> <body> <form action="login-action.php" method="post"> <fieldset> <legend>Enter Credential</legend> <p> <label for="username">Username: </label> <input type="text" name="username" id="username" value="" /> </p> <p> <label for="password">Password: </label> <input type="password" name="password" id="password" value="" /> </p> <p> <label for="remember"> <input type="checkbox" name="remember" id="remember" value="1" /> Remember me </label> </p> </fieldset> <p> <input type="submit" value="Submit" /> <input type="reset" value="Reset" /> </p> </form> </body> </html>
Simple and effective.
#3: Creating the library classes – admin-class.php
We first need to analyze what features we need for our library. The basic features are (and also the code behind it):
#3.0: Initialize the session for login system:
Login systems work mainly either on session or on cookie. As we are using remember me option, so it is better to use both. Here is how we initialize the session and do some other stuffs.
/** * The constructor function of admin class * We do just the session start * It is necessary to start the session before actually storing any value * to the super global $_SESSION variable */ public function __construct() { session_start(); //store the absolute script directory //note that this is not the admin directory self::$abs_path = dirname(dirname(__FILE__)); //initialize the post variable if($_SERVER['REQUEST_METHOD'] == 'POST') { $this->post = $_POST; if(get_magic_quotes_gpc ()) { //get rid of magic quotes and slashes if present array_walk_recursive($this->post, array($this, 'stripslash_gpc')); } } //initialize the get variable $this->get = $_GET; //decode the url array_walk_recursive($this->get, array($this, 'urldecode')); }
#3.1: Checking the database for valid username and password combination:
/** * Check the database for login user * Get the password for the user * compare md5 hash over sha1 * @param string $username Raw username * @param string $password expected to be md5 over sha1 * @return bool TRUE on success FALSE otherwise */ private function _check_db($username, $password) { global $db; $user_row = $db->get_row("SELECT * FROM `user` WHERE `username`='" . $db->escape($username) . "'"); //general return if(is_object($user_row) && md5($user_row->password) == $password) return true; else return false; }
So, what we do is, we compare the md5 and sha1 encrypted password with the one stored in database. As the database has only sha1 encrypted password, so we calculate the md5 hash by passing it through the function md5. If it matches, then we return true else, false. You might think, from where we get the username and password. Just keep on reading.
#3.2: Add action for the login-action.php file:
/** * Check for login in the action file */ public function _login_action() { //insufficient data provided if(!isset($this->post['username']) || $this->post['username'] == '' || !isset($this->post['password']) || $this->post['password'] == '') { header ("location: login.php"); } //get the username and password $username = $this->post['username']; $password = md5(sha1($this->post['password'])); //check the database for username if($this->_check_db($username, $password)) { //ready to login $_SESSION['admin_login'] = $username; //check to see if remember, ie if cookie if(isset($this->post['remember'])) { //set the cookies for 1 day, ie, 1*24*60*60 secs //change it to something like 30*24*60*60 to remember user for 30 days setcookie('username', $username, time() + 1*24*60*60); setcookie('password', $password, time() + 1*24*60*60); } else { //destroy any previously set cookie setcookie('username', '', time() - 1*24*60*60); setcookie('password', '', time() - 1*24*60*60); } header("location: index.php"); } else { header ("location: login.php"); } die(); }
What it does is, calls the _check_db function with the username and encrypted password as parameters. If true is returned, then it sets the session for the admin with the username as $_SESSION[‘admin_login’] variable. Then it further checks for remember me option, and if yes, then it sets cookie as well. We shall discuss more about cookie in some other post. For now, you can just check the comments. As it says, it stores the username and password in the corresponding variables for 1 day. To fetch the cookie we shall use $_COOKIE super global.
#3.3: Creating the authentication method:
/** * Checks whether the user is authenticated * to access the admin page or not. * * Redirects to the login.php page, if not authenticates * otherwise continues to the page * * @access public * @return void */ public function _authenticate() { //first check whether session is set or not if(!isset($_SESSION['admin_login'])) { //check the cookie if(isset($_COOKIE['username']) && isset($_COOKIE['password'])) { //cookie found, is it really someone from the if($this->_check_db($_COOKIE['username'], $_COOKIE['password'])) { $_SESSION['admin_login'] = $_COOKIE['username']; header("location: index.php"); die(); } else { header("location: login.php"); die(); } } else { header("location: login.php"); die(); } } }
When ever we need to authenticate in a file access, we just have to call this function. We shall see it in the index.php file. It automatically fetches the data from cookie, revalidates it and also redirects to the login.php in case of failure. This is just pretty much what you need.
#3.4: Putting together the class file – admin-class.php
<?php /** Include the database file */ include_once '../db/db.php'; /** * The main class of login * All the necesary system functions are prefixed with _ * examples, _login_action - to be used in the login-action.php file * _authenticate - to be used in every file where admin restriction is to be inherited etc... * @author Swashata <swashata@intechgrity.com> */ class itg_admin { /** * Holds the script directory absolute path * @staticvar */ static $abs_path; /** * Store the sanitized and slash escaped value of post variables * @var array */ var $post = array(); /** * Stores the sanitized and decoded value of get variables * @var array */ var $get = array(); /** * The constructor function of admin class * We do just the session start * It is necessary to start the session before actually storing any value * to the super global $_SESSION variable */ public function __construct() { session_start(); //store the absolute script directory //note that this is not the admin directory self::$abs_path = dirname(dirname(__FILE__)); //initialize the post variable if($_SERVER['REQUEST_METHOD'] == 'POST') { $this->post = $_POST; if(get_magic_quotes_gpc ()) { //get rid of magic quotes and slashes if present array_walk_recursive($this->post, array($this, 'stripslash_gpc')); } } //initialize the get variable $this->get = $_GET; //decode the url array_walk_recursive($this->get, array($this, 'urldecode')); } /** * Sample function to return the nicename of currently logged in admin * @global ezSQL_mysql $db * @return string The nice name of the user */ public function get_nicename() { $username = $_SESSION['admin_login']; global $db; $info = $db->get_row("SELECT `nicename` FROM `user` WHERE `username` = '" . $db->escape($username) . "'"); if(is_object($info)) return $info->nicename; else return ''; } /** * Sample function to return the email of currently logged in admin user * @global ezSQL_mysql $db * @return string The email of the user */ public function get_email() { $username = $_SESSION['admin_login']; global $db; $info = $db->get_row("SELECT `email` FROM `user` WHERE `username` = '" . $db->escape($username) . "'"); if(is_object($info)) return $info->email; else return ''; } /** * Checks whether the user is authenticated * to access the admin page or not. * * Redirects to the login.php page, if not authenticates * otherwise continues to the page * * @access public * @return void */ public function _authenticate() { //first check whether session is set or not if(!isset($_SESSION['admin_login'])) { //check the cookie if(isset($_COOKIE['username']) && isset($_COOKIE['password'])) { //cookie found, is it really someone from the if($this->_check_db($_COOKIE['username'], $_COOKIE['password'])) { $_SESSION['admin_login'] = $_COOKIE['username']; header("location: index.php"); die(); } else { header("location: login.php"); die(); } } else { header("location: login.php"); die(); } } } /** * Check for login in the action file */ public function _login_action() { //insufficient data provided if(!isset($this->post['username']) || $this->post['username'] == '' || !isset($this->post['password']) || $this->post['password'] == '') { header ("location: login.php"); } //get the username and password $username = $this->post['username']; $password = md5(sha1($this->post['password'])); //check the database for username if($this->_check_db($username, $password)) { //ready to login $_SESSION['admin_login'] = $username; //check to see if remember, ie if cookie if(isset($this->post['remember'])) { //set the cookies for 1 day, ie, 1*24*60*60 secs //change it to something like 30*24*60*60 to remember user for 30 days setcookie('username', $username, time() + 1*24*60*60); setcookie('password', $password, time() + 1*24*60*60); } else { //destroy any previously set cookie setcookie('username', '', time() - 1*24*60*60); setcookie('password', '', time() - 1*24*60*60); } header("location: index.php"); } else { header ("location: login.php"); } die(); } /** * Check the database for login user * Get the password for the user * compare md5 hash over sha1 * @param string $username Raw username * @param string $password expected to be md5 over sha1 * @return bool TRUE on success FALSE otherwise */ private function _check_db($username, $password) { global $db; $user_row = $db->get_row("SELECT * FROM `user` WHERE `username`='" . $db->escape($username) . "'"); //general return if(is_object($user_row) && md5($user_row->password) == $password) return true; else return false; } /** * stripslash gpc * Strip the slashes from a string added by the magic quote gpc thingy * @access protected * @param string $value */ private function stripslash_gpc(&$value) { $value = stripslashes($value); } /** * htmlspecialcarfy * Encodes string's special html characters * @access protected * @param string $value */ private function htmlspecialcarfy(&$value) { $value = htmlspecialchars($value); } /** * URL Decode * Decodes a URL Encoded string * @access protected * @param string $value */ protected function urldecode(&$value) { $value = urldecode($value); } }
#4: Creating the login-action.php file:
As we have everything in our class, so creating the login-action.php file will be a breeze. All what we do is
- Include the admin-class.php file.
- Initiate a new instance of the itg_admin class.
- Call the _login_action function.
<?php include_once 'admin-class.php'; $admin = new itg_admin(); $admin->_login_action();
and we are done.
#5: Creating the index.php file – restricted access:
So, it is time to put all the codes to work. In index.php file we simply do what we have done in login-action.php file, except of calling the _login_action, we call _authenticate function. It will automatically check whether user is authenticated to access the further script or not and will redirect to login form if necessary.
<?php include_once 'admin-class.php'; $admin = new itg_admin(); $admin->_authenticate(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Administrator page</title> </head> <body> <fieldset> <legend>Welcome <?php echo $admin->get_nicename(); ?></legend> <p> Here are some of the basic informations </p> <p> Username: <?php echo $_SESSION['admin_login']; ?> </p> <p> Email: <?php echo $admin->get_email(); ?> </p> </fieldset> <p> <input type="button" onclick="javascript:window.location.href='logout.php'" value="logout" /> </p> </body> </html>
and finally…
#6: The logout.php file:
Everything seems to be incomplete without it! What we do is
- Destroy the session.
- Expire the cookie.
- Redirect to login form.
<?php /** * The logout file * destroys the session * expires the cookie * redirects to login.php */ session_start(); session_destroy(); setcookie('username', '', time() - 1*24*60*60); setcookie('password', '', time() - 1*24*60*60); header("location: login.php"); ?>
and we are done. It looks like this
So that was all. Feel free to ask any questions you have. I will try best to answer them.
plz sujjest me what to do…?
hiiiiiiiii
i want to add super user to sample php base website that can view all user and can do any thing with any user i.e can delete e.t.c
can any one help me??????
i want to add admin to my login page which can wive all user is it is possible???
I wanted to compliment you on your blog! know that you have a function that follows you from Sicily.
I wanted to ask this method is good to login as administrator, but if I wanted to use this method to create protected pages for the user that’s fine right?
how to make alert box that “you have already logged in another page ? message
Great Tutorial, Mine is working 100% no issues at all.
hi, how to grab only login data only from database by using session?
eg: select * from table where $_SESSION………
hey, i’m a newbie and i have a project for school, i need to learn this so that i’d be able to work on it, i have 2 types of users, admin and ordinary users. how do i do this?