I'm currently learning php and trying to write session data to my database without success.
I have a setup with Apache24, PHP 7 environment and Postgresql database.
When I instantiate sessionhandling class ($sess = new sessionhandling) in my other PHP file nothing is written to database. However, when I pass variable to and call the write function ($sess->write), data is written to the database.
(Hope this is not a duplicate of any other questions raised. Done a lot of searches on Stackoverflow and Google, but not found any answers that solve my challenge)
My session handler code is as follows:
<?php
Include(dirname(__DIR__).'\Userstories\db\Connection.php');
class sessionhandling extends Connecting implements SessionHandlerInterface {
public function __construct(){
// Set handler to overide SESSION
session_set_save_handler(
array(&$this, "open"),
array(&$this, "close"),
array(&$this, "read"),
array(&$this, "write"),
array(&$this, "destroy"),
array(&$this, "gc")
);
register_shutdown_function('session_write_close');
// Start the session
session_start();
session_write_close;
}
public function open($save_path, $id) {
if(self::get()->connect()) {
return true;
} else {
return false;
}
}
public function close() {
if(self::get()->connect()->pdo = Null) {
return true;
} else {
return false;
}
}
public function read($id) {
//$pdo = Connecting::get()->connect();
$ipdo = self::get()->connect();
$q_udata = "SELECT data FROM sessions WHERE id=:id";
$stmt=$ipdo->prepare($q_udata);
$stmt->bindvalue(':id', $id);
$stmt->execute();
if($stmt->execute()) {
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$ipdo = NULL;
return $row['data'];
} else {
$ipdo = NULL;
return '';
}
}
public function write($id, $data){
$id = (string) $id;
$data = (string) $data;
$access = time();
$ipdo = self::get()->connect();
$c_id = "SELECT id FROM sessions WHERE id=:id";
$stmt=$ipdo->prepare($c_id);
$stmt->bindvalue(':id', $id);
$stmt->execute();
$idarray=$stmt->fetch(PDO::FETCH_ASSOC);
$row_id = $idarray['id'];
if(empty($row_id)) {
$sessionids = 'INSERT INTO sessions(id, data, access) VALUES(:id, :data, :access)';
$stmt = $ipdo->prepare($sessionids);
$stmt->bindvalue(':id', $id);
$stmt->bindvalue(':access', $access);
$stmt->bindvalue(':data', $data);
$stmt->execute();
session_write_close();
} else {
$rep_data = "UPDATE sessions SET data = :data, access = :access WHERE id = :id";
$stmt=$ipdo->prepare($rep_data);
$stmt->bindvalue(':id', $id);
$stmt->bindvalue(':access', $access);
$stmt->bindvalue(':data', $data);
$stmt->execute();
session_write_close();
}
if($stmt->execute()) {
$ipdo = NULL;
return true;
} else {
$ipdo = NULL;
return false;
}
}
public function destroy($id) {
$ipdo = self::get()->connect();
$del_data = "DELETE FROM sessions WHERE id =:id";
$stmt = $ipdo->prepare($del_data);
$stmt->bindvalue(':id', $id);
$stmt->execute();
if($stmt->execute()) {
$ipdo = NULL;
return true;
} else {
$ipdo = NULL;
return false;
}
}
public function gc($max) {
$old = time() - $max;
$ipdo = self::get()->connect();
$cleanup = "DELETE * FROM sessions WHERE access < :old";
$stmt = $ipdo->prepare($cleanup);
$stmt->bindvalue(':old', $old);
$stmt->execute();
if($stmt->execute()) {
$ipdo = NULL;
return true;
} else {
$ipdo = NULL;
return false;
}
}
}
?>
When I remove the 'implements SessionHandlerInterface' sessionhandling class and remove the parameters $save_path, $id from open function, I get the following error: "Warning: session_start(): Failed to read session data: user (path: ) in C:\Users\Public\Server\Apache24\htdocs\Userstories\sessionhandling.php on line 19"
Is it reuiqred to define the $save_path when using DB for session handling? If so, what should the $save_path be?
Any advise on how to get my session handler to write to DB is very much appreciated.
I made ut work by changing my read function to this and ensuring that a string is returned:
public function read($id) {
//$pdo = Connecting::get()->connect();
$ipdo = self::get()->connect();
$q_udata = "SELECT data FROM sessions WHERE id=:id";
$stmt=$ipdo->prepare($q_udata);
$stmt->bindvalue(':id', $id);
$stmt->execute();
if($stmt->execute()) {
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
$ipdo = NULL;
$data = $row['data'];
return (string) $data;
} else {
$ipdo = NULL;
return '';
}
}
I know this has been pointed out in other posts, but I thought that my $data = $row['data'] would return a string in the first place.
Related
Everything is working except when i call the save_info function from load_info function to save to database
I tried including the entire block of code from the save_info function in the if statement but it still doesn't work
// This function will save information to an existing account
//==MAN8==
function save_info($dbh, $table, $pname, $pip, $pnp, $pop, $psp)
{
try
{
$stmt = $dbh->prepare("UPDATE $table SET p_ip=?, p_np=?,p_op=?,p_sp=? WHERE p_name=?");
$stmt->execute(array($pip,$pnp,$pop,$psp,$pname));
echo "1";
}
catch (PDOExecption $ex)
{
echo "0";
}
$dbh = null;
}
// This function will pull account information
//==MAN9==
function load_info($dbh,$table,$pname)
{
{
$stmt = $dbh->query("SELECT * FROM $table WHERE p_name = '$pname'");
$result = $stmt->fetchObject();
if ($result->p_ip > $result->p_np)
{
echo 'yes';
}
if ($result->p_ip = $result->p_np)
{
save_info($dbh, $table, $pname, $pip, $pnp, $pop, $psp);
}
}
here is my code for optverify.php if the input number is wrong its redirect to index.php its not giving error.its should give a error for wrong otp but please help me to solve this issue
<?php
// Create a unique instance of your session variables
session_start();
if(isset($_SESSION['usr_id']))
{
$uid=$_SESSION['usr_id'];
} else {
header("Location:login.php");
}
require_once 'include/DB_Functions.php';
$db = new DB_Functions();
if (isset($_POST['verifyotp'])) {
$otpsms = $_POST['smsotp'];
$otpemail = $_POST['emailotp'];
$user = $db->verifyotp($uid);
if($user){
$user['smsotp'] = $otpsms;
$user['emailotp'] = $otpemail;
header("Location:index.php");
} else {
$errormsg = "Invalid otp";
}
}
?>
and my codes for data base function are below
public function verifyotp($uid){
$stmt = $this->con->prepare("SELECT uid,smsotp,emailotp FROM users WHERE uid = '$uid'");
$stmt->bind_param("i", $uid);
if ($stmt->execute()) {
$stmt->bind_result($uid,$smsotp,$emailotp);
$stmt->fetch();
$user = array();
$user["uid"] = $uid;
$user["smsotp"] = $smsotp;
$user["emailotp"] = $emailotp;
$stmt->close();
return $user;
} else
{
return $stmt;
}
}
Not tested but this should work !! Let me know if this doesn't work. will delete this answer.
Updated
Change this $user = $db->verifyotp($uid); to $user = $db->verifyotp($uid, $otpsms, $otpemail);
then modify your function like below if you are willing to test 3 parameters (1) id (2) smsotp (3) emailotp.
public function verifyotp($uid, $sotp, $eotp){
$stmt = $this->con->prepare("SELECT uid,smsotp,emailotp FROM users WHERE uid = '$uid' And smsotp='$sotp' And emailotp ='$eotp'");
$stmt->bind_param("i", $uid);
if ($stmt->execute()) {
$stmt->bind_result($uid,$smsotp,$emailotp);
$stmt->fetch();
$user = array();
$user["uid"] = $uid;
$user["smsotp"] = $smsotp;
$user["emailotp"] = $emailotp;
$stmt->close();
return $user;
} else
{
return $stmt;
}
}
Thanks for your help in advance.
I have just migrated my webserver from apache to nginx. Session information was happily being stored in the database previously, now for some reason they are writing to the /tmp directory.
Here is the code to set the session handler:
session_write_close();
$sess = new sessionHandler();
session_set_save_handler(array($sess, 'open'),
array($sess, 'close'),
array($sess, 'read'),
array($sess, 'write'),
array($sess, 'destroy'),
array($sess, 'gc'));
register_shutdown_function('session_write_close');
session_start();
$cookieLifetime = 365 * 24 * 60 * 60;
setcookie(session_name(),session_id(),time()+$cookieLifetime);
and here is the session handler class:
class appSessionHandler {
private $db;
public function open($save_path, $session_name) {
$this -> db = new appSql();
return true;
}
public function close() {
$this -> db -> close();
}
function read($id) {
// Create Memcache Class
$memcache = new memcacher();
var_dump('123');
// Check Memcache
$memcache->key = 'session-' . $id;
$memcache->get();
// If results is in memcache
if ($memcache->result != false){
$res = $memcache->result;
return $res;
}
// Else get the result from sql and update cache
else{
$this->open();
$this->db->sqlQuery = "SELECT data FROM session WHERE id = :id";
$this->db->params = array('id' => $id);
$res = $this->db->sqlQuery();
if (count($res) >= 1){
$memcache->input = $res[0]->data;
$memcache->duration = 2000;
$memcache->set();
return $res[0]->data;
}
return '';
}
}
function write($id, $data) {
$access = time();
$this->open();
// Create Memcache Class
$memcache = new memcacher();
// Check Memcache
$memcache->key = 'session-' . $id;
$memcache->input = $data;
$memcache->duration = 2000;
$memcache->set();
$this->db->sqlQuery = "REPLACE INTO session VALUES (:id, :access, :data)";
$this->db->params = array('id' => $id, 'access' => $access, 'data' => $data);
return $this->db->sqlQuery();
}
function destroy($id) {
// Delete From SQL
$this->open();
$this->db->sqlQuery = "DELETE FROM session WHERE id = :id";
$this->db->params = array('id' => $id);
// Create Memcache Class
$memcache = new memcacher();
// Check Memcache
$memcache->key = 'session-' . $id;
$memcache->delete();
return $this->db->sqlQuery();
}
function gc($max) {
$old = time() - $max;
$this->open();
$this->db->sqlQuery = "DELETE FROM session WHERE access < :old";
$this->db->params = array('old' => $old);
return $this->db->sqlQuery();
}
public function killUserSession($username){
$this->open();
$this->db->sqlQuery = "delete from session where data like('%userID|s:%\" :username %\";first_name|s:%')";
$this->db->params = array('username' => $username);
$this->db->sqlQuery();
}
}
I am lost!
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.
After taking some advice from people on here in a previous thread, I'm trying to convert my MySQL to PDO, but am running into some issues.
Here is my original MySQL connection class:
class DbConnector {
public static function getInstance() {
static $instance = null;
if ($instance === null) {
$instance = new DbConnector();
}
return $instance;
}
protected $theQuery;
private $link;
function DbConnector() {
$host = 'localhost';
$db = '';
$user = '';
$pass = '';
// connect to the db
$this->link = mysql_connect($host, $user, $pass);
mysql_select_db($db);
register_shutdown_function(array(&$this, 'close'));
}
public function find($query) {
$ret = mysql_query($query, $this->link);
if (mysql_num_rows($ret) == 0)
return array();
$retArray = array();
while ($row = mysql_fetch_array($ret))
$retArray[] = $row;
return $retArray;
}
public function insert($query) {
$ret = mysql_query($query, $this->link);
if (mysql_affected_rows() < 1)
return false;
return true;
}
public function query($query) {
$this->theQuery = $query;
return mysql_query($query, $this->link);
}
public function fetchArray($result) {
return mysql_fetch_array($result);
}
public function close() {
mysql_close($this->link);
}
public function exists($query) {
$ret = mysql_query($query, $this->link);
if (mysql_num_rows($ret) == 0)
return false;
}
public function last_id($query) {
return mysql_insert_id($query);
}
}
Here is the function that I'm writing:
function getRandomSubmission() {
global $db;
if(!empty($_GET['id'])){
$submission_id = $_GET['id'];
$query = $db->find("
SELECT
*
FROM
`submissions`
WHERE id = '{$submission_id}'
LIMIT 1
");
}
else {
$query = $db->find("
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
");
}
if($query) {
return $query[0];
}
else {
$query = $db->find("
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
");
}
}
Here is the PDO connector:
$host = 'localhost';
$username = '';
$pass = '';
$db = '';
try {
$dbh = new PDO("mysql:host=$host;dbname=$db", $username, $pass);
} catch (PDOException $e) {
echo $e->getMessage();
}
Here is what I've tried to convert it to, but it's just plain wrong. I think I need to be returning a PDO associative array in the 2nd if statement, but am not sure.
function getRandomSubmission() {
global $dbh;
if(!empty($_GET['id'])){
$submission_id = $_GET['id'];
$stmt = $dbh->prepare('
SELECT
*
FROM
`submissions`
WHERE
`id` = ?
LIMIT 1
');
$stmt->bindParam(1, $submission_id, PDO::PARAM_INT);
$stmt->execute();
}
else {
$stmt = $dbh->prepare('
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
');
$stmt->execute();
}
if($stmt) {
return $stmt[0];
}
else {
$stmt = $dbh->prepare('
SELECT
*
FROM
`submissions`
ORDER BY RAND()
LIMIT 1
');
$stmt->execute();
}
}
The original one works as intended, however (I realize I left the connection details blank).
You need to call fetch method of the PDOStatement object:
return $stmt->fetch()
Read about the fetch style, really you don't need FETCH_BOTH ;-)