Through a Handler of custom sessions you can do this because you can perform a different routine at each stage of the session: opening, closing, reading, recording, removing and garbaging.
To create a custom session handler use the function session_set_save_handler()
Handler below, based on Mysqli, will use a simple SQL framework:
CREATE TABLE `session_data` (
`id` varchar(32) NOT NULL,
`data` text,
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8_unicode_ci;
The Handler:
class SessionSaveHandler {
protected $link;
protected $table;
protected $sessionName = 'session';
protected $maxLifeTime = 3600;
public function __construct( $user = null, $pass = null, $host = null, $db = null, $table = null, $sessionName = null ) {
$this -> link = mysqli_connect( $host, $user, $pass, $db );
if( ! $this -> link ) {
throw new Exception( 'Could not connect to the database!' );
}
mysqli_select_db( $this -> link, $db );
session_set_save_handler(
array( $this, 'open' ),
array( $this, 'close' ),
array( $this, 'read' ),
array( $this, 'write' ),
array( $this, 'destroy' ),
array( $this, 'gc' )
);
$this -> table = $table;
session_name( $this -> sessionName );
session_start();
}
public function open( $savePath, $sessionName ) {
$this -> sessionName = $sessionName;
return TRUE;
}
public function close() {
return true;
}
public function read( $id ) {
$query = sprintf(
'SELECT `data` FROM %s WHERE `id` = ? AND UNIX_TIMESTAMP( `last_updated` ) + %d > UNIX_TIMESTAMP( NOW() )',
$this -> table, $this -> maxLifeTime
);
$stmt = mysqli_prepare( $this -> link, $query );
mysqli_stmt_bind_param( $stmt, 's', $id );
if( mysqli_execute( $stmt ) ) {
mysqli_stmt_bind_result( $stmt, $retval );
mysqli_stmt_fetch( $stmt );
if( ! empty( $retval ) ) return $retval;
}
return '';
}
public function write( $id, $data ) {
$query = sprintf(
'INSERT INTO %s (id, data) VALUES (?, ?) ON DUPLICATE KEY UPDATE data = ?, last_updated=NULL',
$this -> table
);
$stmt = mysqli_prepare( $this -> link, $query );
mysqli_stmt_bind_param( $stmt, 'sss', $id, $data, $data );
return mysqli_execute( $stmt );
}
public function destroy( $id ) {
$query = sprintf( 'DELETE FROM %s WHERE id = ?', $this -> table );
$stmt = mysqli_prepare( $this -> link, $query );
mysqli_stmt_bind_param( $stmt, 's', $id );
return mysqli_execute( $stmt );
}
public function gc( $maxlifetime ) {
$query = sprintf(
'DELETE FROM %s WHERE UNIX_TIMESTAMP( last_updated ) + %d <= UNIX_TIMESTAMP( NOW() )',
$this -> table, $this -> maxLifeTime
);
mysqli_query( $this -> link, $query );
return;
}
}
And its use:
require_once 'handler.php';
new SessionSaveHandler( 'root', '7v4h6q7t', 'localhost', 'session', 'session_data' );
$_SESSION['name'] = 'Bruno Augusto'; // write
$_SESSION['age'] = 26; // write
var_dump( $_SESSION['name'] ); // read
unset( $_SESSION['age'] );
var_dump( $_SESSION ); // proof
That one Handler generic allows session data to be recorded, read and manipulated in a database. Point!
Now, what do you say really the scope of the topic is precisely to customize the behavior. For example, just add a new column to the table to make the condition according to the reference link that raised the doubt and modify the queries of the methods Sessionhandler::write() and Sessionhandler::read() (for safety) to take account of it.
This way when creating the session variable, thus triggering the method Sessionhandler::write() the index shall be created only if the condition of existence is satisfied.
And thanks to her, when checking if the session index exists to free up access to a given page, even having been created, everything is solved practically by itself.
I want to see how to save the session without a cookie (you can do it, but you have to pass the ID through the URL). I find it much easier to let you always log in, but every time you log in, kill the previous session. Much simpler, without danger of locking itself out, and without the risk of simultaneous use. Now, the strong impression I have is that this may even have some legitimate application, but it probably serves to cover some other application failure.
– Bacco
No cookie, I think, just like this: http://stackoverflow.com/a/3643602
– Franchesco
@Bacco liked the idea you don’t want to formulate an answer?
– Jorge B.
@Jorgeb. To tell you the truth, if I was going to answer, I would prefer to use that other one, first for the restriction of cookies, which I don’t think has much to do with the problem, and despite minor differences in the formulation, I think in the end is the same question. Actually I wouldn’t even have much to add besides the comment I made, it would be basically that. Logou, invalidates the previous login, only. For example, associating the session ID to the user ID. If not.
– Bacco