Tutorial

Session Management Using PHP : Cookie-based Sessions




What's in a session?

A session means the duration spent by a Web user from the time logged in to the time logged out-during this time the user can view protected content. Protected content means the information that is not open to everyone. The beauty of a session is that it keeps the login credentials of users until they log out, even if they move from one Web page to another, in the same Web service, of course.


From the point of view of a server-side programmer, the server verifies the user name and password obtained from the client and permits the client to create a session if the data is valid. On successful verification of login credentials, a session ID is created for the user, which should either be stored on the server or the client. Once the login information is stored, all subsequent pages identify the user and provide the requested information.


Few methods of session management?

  1. Cookie Based Session
  2. Database Driven Session

Advantages of Cookie Based Session

Cookie-based strategy is simple.


Disadvantages of Cookie Based Session

  1. People might peep into the client machine, find the cookie and misuse the name-value pair to cheat the server, disguising themselves as authentic users.
  2. The second pitfall in cookie-based sessions is that a conservative user may block all incoming cookies. When the server sends a session cookie, it assumes that the client would store it. But, the client might reject the cookie for security reasons and thus hamper the formation of a session.

Implementation : Table Schema

  1. I have taken the schema of the general User table that one would require.
  2. Creating object of this class creates connection.

CREATE TABLE `users` (
  `uid` bigint(20) NOT NULL AUTO_INCREMENT,
  `password` varchar(50) DEFAULT NULL,
  `email` varchar(70) DEFAULT NULL,
  PRIMARY KEY (`uid`),
  UNIQUE KEY `email` (`email`)
);
insert  into `users`(`uid`,`password`,`email`) values (17,'827ccb0eea8a706c4c34a16891f84e7b','pavanratnakar@gmail.com');

Implementation : Db Class

Table 1: Datebase Connection Functions
Function Purpose
mysql_pconnect() establishes a persistent connection. You only need to call it once for the session. That's the beauty of it. It will hold open a connection to the db that you can use over and over again simply by calling the resource ID whenever you need to interact with the db.
mysql_connect() establishes a connection for the duration of the script that access the db. Once the script has finished executing it closes the connection. The only time you need to close the connection manually is if you jump out of the script for any reason.

  1. The constructor establishes connection with database server using mysql_connect function.
  2. Creating object of this class creates connection.

<?php
define("DB_SERVER","localhost");
define("DB_USERNAME","root");
define("DB_PASSWORD","");
define("DB_DATABASE","test");
define("USER_TABLE","users");
class DB
{
	private $connection;
	function __construct()
	{
		$connection=mysql_connect(DB_SERVER,DB_USERNAME,DB_PASSWORD) or die("We are facing some technical issue.Please try later on.");
		mysql_select_db(DB_DATABASE,$connection) or die("We are facing some technical issue.Please try later on.");
	}
}
?>

Implementation : Functions Class

Table 2: PHP Functions
Function Purpose
nl2br() Inserts HTML line breaks before all newlines in a string.
trim() Strip whitespace (or other characters) from the beginning and end of a string.
stripslashes() Un-quotes a quoted string.
strtr() Translate characters or replace substrings.
strip_tags() Strip HTML and PHP tags from a string.
mysql_real_escape_string() Escapes special characters in a string for use in an SQL statement.

  1. I use Functions class to have common functions defined. Functions class has currently two methods which are meant for security purpose.
  2. checkValues method is used to check any string for CROSS-SIDE Scripting.
  3. dbCheckValues method is used to check any string for SQL injection. This method should be used after mysql_connect method.

<?php
class Functions
{
	public function __construct()
	{

	}
	public function checkValues($value)
	{
		$value= nl2br($value);
		$value = trim($value);
		if (get_magic_quotes_gpc()) 
		{
			$value = stripslashes($value);
		}
		$value = strtr($value,array_flip(get_html_translation_table(HTML_ENTITIES)));
		$value = strip_tags($value,"<br>");
		return $value;
	}
	public function dbCheckValues($value)
	{
		$value = mysql_real_escape_string($value);
		return $value;
	}
}
?>

