UrbanPro
true

Learn PHP from the Best Tutors

  • Affordable fees
  • 1-1 or Group class
  • Flexible Timings
  • Verified Tutors

Search in

User Authenication In PHP: Some Advanced echniques

Dheeraj Kushwaha
25/07/2017 0 0

User Authentication in CodeIgniter: Goals

  • Security: We want our login system to be secure, we want to do everything we can to stop people’s accounts being hacked into.
  • Tracking: We’d like to know who’s logged in, when they were last active and what they’ve looked at.
  • Efficiency: We want to include features to ensure the system is efficient and doesn’t slow everything down.

A Bit of Theory:

Before we jump in and start coding, it’s important to discuss some theory on how we can achieve the above goals.

Security:

Firstly, on the security side of things we need to decide how we will determine if a user is logged in. Personally I prefer to do this using a cookie rather than a PHP Session. Reason being you can keep users logged in for longer periods of time with cookies (ie  provide a “remember me” option). However including any user information in the cookie itself is a security risk, because anybody can access the cookies in their browser and find the data stored. This is not just bad on shared computers  if you’re saving someone’s user id for example, what’s stopping someone guessing another user’s user id and setting their own cookie?

We will be using a database table along with a cookie to determine if a user is logged in. The cookie itself will hold just a hashed string of characters that reference a field in the database table. If a session exists the user is logged in, if not we can delete the cookie and get them to log in.

Taking this further, it makes sense to check other things at this stage too. The user’s last login can be saved in the database table for example then if they’ve not been active for a set amount of time we can force log them out. We can also track a user’s IP address, and if the user’s current IP address is different log them out. It could be perfectly innocent as a lot of users will not have a static IP address, but for the sake of security getting them to log in again when it does change isn’t a big loss.

Tracking:

This database table leads nicely into the tracking we want to do. Every time a user visits a page on your application, we will perform the above checks to ensure a valid session exists. At the same time we can update their last active date. You could  if you wanted to go further have another database table that logs pages viewed or actions taken. Doing so would give you a lot of data to run statistics on, providing useful metrics for future development or marketing purposes.

Efficiency:

With this kind of tracking however, we need to be careful with performance. It doesn’t take an expert to realise that if you’re inserting a new row in a table every time a user visits a page your table is going to grow very big very fast. Some tweaks and carefully inserting only when you need to can help here, along with regularly clearing data you don’t need any more.

So that’s the theory out of the way, time to start coding!

Database Tables:

As you will have gathered by now, everything revolves around a database table for user sessions. Here’s an example table definition for user_sessions:

