I need help with the class below - its not writing to the database and I have no idea why. I know the "read" method is called, but not the "write" method :S
This is the code I'm using:
require '../application/database.php';
$db = new Database('localhost', 'root', '', 'gemgale');
require '../application/session.php';
$session = new Session($db);
session_set_save_handler(
array(&$session, 'open'),
array(&$session, 'close'),
array(&$session, 'read'),
array(&$session, 'write'),
array(&$session, 'destroy'),
array(&$session, 'clean')
);
session_start();
var_dump($session);
$_SESSION['something'] = "gem";
var_dump($_SESSION);
#$session->delete();
#var_dump($_SESSION);
and this is the class ...
class Session
{
###########################################################################
private $expiry = 3600;
private $securityCode = "gnvriev847e8grdinvrdg5e8g4r7fr7rdvreh8^£*^£FGgyhf";
private $tableName = "session_data";
###########################################################################
private $dbh;
function __construct(Database $db)
{
$this->dbh = $db->getConnection();
ini_set('session.cookie_lifetime', 0);
ini_set('session.gc_maxlifetime', $this->expiry);
}
function open($save_path, $session_name)
{
return true;
}
function close()
{
return true;
}
function read($session_id)
{
echo $session_id;
print "READING";
$time = time();
$hua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
$hua = $hua . $this->securityCode;
$hua = md5($hua);
try {
$stmt = $this->dbh->prepare("
SELECT session_data
FROM :tableName
WHERE session_id = :sesID
AND session_expire > :time
AND http_user_agent = :hua
LIMIT 1
");
$stmt->bindParam("tableName", $this->tableName);
$stmt->bindParam("sesID", $session_id);
$stmt->bindParam("time", $time);
$stmt->bindParam("hua", $hua);
$stmt->execute();
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
$rs = $stmt->fetch();
if (!$rs)
return '';
else
return $rs['session_data'];
}
function write($session_id, $session_data)
{
print "WRITING";
$expiry = time() + $this->expiry;
$hua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
$hua = $hua . $this->securityCode;
$hua = md5($hua);
try {
$stmt = $this->dbh->prepare("
INSERT INTO :tableName (
session_id,
http_user_agent,
session_data,
session_expiry
)
VALUES (
:sessID,
:hua,
:sdata,
:expiry
)
ON DUPLICATE KEY UPDATE
session_data = :sdata,
session_expire = :expiry
");
$stmt->bindParam("tableName", $this->tableName);
$stmt->bindParam("sessID", $session_id, PDO::PARAM_STR);
$stmt->bindParam("hua", $hua);
$stmt->bindParam("sdata", $session_data, PDO::PARAM_STR);
$stmt->bindParam("expiry", $expiry);
$stmt->execute();
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
if ($stmt->rowCount() > 1)
return true;
else
return '';
}
function destroy($session_id)
{
try {
$stmt = $this->dbh->prepare("
DELETE FROM :tableName
WHERE session_id = :id
");
$stmt->bindParam("tableName", $this->tableName, PDO::PARAM_STR);
$stmt->bindParam("id", $session_id, PDO::PARAM_STR);
$stmt->execute();
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
return true;
}
function clean($maxLifeTime)
{
try {
$x = time() - $maxLifeTime;
$stmt = $this->dbh->prepare("
DELETE FROM :tableName
WHERE session_expire < :x
");
$stmt->bindParam("tableName", $this->tableName, PDO::PARAM_STR);
$stmt->bindParam("x", $x, PDO::PARAM_INT);
$stmt->execute();
} catch (PDOException $e) {
die($e->getMessage());
}
return true;
}
function delete()
{
$oldID = session_id();
session_regenerate_id();
$this->destroy($oldID);
session_unset();
session_destroy();
}
function getActive()
{
$this->clean($this->expiry);
try {
$stmt = $this->dbh->prepare("
SELECT COUNT(session_id) as count
FROM :tableName
");
$stmt->bindParam("tableName", $this->tableName, PDO::PARAM_STR);
$stmt->execute();
$rs = $stmt->fetch();
return $rs['count'];
} catch (PDOException $e) {
die($e->getMessage());
}
}
}
Hope you guys can help :)
Thanks, Gem
One, you don't need to pass by reference. Do this instead:
session_set_save_handler(
array($session, 'open'),
array($session, 'close'),
array($session, 'read'),
array($session, 'write'),
array($session, 'destroy'),
array($session, 'clean')
);
To test if the save/write is working, you could try this:
session_start();
$_SESSION['something'] = "gem";
session_write_close();
echo "- Foo";
This should trigger a write to the session store and flush anything to be written. In this case it should display WRITING- Foo
if your write method is being called.
If the DB is not being written, but the method is being called, there are other issues.
The first thing I'd look at is the :tableName you're replacing in the prepared statement. You cannot prepare-replace column names or tables. Change your statement to this:
$stmt = $this->dbh->prepare("
INSERT INTO ".$this->tableName." (
session_id,
http_user_agent,
session_data,
session_expiry
)
VALUES (
:sessID,
:hua,
:sdata,
:expiry
)
ON DUPLICATE KEY UPDATE
session_data = :sdata,
session_expire = :expiry
");
If you do substitue in variables for table names or columns, make sure you whitelist them before using to be safe against opening an injection hole.