Nightmares trying to restore sessions from mysql db

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
thrasherben
Forum Newbie
Posts: 3
Joined: Wed Jul 15, 2009 2:59 pm

Nightmares trying to restore sessions from mysql db

Post by thrasherben »

***** Please do not double post *****

Hi,

I'm having nightmares trying to restore sessions from a mysql database using the session_set_save_handler function built into PHP. When I link to pages from the secure domain to the un-secure domain the session data is temporarily restored, and vice-versa. However, when I go to another page on the un-secure domain the session data is lost, and vice-versa.

e.g. Say I have a shopping cart page which puts the cart contents in to a SESSION variable called $_SESSION['cart']. When I click 'Checkout' on the shopping cart page the url is moved from the un-secure domain (http://www.domainname.com/cart.php) to the secure domain (https://secure2.securehost.co.uk/locked/checkout.php). When the checkout page loads it has successfully retrieved the session data from the shopping cart page. However, this page asks for the shipping details and you must click continue, with valid data in the form, to proceed to the billing details page. When the billing details page is loaded, which is also on the secure domain, the session data is lost and the the basket displayed is empty. The next page is the order review page, which is also secure, but because the data is lost on the billing page it shows an empty list of items to review.

My session handler object generates a unique id (for security reasons), which it saves in a table called 'tmp_sessions', along with the actual session id, data and a timestamp. The unique id is then appended to the url (e.g. checkout.php/auth=0907152131-9cYF) when going between pages on the secure and non-secure site. When the checkout page loads the Read method is called by session_set_save_handler and checks whether $_GET['auth'] is set. If it is set it queries the db for a record that matches the unique id otherwise it queries for the session id passed into Read.

However, when going between pages on the same domain name I don't want to save the session data (passing the unique id to the next page which would work) because the stored data will not have changed plus if I save the session data after the billing details page the customers card details will be stored in the 'tmp_sessions' table. VERY BAD

I want it to keep the session data that was loaded when the domain was originally changed i.e. the data that was loaded from 'tmp_sessions' on the shipping information page.

The secured files are hosted on the same server as the non-secured files except that the non-secured files are in the root directory but the secured files are in a folder called 'locked' in the root directory. If I call a file that needs a secure connection, such as my login and checkout pages, using the non secure domain name the page loads and works fine, but is obviously not secure.

Below is the tmp_sessions table structure:-

Code: Select all

 
CREATE TABLE `tmp_sessions` (
  `tmp_id` varchar(100) NOT NULL,  
  `tmp_session_id` varchar(100) NOT NULL,
  `tmp_data` text NOT NULL,
  `tmp_expiry_date_time` int(11) NOT NULL,
  
  PRIMARY KEY  (`tmp_id`);
)
 
I am then using my own methods, held within the SessionHandler object, to pass to session_set_save_handler in the constructor of my object. Here is my SessionHandler object:-

Note: I have replaced any sensitive information with *

Code: Select all

 
class SessionHandler{
    
    var $mLifeTime;
    var $mMySQLConnect;
    var $mUniqueID;
    var $mTempUniqueID;
    
    
    function SessionHandler()
    {
        // Read the maxlifetime setting from PHP
        
        $this->mUniqueID = $this->GenerateUniqueSessionId();
        
        $this->mLifeTime = get_cfg_var("session.gc_maxlifetime");
 
        // Register this object as the session handler
 
        session_set_save_handler( 
 
            array( &$this, "OpenConnection" ), 
    
            array( &$this, "CloseConnection" ),
    
            array( &$this, "Read" ),
    
            array( &$this, "Write"),
    
            array( &$this, "Destroy"),
    
            array( &$this, "GarbageCollector" )
 
        );
    }
    
    function GetUniqueId()
    {
        return $this->mUniqueID;
    }
    
    function OpenConnection( $save_path, $session_name ) {
        
        global $sess_save_path;
        
        $sess_save_path = $save_path;      // Don't need to do anything. Just return TRUE.
        
        $this->mDBConnect = new MySQLConnect("***.***.***.***","******","****","****");
        
        return true;
    }
 
    function CloseConnection() {
        $this->mDBConnect->CloseConnection();
        
        return true;
    }
    
    function Read( $id ) {
 
        echo "Read - ";
        // Set empty result
 
        $data = '';
 
        // Fetch session data from the selected database
 
        $time = time();
        
        if (isset($_GET["auth"]))
        {
            echo "Auth - ";
            $sql = "SELECT `tmp_data` FROM `tmp_sessions` WHERE `tmp_id` = '".$_GET["auth"]."' AND `tmp_expiry_date_time` > $time";
        }
        else
        {
            echo "New Id - ";
            $newid = mysql_real_escape_string($id);
            $sql = "SELECT `tmp_data` FROM `tmp_sessions` WHERE `tmp_session_id` = '".$newid."' AND `tmp_expiry_date_time` > $time";
            echo $newid;
            //echo $sql." - ";
        }
        
        $rs = mysql_query($sql);
        $a = mysql_num_rows($rs);
        
        if($a > 0) {
 
            $row = mysql_fetch_assoc($rs);
    
            $data = $row['tmp_data'];
                
            echo "Temp data = ".$row['tmp_data']." - ";
        }
        else
        {
            echo "No temp data - ";
        }
        
        return $data;
    }
 
    function Write( $id, $data ) {
        
        
        // Build query                
 
        //echo "Page - ".$_SERVER["SCRIPT_NAME"]." - ";
        
        
        echo "Write - ";
            
        $time = time() + $this->mLifeTime;       
        
        $newid = mysql_real_escape_string($id);
    
        $newdata = mysql_real_escape_string($data);
                    
        $sql = "REPLACE `tmp_sessions` (`tmp_id`,`tmp_session_id`,`tmp_data`,`tmp_expiry_date_time`) VALUES('".$this->mUniqueID."','$newid','$newdata', $time)";
    
        $rs = $this->mDBConnect->Replace($sql);
       
        
        
        return true;
   }
 
   function Destroy( $id ) {
        
        echo "Destroy - ";
        // Build query
 
       $newid = mysql_real_escape_string($id);
 
       $sql = "DELETE FROM `tmp_sessions` WHERE `tmp_id` = '$newid'";
       
       $this->mDBConnect->Delete($sql);
       
       return true;
   }
 
   function GarbageCollector() {
      // Garbage Collection
      // Build DELETE query.  Delete all records who have passed
 
      //  the expiration time
 
      echo "Garbage Collection - ";
      
      $sql = 'DELETE FROM `tmp_sessions` WHERE `tmp_expiry_date_time` < UNIX_TIMESTAMP();';
 
      $this->mDBConnect->Delete($sql);
 
      // Always return TRUE
 
      return true;
    }
    
    function GenerateCharacter()
    {
        $possible = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
        return $char;
    }
    
    function GenerateUniqueSessionId()
    {
        $GUID = date('ymdHi')."-";
        $GUID = $GUID .$this->GenerateCharacter().$this->GenerateCharacter().$this->GenerateCharacter().$this->GenerateCharacter();
        return $GUID;
    }
    
 }
 
When moving to the second page of the new domain I noticed that the session id has changed from the one stored in the database on the original move to the new domain by echoing $newid and checking the record in the db.

Also, thought you might like to know how I'm calling the session handler:-

Code: Select all

 
 ini_set('session.save_handler','user');
 ini_set('session.cookie_domain','domainname.com');
 session_set_cookie_params(900,'/','domainname.com',false,false);
 
 require('../classes/MySqlConnect.php');
 require_once("../classes/SessionHandler.php");
 
 $Session = new SessionHandler();
 
 session_start();
 
 require('../classes/UserAuthentication.php');
 require('../classes/ShoppingCart.php');
 require('../classes/Navigation.php');
 require('../classes/CheckoutContent.php');
 require('../classes/GeneratePage.php');
 require('../classes/TwoColumnNavBarLayout.php');
 require('../classes/ShippingInformation.php');
 require('../classes/BillingInformation.php');
 
 /* rest of my code which initialise instances of the required objects for the page and calls methods to get the information then echoes the output. None of these should affect the SessionHandler so I haven't included them!*/
 
 session_write_close();
 
Can anyone see what is wrong with my code or can you suggest a better solution? I thought that session_set_save_handler was supposed to handle this so that the data stays once you've copied it to the new domain.

This is driving me crazy as I have been trying to figure it out for days. I've tried to write solutions but then ended up scrapping them because the either didn't work or I noticed security flaws with them.

My object is adapted from the following artical:-

http://www.mt-soft.com.ar/2007/12/21/us ... sion-data/

Any help would be greatly appreciated

Thanks in advance,

Ben
thrasherben
Forum Newbie
Posts: 3
Joined: Wed Jul 15, 2009 2:59 pm

Re: Nightmares trying to restore sessions from mysql db

Post by thrasherben »

Forgot to add,

I'm using PHP Version 5.1.6
thrasherben
Forum Newbie
Posts: 3
Joined: Wed Jul 15, 2009 2:59 pm

Re: Nightmares trying to restore sessions from mysql db

Post by thrasherben »

I've decided to scrap this file as I worked out that when PHP was handling the sessions from the database it was changing the session id on every page. This meant that the session data disappeared on every page move unless the unique id was passed in a GET, in which case it would restore the info from the db.

I have now implemented a solution that stores the session data in the database temporarily when moving between domain, using a unique id, then just set the session data from the data associated with that id on the next page but only setting the data with session_decode() and not setting the session id that's stored. This way it only uses two different session id, one for each domain, and only calls Read() when $_GET['auth'] is set.

Also, this way you can leave session.cookie_domain as the default value for all domains.

I hope this helps anyone else with a similar problem, it's taken me days to figure out how PHPs session function work.
Post Reply