views:

825

answers:

4

Hello, i've implemented this custom PHP Session Class for storing sessions into a MySQL database:

class Session
{
    private $_session;
    public $maxTime;
    private $database;
    public function __construct(mysqli $database)
    {
        $this->database=$database;
        $this->maxTime['access'] = time();
        $this->maxTime['gc'] = get_cfg_var('session.gc_maxlifetime');

        session_set_save_handler(array($this,'_open'),
                array($this,'_close'),
                array($this,'_read'),
                array($this,'_write'),
                array($this,'_destroy'),
                array($this,'_clean')
                );

        register_shutdown_function('session_write_close');

        session_start();//SESSION START

    }

    public function _open()
    {
        return true;
    }

    public function _close()
    {
        $this->_clean($this->maxTime['gc']);
    }

    public function _read($id)
    {
        $getData= $this->database->prepare("SELECT data FROM 
                                            Sessions AS Session
                                            WHERE Session.id = ?");
        $getData->bind_param('s',$id);
        $getData->execute();

        $allData= $getData->fetch();
        $totalData = count($allData);
        $hasData=(bool) $totalData >=1;

        return $hasData ? $allData['data'] : '';
    }

    public function _write($id, $data)
    {
        $getData = $this->database->prepare("REPLACE INTO
            Sessions
            VALUES (?, ?, ?)");
        $getData->bind_param('sss', $id, $this->maxTime['access'], $data);

        return $getData->execute();
    }

    public function _destroy($id)
    {
        $getData=$this->database->prepare("DELETE FROM
            Sessions
            WHERE id = ?");
        $getData->bind_param('S', $id);
        return $getData->execute();
    }

    public function _clean($max)
    {
        $old=($this->maxTime['access'] - $max);

        $getData = $this->database->prepare("DELETE FROM Sessions WHERE access < ?");
        $getData->bind_param('s', $old);
        return $getData->execute();
    }
}

It works well but i don't really know how to properly access the $_SESSION array: For example:

$db=new DBClass();//This is a custom database class
$session=new Session($db->getConnection());
if (isset($_SESSION['user']))
{
    echo($_SESSION['user']);//THIS IS NEVER EXECUTED!
}
else
{
    $_SESSION['user']="test";
    Echo("Session created!");
}

At every page refresh it seems that $_SESSION['user'] is somehow "resetted", what methods can i apply to prevent such behaviour?

+2  A: 

Maybe you need to start a session first?

The MYYN
Doesn't this work `session_start();//SESSION START`
Peter Lindqvist
session_start() is being called in the Constructor of the Session class.As long as he creates an instance of the Session class first, shouldn't this be sufficient?
Addsy
Yes, i start it from the Constructor...
Gianluca Bargelli
A: 

I have had it before where sessions don't seem to persist as they should

You could try checking your sessionid stays the same when you change page and if not set it manually.

var_dump(session_id());

if (session_id()=="")
{
    if ($_GET["sessionid"])
    {
        session_id($_GET["sessionid"]);
    }
    elseif ($_POST["sessionid"])
    {
        session_id($_POST["sessionid"]);
    }

    session_start();
}

This is more of a test to see if this is the problem tho. I'm not sure what the security implications would be of setting the session id from the query string but I suspect they are not good!

Addsy
Yes, the sessionid stay the same after every page refresh...i wonder if creating a new Session Object at every refresh IS the actual problem (the Constructor calls session_start() everytime)...!
Gianluca Bargelli
A: 

mysqli_stmt::fetch() doesn't return an array representing the row, it only returns true or false. Therefore your code in _read():

$allData= $getData->fetch();
$totalData = count($allData);
$hasData=(bool) $totalData >=1;
return $hasData ? $allData['data'] : '';
cannot work. $allData will either be true or false and there is no array element $allData['data']. http://docs.php.net/mysqli-stmt.fetch says:
Fetch the result from a prepared statement into the variables bound by mysqli_stmt_bind_result().
  public function _read($id)
  {
    $getData= $this->database->prepare("SELECT data FROM
      Sessions AS Session
      WHERE Session.id = ?
    ");
    if ( false===$getData ) {
      // now what?
    }

    $getData->bind_param('s',$id);
    $getData->bind_result($data);
    if ( false===$getData->execute() ) {
      // now what?
    }
    return  $getData->fetch() ? $data : '';
  }
VolkerK
Thank you very much VolkerK, now it works! You're amazing!
Gianluca Bargelli
Guess i should read more carefully PHP Doc in the future...thanks again everybody!
Gianluca Bargelli
+1  A: 

Here's the updated code!!! :-) Now it's fully working!!!

<?php
class session {
    private $_session;
    public $maxTime;
    private $db;
    public function __construct() {
        $this->maxTime['access'] = time();
        $this->maxTime['gc'] = 21600; //21600 = 6 hours

        //it is session handler
        session_set_save_handler(array($this,'_open'),
                array($this,'_close'),
                array($this,'_read'),
                array($this,'_write'),
                array($this,'_destroy'),
                array($this,'_clean')
                );

        register_shutdown_function('session_write_close');

        session_start();//SESSION START
    }

    private function getDB() {
        $mysql_host = 'your_host';
        $mysql_user = 'user';
        $mysql_password = 'pass';
        $mysql_db_name = 'db_name';


        if (!isset($this->db)) {
            $this->db = new mysqli($mysql_host, $mysql_user, $mysql_password, $mysql_db_name);
            if (mysqli_connect_errno()) {
                printf("Error no connection: <br />%s\n", mysqli_connect_error());
                exit();
            }
        }

        return $this->db;
    }

    // O_O !!!
    public function _open() {
        return true;
    }


    public function _close() {
        $this->_clean($this->maxTime['gc']);
    }

    public function _read($id)  {       
        $stmt= $this->getDB()->prepare("SELECT session_variable FROM table_sessions 
                                            WHERE table_sessions.session_id = ?");
        $stmt->bind_param('s',$id);
        $stmt->bind_result($data);
        $stmt->execute();
        $ok = $stmt->fetch() ? $data : '';
        $stmt->close();
        return $ok;
    }

    public function _write($id, $data) {    
        $stmt = $this->getDB()->prepare("REPLACE INTO table_sessions (session_id, session_variable, session_access) VALUES (?, ?, ?)");
        $stmt->bind_param('ssi', $id, $data, $this->maxTime['access']);
        $ok = $stmt->execute();
        $stmt->close();
        return $ok;     
    }

    public function _destroy($id) {
    $stmt=$this->getDB()->prepare("DELETE FROM table_sessions WHERE session_id = ?");
    $stmt->bind_param('s', $id);
    $ok = $stmt->execute();
    $stmt->close();
    return $ok;
    }

    public function _clean($max) {
    $old=($this->maxTime['access'] - $max);
    $stmt = $this->getDB()->prepare("DELETE FROM table_sessions WHERE session_access < ?");
    $stmt->bind_param('s', $old);
    $ok = $stmt->execute();
    $stmt->close();
    return $ok;
    }
}
?>

Here's the session table :

CREATE TABLE IF NOT EXISTS `table_sessions` (
  `session_id` varchar(50) NOT NULL,
  `session_variable` text NOT NULL,
  `session_access` decimal(15,0) NOT NULL,
  PRIMARY KEY  (`session_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
zizzamia
Thanks, now people can use it properly ;)
Gianluca Bargelli