PHP's session handling functions are OK, but
what if you wanted to create your own sessions? In this article I will
teach you how to create and maintain your own customized sessions.
Developing Custom PHP Sessions Ever wondered how to make your own session handling functions with PHP.
In this article Brian shows us how to do just that using PHP, MySQL and
a bit of maths!If you were programming a user authorization system for
your website, then you would use a session or a cookie to pass data. A
session would store the data on the server and reference it by a unique
key or ID. As your members browse through the member pages, his/her
data could be displayed or used by fetching that data. Alternatively,
you could use a cookie that stores the data on the users’ computer.
Fetching the data from the cookie would be similar to a session except
you use the cookie name: PHP handles the actual retrieval and sorting
of the cookie data.
PHP's session handling functions are OK,
but what if you wanted to create your own sessions? In this article I
will teach you how to create and maintain your own customized sessions.
You will have complete control over how your session handles the data
and how it fetches the data to make it available in your scripts.
This
is very useful because you can track users' IP addresses and other
information you can grab with PHP. There are many more advantages to
creating your own sessions as compared to using PHP's built-in session
handing functions.
In this tutorial I will assume the following things:
- You have PHP4+ ans MySql installed on your server.
- You have strong PHP and MySQL skills.
- You know object-oriented programming for PHP.
Anyhow, let's get started and work those customized PHP sessions!
Developing the Backend
First off, we need to plan out how we want to run our sessions by
creating our table. You can add a separate database for the sessions,
but I recommend setting up another table in your main database if you
are using one. We'll start by making a new database assuming you want
too. Run this set of code in your MySQL console application:
create database session;
create table sessions (
id int(10) NOT NULL AUTO_INCREMENT,
sess_key char(6) NOT NULL,
val varchar(250) NOT NULL,
ip varchar(35) NOT NULL,
access int(25) NOT NULL,
PRIMARY KEY(id)
);
We
simply created a new database and table. The "sessions" table will hold
all of our sessions that are actively running. As you become more
familiar with how to make your own sessions, then you may want to tweak
the table to optimize it for your needs.
Now let's take a look
at where all of our code will reside and start learning how the
sessions will work. We will need to create a new file, and let's name
it sess.php. In that new file put the following code:
<?php
$host = "localhost";
$user = "user";
$pass = "pass";
$db = "db";
$dbc = mysql_connect($host,$user,$pass) or die("Cannot establish a connection to the database.");
mysql_select_db($db,$dbc);
class session {
var $key;
var $timeout;
}
?>
Be
sure to change the database connection information to match the setup
on your server. We have just defined the very basics of our sessions.
We created a new class named session and defined two variables that
will be our class methods. These two variables will hold the session
key and timeout values.
Creating the Session Functions
I
will begin by introducing our first class function. The function will
be start() and it will initialize the session by generating the session
key. It doesn't store anything in the database yet. You can set the
timeout for the session when you call it, but it is optional.
// start() will initialize the session by generating the session key or ID
function start($timeout = "") {
// create an array with all the letters of the alphabet
$letters = range("a","z");
// declare the $key variable
$key = "";
// generate our session's key formatted such as #a#aa#
for($i = 0; $i < 6; $i++) {
if(($i == 0) || ($i == 2) || ($i == 5))
$key .= rand(0,9);
if(($i == 1) || ($i == 3) || ($i == 4))
$key .= $letters[rand(0,25)];
}
// store the session's key in a method of the class
$this->key = $key;
// perform a conditional to test if the user defined the timeout and if not store the default value.
if($timeout == "")
$this->timeout = 300; // five minutes
else
$this->timeout = $timeout;
return 0;
}
As
you can see from the code above, we have created a new function called
start(). The only argument, $timeout, is optional. If you don't set a
value then the function will set the default value of 300 seconds (5
minutes) for timing out. If you define it, it must be in seconds for
how long the session can be inactive.
Our function also
generates a session key that is used to reference the session in the
database. The key is based off the format #a#aa#. This function must be
called right after you initialize the class in your login script or the
script that will register the value to the session. It only needs to be
called once.
Our next function is register() and it will take the argument $val and store it into the database. Let's take a look:
// this function will register a value to session. (only one value, see replace() to update the value)
function register($val) {
// if key is not generated run start()
if($this->key == "")
$this->start();
$insert
= mysql_query("INSERT INTO sessions (sess_key, val, ip, sec_expire,
stamp_expire, access) VALUES ('" . $this->key. "', '" .
addslashes($val) . "' , '" . $_SERVER["REMOTE_ADDR"] . "' , " .
$this->timeout . "," . (time() + $this->timeout) . "," . time()
.");");
// set the cookie that will store the session key
setcookie("sess_key",$this->key,time()+3600);
}
At
the start of the function you will see that we test to see if the key
has been created or not. If you don't call start() before register()
then it will run start(), but you don't get the option of setting the
timeout. I've made our query bold so that it will be a little bit
easier to read.
The session key, session value, users' IP, all
the expiration details and last access information are stored. The
access field contains the last time the user accessed the session
before the session times out. This is important because the read()
function, seen later on, will update that field and if it's not updated
it will automatically time out after the specified timeout even if the
user is active. Finally, we set a cookie that will contain our session
key and will be used for future reference to the database.
Now let's take a look at our functions that
read and expire the session. The first function is read(). It will read
the session in the database, fetch it and store it to $sess_var. Here's
the code:
function read() {
// set $sess_val global - the variable of the session value.
global $sess_val;
// if the cookie doesn't exisit send them back to the login screen.
if(!$_COOKIE["sess_key"]) {
header("Location: login.php");
exit;
}
// fetch the session key from the cookie.
$this->key = $_COOKIE["sess_key"];
// fetch the session value
$query = mysql_query("SELECT val FROM sessions WHERE sess_key = '" . $this->key . "'") or die("query failed - line 55");
if(mysql_num_rows($query) == 0) {
header("Location: login.php");
exit;
}
$fetch = mysql_fetch_array($query);
// store the session value to $sess_val
$sess_val = stripslashes($fetch["val"]);
// test if session has reached the expiration point
$this->expire();
// this code will only run if expire() returned falsed - we update the last access point to now.
$update
= mysql_query("UPDATE sessions SET access = " . time() . " WHERE
sess_key = '" . $this->key . "'") or die("query failed - line 70");
}
We
tested the user in two places to see if they are logged in or not. The
user is required to be logged in for the user to have the cookie and
for the database entry to remain logged in. If not, they must login
again.
Next, the code pulls the session value from the
database and stores it in the $sess_val variable. When you are using
the code in your pages to output the sessions' value, you should use
the $sess_val variable. We will discuss that later on.
Finally,
we test the session for expiration and if it returns false then it will
update the last access field to "refresh" the session. I will now show
you how to test the session for expiration. It's quite simple, but
requires some mathematical skill.
// this function will test if the user has been inactive for the defined timeout
function expire() {
// fetch the last access and expirations from the database
$query
= mysql_query("SELECT access, sec_expire, stamp_expire FROM sessions
WHERE sess_key = '" . $this->key . "'") or die("query failed - line
78");
$fetch = mysql_fetch_array($query);
$access = $fetch["access"];
$expire = $fetch["sec_expire"];
$timeout = $fetch["stamp_expire"];
// test if session is expired based on defined timeout
if(($timeout - $access) <= ($expire - $expire)) {
$this->destory();
die("Your session has expired. Please re-login.");
}
}
All
of our session timestamps and timeout values are stored in the
database, so we fetch that information first. If $timeout (a regular
timestamp plus the session timeout) minus the last time the session was
accessed is less than or equal to the seconds for the session minus
itself, then we destroy the session and inform the user. If false, the
code continues to execute.
We now know our sessions pretty
well. What if we wanted to change the value of the session because the
value is the users' username? If the username is changed and the
session isn’t updated and you test it, the script would think it's
somebody else. No problem. Our next function is replace(). It simply
updates the current value with a new value.
// this function will update the session value
function replace($val) {
// fetch the user key from cookie
$this->key = $_COOKIE["sess_key"];
// update the database with the new value
$query
= mysql_query("UPDATE sessions SET val = '" . $val . "' WHERE sess_key
= '" . $this->key) or die("query failed - line 77");
}
Our function asks for the new value and then it will update the current value with it. Finally, we reach our last function:
// this function will kill the session
function destroy($key = "") {
// fetch the user key from cookie
$this->key = $_COOKIE["sess_key"];
// delete session from database
$query = mysql_query("DELETE FROM sessions WHERE sess_key = '" . $this->key . "'") or die("query failed - line 86");
// remove cookie from the user's computer
$delete = setcookie("sess_key" , $this->key, time()-3600);
if($query && $delete) {
header("Location login.php");
exit;
}
}
The
destroy() function will kill the session. It deletes the session from
the database and removes the cookie from the users' computer. We now
know everything about creating our sessions. We still have one more
issue to cover, which is how to use them.
Using Our Sessions
(Page 4 of 5 )
Let's start by creating a new file named login php. Add the following code to login.php:
<?php
include "sess.php";
if($login) {
$sess = new session;
$sess->start();
$sess->register($username);
header("Location: welcome.php");
}
?>
<html>
<head>
<title>login</title>
</head>
<body>
<form method="post" action="<?= $PHP_SELF; ?>">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<br>
<input type="submit" name="login" value="Login">
</body>
</html>
The
code above has our login form and if it's submitted it will initialize
the class and use the proper functions to start and register the
values. Then the user is redirected to the welcome.php page.
Last, but surly not least, we need to create our welcome.php page:
<?php
include "sess.php";
$sess = new session;
if($logout == "yes") {
$sess->destroy();
header(“Location: login.php”);
exit;
}
$sess->read();
?>
<html>
<head>
<title>welcome</title>
</head>
<body>
Welcome, <?= $sess_val; ?><br>
<a href="<?= $PHP_SELF; ?>?logout=yes">Logout</a>
</body>
</html>
Since
this page is the first one to use our sessions with the passing key, we
call the read() function to fetch the value. As seen in the read()
function, we saved the value to $sess_val so where we want that data to
appear we print it to the user. Then we offer a link to log out, which
uses the destroy() function to kill the current session.
Using Our Sessions
Let's start by creating a new file named login php. Add the following code to login.php:
<?php
include "sess.php";
if($login) {
$sess = new session;
$sess->start();
$sess->register($username);
header("Location: welcome.php");
}
?>
<html>
<head>
<title>login</title>
</head>
<body>
<form method="post" action="<?= $PHP_SELF; ?>">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<br>
<input type="submit" name="login" value="Login">
</body>
</html>
The
code above has our login form and if it's submitted it will initialize
the class and use the proper functions to start and register the
values. Then the user is redirected to the welcome.php page.
Last, but surly not least, we need to create our welcome.php page:
<?php
include "sess.php";
$sess = new session;
if($logout == "yes") {
$sess->destroy();
header(“Location: login.php”);
exit;
}
$sess->read();
?>
<html>
<head>
<title>welcome</title>
</head>
<body>
Welcome, <?= $sess_val; ?><br>
<a href="<?= $PHP_SELF; ?>?logout=yes">Logout</a>
</body>
</html>
Since
this page is the first one to use our sessions with the passing key, we
call the read() function to fetch the value. As seen in the read()
function, we saved the value to $sess_val so where we want that data to
appear we print it to the user. Then we offer a link to log out, which
uses the destroy() function to kill the current session.
Conclusion You may have noticed that our sessions can be improved upon greatly.
I've shown you one of the easiest ways of creating and maintaining your
own sessions. If you are planning to improve the code seen in this
article, then here are some ideas for expansion:
- Instead of
using a cookie to pass the key you can configure Apache to pass with
folders. For example, www.domain.com/members/5i1hk6/welcome.php.
- What
if the user closed his/her browser before logging out? You may want to
set up a cron job to run every five minutes to remove inactive sessions
to keep the database clean.
- You could also build an
administration area to quickly configure your sessions and see who’s
online and possibly kick them off whenever you desire.
|