PHP
CREATE TABLE `user_sessions` (  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,  `hash` char(40) NOT NULL DEFAULT '',  `users_id` int(11) NOT NULL,  `created_date` datetime NOT NULL,  `last_active` datetime NOT NULL,  `inactive` tinyint(1) NOT NULL DEFAULT '0',  `ip` varchar(45) NOT NULL DEFAULT '',  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

As you can see the table references the users table with users_id. The hash field will hold a 40 character SHA1 hash which is saved in the user’s cookie. We save the date the user first logged in with this session in created_date and the last_active date holds when the user was last active in the system. The inactive field is set to 1 when a user is logged out so we know it’s an old session. Finally the ip field will hold the user’s IP address.

If we wanted to track pages a session visits here’s an example table definition for sessions_track:

PHP
CREATE TABLE `sessions_track` (  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,  `sessions_id` int(11) NOT NULL,  `uri` varchar(255) NOT NULL DEFAULT '',  `last_visited` datetime NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

In this table we reference the sessions table with sessions_id. The URI of the page visited and the last_visited date. We don’t really need to capture any more than this, and the smaller this table is the better!

Finally, here’s an example users table:

PHP
CREATE TABLE `users` (  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,  `name` varchar(55) NOT NULL DEFAULT '',  `email` varchar(100) NOT NULL DEFAULT '',  `password` char(40) NOT NULL DEFAULT '',  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

I’ve kept this to the bare minimum, your system might require all manner of user information, but for the purposes of this article just the user’s name, email and a password are only really required.

MD5 vs SHA1:

You’ll notice the user’s password and the hash in the tables above are 40 character SHA1 hashes rather than 32 character MD5 hashes. Put simply, SHA1 is more secure than MD5. The actual reasons why are outside the scope of this article, but with it being just as easy to hash a string using SHA1 in PHP as it is MD5, there’s no reason not to use SHA1.

PHP
sha1($password);

User Sessions Model:

To achieve our goals we’ll be creating a Model. The Model will hold all the functions our application will need. To start with, let’s create the skeleton of the class first:

PHP
class User_sessions_model extends CI_Model {        }

Login Function:

PHP
public function login($username, $password) {	// Is there a valid user?	$this->db->select('id');	$this->db->where('email', $username);	$this->db->where('password', sha1($password));	$query	= $this->db->get('users');    $user   = $query->row_array();	if ( $user['id'] ) {		// Is there an open session for this user?		$this->db->select('id');		$this->db->where('users_id', $user['id']);		$this->db->where('inactive !=', 1);		$query		= $this->db->get('user_sessions');	    $session   	= $query->row_array();		if ( $session['id'] ) {			// Close the session			$this->destroy_session($session['id']);		}		// Create the new session		$newsession['users_id']	= $user['id'];		$newsession['ip']		= $_SERVER['REMOTE_ADDR'];		$this->create_session($newsession);		return true;	} else {		return false;	}}

The first part of this function is pretty standard stuff. We check to see if a user exists with the email and password passed.

If they do we check the sessions table for an active session. If there is an active session for the user we call destroy_session to close it down – we’re about to make a new one and we don’t want more than 1 active session open at once.

Then, we call create_session which creates a new session for us, and sets the relevant cookies.

Create Session Function:

PHP
public function create_session($data) {	// Set additional data	$data['created_date']	= date('Y-m-d H:i:s');	$data['last_active']	= date('Y-m-d H:i:s');	$data['inactive']		= 0;	$data['hash']			= sha1($data['users_id'].time());	// Perform the insert	$this->db->insert('user_sessions', $data);	// Create cookie	set_cookie('user_login', $data['hash'], 0, 'your-domain');}

This function creates a new session. All of the required data should be passed in the $data parameter as an array. Note the keys in the array match the database field name so we can use CodeIgniter’s build in database class to perform the insert for us. Then we create the user’s cookie.

This is also where we create the hash. You can do this a number of ways, but it’s a good idea to combine a number of pieces of information unique to the member with a random string or the current time. It’s also a good idea to use a different combination of values on each application you build.

Session Check Function:

PHP
public function session_check($hash) {	// Is there a session for this hash?	$this->db->where('hash', $hash);	$this->db->where('inactive !=', 1);	$query		= $this->db->get('user_sessions');    $session   	= $query->row_array();	if ( $session['id'] ) {		// Check the session isn't more than 30 days old and the ips match		if( ( strtotime($session['last_active']) < strtotime('-30 days') ) || $session['ip'] != $_SERVER['REMOTE_ADDR'] ) {			$this->destroy_session($session['id']);			return false;		} else {			// Update the last active date to now			$this->db->set('last_active', date('Y-m-d H:i:s'));			$this->db->where('id', $session['id']);			$this->db->update('user_sessions');			// Track the URI			$trackdata['sessions_id']	= $session['id'];			$trackdata['uri']			= $this->uri->uri_string();			$this->track_uri($trackdata);			// Return the session			return $session;		}	} else {		return false;	}}

This function is used when a user visits a page. The hash stored in their cookie is passed in the $hash parameter, and we check to see if there’s a session that isn’t inactive in the database. If there is an active session, we perform a check to see if their session is too old, and a check to ensure the user’s current IP address matches the one in the session. If any of the checks fail we return false and call destroy_session.

Otherwise, we update the last active date and we call track_uri to track the URI the user has visited. Finally we return the session itself.

Destroy Session Function:

PHP
public function destroy_session($session_id) {	// Mark as inactive in database	$this->db->set('inactive', 1);	$this->db->where('id', $session['id']);	$this->db->update('user_sessions');	// Destroy the cookie	delete_cookie('user_login', 'your-domain');}

Here we mark a session as inactive and destroy the user’s cookie.

Track URI Function:

PHP
public function track_uri($data) {	// Set additional data	$data['last_visited']	= date('Y-m-d H:i:s');	// Perform the insert	$this->db->insert('sessions_track', $data);}

This function inserts the current session, URI and date into the sessions_track table.

Usage Examples:

In the above user sessions model there are a number of functions that provide us with our secure user logins system – but how do we use them? Here are a few examples:

Handling a login form:

PHP
public function login($username, $password) {	// Is a user already logged in?	$users_data = $this->users_model->session_check($this->input->cookie('user_login'));	if ( $users_data['id'] ) {		redirect('members');	}	// Login form submission	if ( $this->input->post('frm_submit') ) {		$users_id = $this->users_model->login($this->input->post('email'), $this->input->post('password'));		if ( $users_id ) {			redirect('dashboard');		} else {			$data['error_message'] = 'Login failed, please check your username and password are correct and try again';		}	}	// Load view	$this->load->view('login', $data);}

Notice how the login form also checks for a logged in user. If there is one it redirects to the members section – we don’t want them to log in twice!

Checking if a user is logged in

PHP
public function members_only_page() {	// Is a user already logged in?	$users_data = $this->users_model->session_check($this->input->cookie('user_login'));	if ( !$users_data['id'] ) {		redirect('login');	}	// User is logged in and valid - continue with members only content	// Load view	$this->load->view('members_only_page', $data);}

Typically, this will be done on every controller function. The if statement checking if a user is logged in and redirecting if not can be removed for pages that aren’t member’s only – this way you can display a login link if a user is not logged in for example.

Handling logging out:

PHP
public function logout() {	// Is a user already logged in?	$users_data = $this->users_model->session_check($this->input->cookie('user_login');	if ( $users_data['id'] ) {		$this->users_model->destroy_session($users_data['id']);	}	redirect('login');}

Auto load the model:

PHP
// config/autoload.php$autoload['model'] = array('User_sessions_model');

For most systems, this functionality will be applicable to every page. Therefore it makes sense to autoload the model in order to have access to it at all times.

Performance Tweaks:

Smart inserting into sessions_track:

In our tracking function we could be a bit smarter with the data we insert. Firstly we could check to see if the same track request has happened within the last few seconds. This simple throttling will stop multiple requests erroneously filling the table up. Secondly, tracking the time of every request to a URI might be a bit overkill, so we can check to see if the session has already tracked the URI, and if it has just increment the visits field. Of course, this does require the addition of a visits field in the database table too.

Cleaning up data we don&rsq

0 Dislike
Follow 0

Please Enter a comment

Submit

Other Lessons for You

How to Create A Master Page Template In PHP?
A master page template is essential to give a consistent look and feel to any website having multiple pages. It is quite easy to create a master page template in PHP using Dreamweaver. Let’s have...

How to Create A Master Page Template In PHP?
A master page template is essential to give a consistent look and feel to any website having multiple pages. It is quite easy to create a master page template in PHP using Dreamweaver. Let’s have...

What is Array in PHP | Types of Array
An array is a special variable, which can hold more than one value at a time or you can say An array stores multiple values in one single variable. If you have a list of items (a list of car names, for...

What Is PHP?
PHP stands for PHP: Hypertext Preprocessor PHP is a widely-used, open source scripting language PHP scripts are executed on the server PHP is free to download and use PHP files can contain text,...

What is Type Juggle in PHP ?
Type Juggling means dealing with a variable type. PHP does not require explicit type definition in variable declaration. A variable's type is determined by the context in which the variable is used. Example,...

Looking for PHP Classes?

Learn from Best Tutors on UrbanPro.

Are you a Tutor or Training Institute?

Join UrbanPro Today to find students near you
X

Looking for PHP Classes?

The best tutors for PHP Classes are on UrbanPro

  • Select the best Tutor
  • Book & Attend a Free Demo
  • Pay and start Learning

Learn PHP with the Best Tutors

The best Tutors for PHP Classes are on UrbanPro

This website uses cookies

We use cookies to improve user experience. Choose what cookies you allow us to use. You can read more about our Cookie Policy in our Privacy Policy

Accept All
Decline All

UrbanPro.com is India's largest network of most trusted tutors and institutes. Over 55 lakh students rely on UrbanPro.com, to fulfill their learning requirements across 1,000+ categories. Using UrbanPro.com, parents, and students can compare multiple Tutors and Institutes and choose the one that best suits their requirements. More than 7.5 lakh verified Tutors and Institutes are helping millions of students every day and growing their tutoring business on UrbanPro.com. Whether you are looking for a tutor to learn mathematics, a German language trainer to brush up your German language skills or an institute to upgrade your IT skills, we have got the best selection of Tutors and Training Institutes for you. Read more