Jump to content

Sessions stored in database


Micro22

Recommended Posts

Hey guys,

 

I have been banging my head against a wall here with this. I am saving my sessions in my database via session_set_save_handler(). So let me walk you through what I have here, what works, and what the issue seems to be.

 

basically, the problem is the $_SESSION array is empty on page load.

 

common.php:

I have the open / close / read / write / destroy / and gc functions. These all work properly as when i use a session variable it stores into the database and i can see all of the information in there..

 

inside of common.php i have session_start().. I am positive that the session_start() is running becasue common.php is included into index.php and i tried adding session_start() to index.php again and i got an E_NOTICE saying the session already began.

 

(yes, for the read function i am returning a string... i included that below).

 

for the table itself, i have set the session_data as both text and blob, same issue with both.

 

 

index.php:

includes common.php. I know it's included as other aspects of the file are included and work properly.

 

if i call var_dump($_SESSION) i get an empty array.  and i prited out the session_id() and it matched my session id in the database. and the values that are stored in there are correct. i have for example:

 

count|i:0

 

now with that value actually in the database and when calling session_id() and i get the ID that matches in the table. so i will get an E_NOTICE of an undefined index..

 

i was trying something like:

 

if(!isset($_SESSION['count']))
     $_SESSION['count'] = 0;
else
     $_SESSION['count']++;

echo $_SESSION['count'];

 

Everytime the page is reloaded, count is reset to 0.. I can tell that it is reset to 0 as the expired time changes in the database after every load of the page (which is part of the write function).  I double checked that it wasn't a problem for some reason with the ++ by adding in a variable that sets to 1 when in the if, and 0 if in the else, and it always outputs a 1.

 

i have included here my read function since that apparently is the issue..

 

function sess_read($sess_id)
{
      global $DB;      

      $sql = "SELECT `session_data` FROM `sessions` WHERE
                session_id = '".$sess_id."' AND
                session_agent = '".$_SERVER["HTTP_USER_AGENT"]."' AND
                session_expire > '".time()."';";                

       $query = $DB->query($sql);       

       if($DB->num_rows($query) > 0)       
       {
       $r = $DB->fetch($query);       
           return settype($r['session_data'], 'string');           
   }       
   
        
       return '';
}

 

I tried also with removing the agent and expire check to see if it was an issue there but same problem.

 

I probably have missed something really dumb but i can't for the life of me figure it out and I have googled around for a similar issue. The actual output of the page is correct.. all of the HTML and CSS information loads properly.. no errors are reported (and i have E_ALL on).

 

Thanks

Link to comment
Share on other sites

Without a complete set of code that reproduces the problem, it will be a little hard to help with the problem.

 

It could be your database class, your session_set_save_handler statement, a program/variable scope problem, your php code that is attempting to use the session variables...

Link to comment
Share on other sites

As I have said above.. the rest of it works.. and i gave an example of where i used the code and it not working.. which is the exact code from my site.. but if you wish to see the rest of my session handler:

 

common.php:

$sessionLifetime = get_cfg_var("session.gc_maxlifetime");

function sess_regen_id()
{
    $old = session_id();    
    session_regenerate_id();    
    sess_destroy($old);
}

function sess_open($who, $cares)
{
   return true;   
}

function sess_close()
{
   return true;    
}

function sess_read($sess_id)
{
      global $DB;      

      $sql = "SELECT `session_data` FROM `sessions` WHERE
                session_id = '".$sess_id."' AND
                session_agent = '".$_SERVER["HTTP_USER_AGENT"]."' AND
                session_expire > '".time()."';";                

       $query = $DB->query($sql);       

       if($DB->num_rows($query) > 0)       
       {
       $r = $DB->fetch($query);       
           return $r['session_data'];           
   }       
   
        
       return '';
}

