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`);
)
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;
}
}
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();
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