Storing sessions in the database

Using Sessions in PHP can be extremely useful, and is almost a requirement when making dynamic web applications. However, sessions do have drawbacks, and one of these is security. When a session is created, it gets written to a file on the server. If the server you are using has other hosting accounts, they will also be using the same directory as your session files. If you’re storing any personal information about your website visitors, you have quite a serious problem.

For this reason, I would strongly suggest storing your sessions in a database. This tightens security considerably, and also allows for a wealth of new possibilities, such as running SQL queries on the database to see how many users are logged in. It is also the only logical solution if you are using multiple servers that need to access the same user sessions.

It’s quite simple to make the change to storing sessions in the database, and all you need for the following example is PHP 5 and MySQL.

First of all you will need to include the following PHP code in every page on your website that needs database or session access. It should be the very first thing included on every page.

sessions_database.inc.txt

Don’t forget to change your database details!

Secondly, you will need the following at the bottom of each page:

//You must call the following at the bottom of every page that uses sessions
session_write_close();

The last thing you need to do is to create the database table to store the sessions. Here is the SQL to do so for a MySQL database:

CREATE TABLE `sessions` (
  `id` char(32) NOT NULL,
  `data` longtext NOT NULL,
  `last_accessed` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Tags: , , , ,

16 Comments

  1. Thanks for this. How do you go about accessing the session on a per user basis to show content. For instance, I’m using your method to store the session in a database, but all my pages are configured to use $_SESSION.

    Example of what I’m using:

    if(isset($_SESSION['user'])){
    //user is logged in, do something
    } else {
    //user is not logged in… give login prompt
    }

    Because the session is now not stored in $_SESSION, obviously that will always return that the user is not logged in.

    • Hi Zack,

      The session is still accessed using the $_SESSION variable so you shouldn’t need to change your code. Whether you’re using the filesystem or the database to store your sessions you’ll always use $_SESSION to access it.

  2. This is a great script, I am stuck on one part – I have two questions.

    Firstly – my sessions never seem to expire ? they seem to last forever .. why would that be?

    Second – how can I adjust the script so that I can define my own timeout?

    Thanks
    Mark

  3. ahh in my last message, when I say they dont expire – what I mean is they never disapear from the database. – Sorry

  4. Hi Mark,

    The way PHP works is that it runs the garbage collection method on random occasions based on a few probability rules (you wouldn’t want it running every time a page is loaded for efficiency reasons). If you’re finding that the garbage collection method isn’t running try increasing the probability of it running.. you can find out information on how to do that here – http://www.captain.at/howto-php-sessions.php

    Not sure what you mean by defining the timeout, could you describe this a bit more?

    • Hi Richard, thanks for coming back to me so quickly, I think I may not be fully understanding the script.

      I have checked on php info my settings are
      session.gc_divisor 100 100
      session.gc_maxlifetime 1440 1440
      session.gc_probability 1 1

      I have actually set it manually within the script so that the maxlifetime (sorry I was calling it timeout) was quick …

      $garbage_timeout = 100; // 3600 seconds = 60 minutes = 1 hour
      ini_set(‘session.gc_maxlifetime’, $garbage_timeout);

      yet I am looking at sql table and it is full of old sessions (from two / three days ago) … I have checked permissions of the database and with the account specified in the script have made sure I can delete the record manually.

      I don’t think I fully understand how the function within your script – function clean_session($expire) … actually is called ?

      I think I maybe doing something really silly?

      • Hi Mark,

        Could you check whether the last_accessed field is working in your database – is it storing the timestamp?

        Try running this query and see if it returns any results..
        SELECT `id` FROM sessions WHERE DATE_ADD(last_accessed, INTERVAL 3600 SECOND) < NOW()

        If it works it should return sessions older than an hour. If that's the case we've eliminated one potential issue and can try something else..

    • Wow you were quick replying … thanks for helping me.

      Yes the query was successful, and i have results … showing old sessions.

      • No problem! It’s an 16 hour working day for me at the moment so i’m often around! That’s good that that’s working. The next step is to see if the garbage collector function (clean_session) gets called. The idea is PHP calls the function randomly based on your probability rules – it passes the session expiry length as a parameter.

        Put this code at the bottom of the clean_session function:
        mail(‘youremail@yourdomain.com’,'cleaning the session’,$q);

        You won’t get an email as soon as you refresh the page – you might have to call the page a hundred times in order to trigger the garbage collector. If you don’t get the email through alter the probability settings – you should tweak these anyway to suit the traffic on your website (a popular website could trigger the collector every few seconds whereas a less popular site could trigger it every week).

    • Ive run the mail command seperately to make sure it works .. which it does …

      I have now called my page that includes your script around 300 times … but no email …

      its very odd, I know when I do normal sessions (if you call it that) via file it does clean them up, it seems strange that this function is never called? — I will keep refreshing for another 10 minutes …

    • and sods law .. 5 more refreshes and I get my email – so the function is being called (feeling exciting now!!) … yet the sessions still exist in my sql table…

    • actually looking at it, i think sessions from over 2 days ago have been deleted … maybe this is a timing issue somewhere … I am just going back through the code

  5. Hi Richard,

    I have it working perfectly now, I think it was simply due to me not being patient enough with the system, as its only an intranet page it doesnt get accessed all that much so the gc function takes a while to get called.

    Anyway I have started to make a page that displays who is currently online, I have pulled the data from the session table and started to use the explode function to try and seperate between the | : i.e. one of the session data stored in the database looks like timezone|s:13:”Europe/London” where I want to display it as timezone:”Europe/London”

    Just thought I would ask to see if you or anyone reading had any simple ideas on extracting the data rather than using explode?


Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>