function sess_write($sess_id, $sess_data)
{
       global $DB, $sessionLifetime;
     

       $query = $DB->query("SELECT * FROM `sessions` WHERE `session_id` = '". $sess_id ."';");       
       if($DB->num_rows($query) > 0)       
       {       
            $DB->query("UPDATE `sessions` SET `session_data` = '". $sess_data ."',             
            `session_expire` = '". (time() + $sessionLifetime) ."' WHERE `session_id` = '". $sess_id ."';");

            if($DB->affected() > 0)            
                return true;                
  
            return false;
       }       
       else       
       {       
             $DB->query("INSERT INTO `sessions`(`session_id`, `session_data`, `session_expire`, `session_agent`, `session_ip`) VALUES             
                       ('". $sess_id ."', '". $sess_data ."', '". (time() + $sessionLifetime) ."', '". $_SERVER['HTTP_USER_AGENT'] ."', '". $_SERVER['REMOTE_ADDR'] ."');");                                              

            if($DB->affected() > 0)            
                return '';                  

             return false;
       }       

       return false;
}

function sess_destroy($sess_id)
{
        global $DB;        
        
        $DB->query("DELETE FROM `sessions` WHERE `session_id` = '". $sess_id ."';");        

        if($DB->affected() > 0)        
           return true;           

         return false;
}

function sess_gc($limit)
{
         global $DB;    

         $DB->query("DELETE FROM `sessions` WHERE `session_expire` > '". (time() - $limit) ."';");

         if($DB->affected() > 0)         
             return true;             
                
          return false;
}

session_set_save_handler("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");

register_shutdown_function('session_write_close'); 

session_start();

 

the database class i am using i know works.. and in this scope it works as again it works with the other functions.. also again as i said above no errors are thrown. (before you say i don't check for errors on the queries my DB class handles that).

 

the $_SESSION should be global by default.. and simply commenting all of the above code out works with the default PHP session handler so it's not a scope problem for $_SESSION (which is used directly after this file is included anyway)

 

i will include the code i used again to test all of this:

 

index.php


require_once './common.php';

var_dump($_SESSION); // outputs array(0) {}

if(!isset($_SESSION['count']))     
    $_SESSION['count'] = 0;
else     
     $_SESSION['count']++;

echo $_SESSION['count'];  // outputs 0 everytime

// rest of code.

 

 

since session_start() is in common.php it is running before the sessions are being called.. and the auto start is not on for PHP sessions.

Link to comment
Share on other sites

if($DB->num_rows($query) > 0)

 

^^^ That line looks suspicious. In most db classes, the query would return a result object and you would use a call like $query->num_rows() to access the number of rows. Have you actually tested the logic in sess_read() by calling it directly to see if it does what you expect for an existing record?

 

Your sess_gc() logic is backward and probably won't ever delete anything or it will delete things that have a future (>) expire time. You probably want it to delete records where the `session_expire` < '". time() ."'

 

Your overall use of `session_expire` is a bit unusual. By setting it to a future time (rather than setting it to the current time when a record is accessed) any time you change the session.gc_maxlifetime setting, the change won't affect existing session data records because their session_expire was already determined when they were stored, not when they are referenced.

 

You can replace (pun intended) most of your sess_write() code with a single REPLACE query. There's no need to run a SELECT query to decide if you should run an UPDATE or an INSERT query.

 

And you do realize that using some relatively slow parsed, tokenized, interpreted php code to do the session handling is ~10 times slower than using the built-in compiled file save handler, so you would need to have a really good reason to use a database session save handler.

Link to comment
Share on other sites

BTW, I just tested your code and it 'functions' as expected, with no changes to the common.php code.

 

All I added was a simple DB class, an instance of the db class in $DB, and the actual table in the database.

 

Your index.php displays the following expected output for each refresh of the page -

array(1) { ["count"]=> int(38) } 39

array(1) { ["count"]=> int(39) } 40

array(1) { ["count"]=> int(40) } 41

...

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.