Implementation : User Class

Table 3: mysql Functions
Function Purpose
mysql_query() Send a MySQL query.
mysql_fetch_assoc() Fetch a result row as an associative array.
mysql_num_rows() Get number of rows in result.

  1. The constructor creates database object.
  2. checkUser method checks if the given email id and password are available in the USER table.
  3. dbCheckValues method is used to check for SQL injection. Each parameter of the function should go through this function to prevent possiblity of SQL injection.
  4. If user is available in database, return an array with true flag and userid.
  5. If user is not available return false flag with null user id.

<?php
include_once("db.php");
include_once("functions.php");
class User
{
	public function __construct()
	{
		$db=new DB();
	}
	function checkUser($email,$password)
	{
		$function=new Functions();
		$userArray=array();
		$status=FALSE;
		$userid=NULL;
		$email=$function->dbCheckValues($email);
		$password=$function->dbCheckValues(md5($password));
		$sql=mysql_query("SELECT uid FROM ".USER_TABLE." WHERE email='$email' and password='$password'");
		$row = mysql_fetch_assoc($sql);
		if(mysql_num_rows($sql)==1)
		{
			$status=TRUE;
			$uid=$row["uid"];
		}
		else
		{
			$status=FALSE;
			$uid=NULL;
		}
		$userArray= array(
			"status" => $status,
			"uid" => $uid
			);
		return $userArray;
	}
}
?>

Implementation : Error Class

  1. Contains method for printing the error.

<?php
class Error
{
	public function errorDisplay($subject,$errors)
	{
		$errorString = "<p class=\"error\">".$subject." Error</p>";
		$errorString .= "<ul>";
		foreach($errors as $error)
		{
			$errorString .= "<li class=\"error\">$error</li>";
		}
		$errorString .= "</ul>";
		return $errorString;
	}
}
?>

Implementation : User Controller

PHP provides a cookie-based implementation for session management. The $_SESSION array is used for storing session data. PHP automatically generates a session ID and sends a session cookie containing this session ID to the client machine. The PHP functions for session management are listed in Table 1


Table 4: Session Management Functions
Function Purpose
session_set_cookie_params() Set the session cookie parameters.
session_name () Get and/or set the current session name.
session_start() Initialises a session. If the session was not already started, it sends the session cookie to the client machine. If the session was already started, it loads the $_SESSION global variable with whatever values it was previously initialised with.
isset() Determine if a variable is set and is not NULL.
session_destroy() Destroys the session. The variable $_SESSION is cleared and the session cookie on the client is killed.

  1. Contains all methods related to user. This is the file which handles session in my case.
  2. Used session_name to set a session name. This is not mandatory.
  3. Used session_set_cookie_params to set session expiry time.
  4. session_start function should be called before you assign or read any session values. Functionality of the function is explained in the table above.
  5. loginUser method is used to check if the User is a valid user. To check for valid user, I call the user class method checkUser which returns either TRUE or FALSE value based on SELECT query. Parameters which are passed to loginUser are checked for CROSS-SIDE scripting using checkValues method defined in Functions class. If the user is valid, create a SESSION with key as uid and value as SQL SELECT userid.
  6. getUserId method is used to check if the SESSION is alive of not. If it is alive it returns TRUE, if not FALSE.
  7. logoutUser destroys the session for the given user. session_destroy functionality is explained in the table above.

<?php
session_name("pavanTutorialLogin");
// Starting the session
session_set_cookie_params(2*7*24*60*60);
// Making the cookie live for 2 weeks
session_start();
include_once("class/functions.php");
include_once("class/user.php");
class UserController
{
	public function loginUser($email,$password)
	{
		$function=new Functions();
		$email=$function->checkValues($_POST["email"]);
		$password=$function->checkValues($_POST["password"]);
		$user=new User();
		$userData=$user->checkUser($email,$password);
		if($userData["status"])
		{
			$_SESSION["uid"]=$userData["uid"];
			return TRUE;
		}
		else
		{
			return FALSE;
		}
	
	}
	public function getUserId()
	{
		if(isset($_SESSION["uid"]))
		{
			return $_SESSION["uid"];
		}
		else
		{
			return FALSE;
		}
	}
	public function logoutUser()
	{
		if(isset($_SESSION["uid"]))
		{
			$_SESSION = array();
			session_destroy();
		}
	}
}
?>

Implementation : Index Page

  1. Create object of userController Class. Call the method getUserId to check if the user is logged in.
  2. If the user is logged in, display logout link. Will explain the logout functionality at the end.
  3. Login Form has email and password as input fields. I am not performing any client side validation here. Will host another tutorial with client side validation using jQuery. Submission of the form, sends the form data as POST variables along with HTTP header to process.php page.

<?php 
include_once("controller/userController.php");
$userController=new UserController();
?>
<html>
	<head>
		<title>Login</title>
	</head>
	<body>
		<?php
		if($userController->getUserId())
		{
			echo "You have successfully logged in and your user id is ".$userController->getUserId();
			echo "<br/><a href=\"logout.php\">Click here if you want to logout</a>";
		}
		else
		{
			echo $errorString; 
		?>
		<form method="post" action="process.php">
			<table border="0">
				<tr>
					<td><label for="email">Email:</label></td>
					<td><input type="text" id="email" name="email" maxlength="50" /></td>
				</tr>
				<tr>
					<td><label for="password">Password:</label></td>
					<td><input type="password" id="password" name="password" /></td>
				</tr>
			</table>
			<input name="submit" type="submit" value="Log in" />
		</form>
		<?php
		}
		?>
	</body>
</html>

Implementation : Process Page

Table 5: php Functions
Function Purpose
in_array() Checks if a value exists in an array.

  1. Check if the form has been submitted.
  2. I have created an array to permit only the fields that I want to accept so that one can't send whatever they want to the form.
  3. All POST variable are checked for their size. If any POST variable is null, errors array would be pushed with the error message. All the POST variable are stored as normal variable with the same name.
  4. If errors array is not null, print the errors and show the form once again.
  5. If form has been submitted with no validation errors, call loginUser method part of userController object.
  6. If the response is FALSE, display the error and show the form once again.
  7. If the response is TRUE, redirect to index page.

<?php
// process.php
/*
 *  Specify the field names that are in the form. This is meant
 *  for security so that someone can't send whatever they want
 *  to the form.
 */
include_once("controller/userController.php");
include_once("class/error.php");
if($_POST["submit"])
{
	$error=new Error();
	$userController=new UserController();
	$allowedFields = array(
		"email",
		"password"
	);
	// Specify the field names that you want to require...
	$requiredFields = array(
		"email",
		"password"
	);
	// Loop through the $_POST array, which comes from the form...
	$errors = array();
	foreach($_POST AS $key => $value)
	{
		// first need to make sure this is an allowed field
		if(in_array($key, $allowedFields))
		{
			$$key = $value;
			// is this a required field?
			if(in_array($key, $requiredFields) && $value == "")
			{
				$errors[] = "The field $key is required.";
			}
		}
	}
	// were there any errors?
	if(count($errors) > 0)
	{
		$errorString=$error->errorDisplay("Form",$errors);
		// display the previous form
		include_once("index.php");
	}
	else
	{
		if($userController->loginUser($email,$password))
		{
			header("Location: index.php");
		}
		else
		{
			$errors[]="Wrong Id or Password";
			$errorString=$error->errorDisplay("Form",$errors);
			include_once("index.php");
		}
	}
}
else
{
	header("Location: index.php");
}

Implementation : Logout

  1. On page call, create object of userController and call logoutUser method which will destroy the SESSION and then redirect to Index page.

<?php
// logout.php
/*
 *  Logout the user
 */
include_once("controller/userController.php");
$userController=new UserController();
$userController->logoutUser();
header("Location: index.php");
?>

I have tried keeping it as simple as possible. Please post your comments/feedback below.





POST COMMENTS

No Comments Posted yet. Be the first one to comment.
Login to comment