109
public function open($savePath, $sessionName)
111
//$this->log->debug('Session open');
112
$this->maxLifetime = ini_get('session.gc_maxlifetime');
119
public function close()
121
//$this->log->debug('Session close');
126
} catch (\PDOException $e) {
127
$this->log->error('Error closing session: %s', $e->getMessage());
132
// Prune this session if necessary
133
if ($this->pruneKey || $this->gcCalled) {
134
$db = new PdoStorageService($this->log);
135
$db->setConnection();
137
if ($this->pruneKey) {
138
$db->update('DELETE FROM `session` WHERE session_id = :session_id', array('session_id' => $this->key));
141
if ($this->gcCalled) {
142
// Delete sessions older than 10 times the max lifetime
143
$db->update('DELETE FROM `session` WHERE IsExpired = 1 AND session_expiration < :expiration', array('expiration' => (time() - ($this->maxLifetime * 10))));
145
// Update expired sessions as expired
146
$db->update('UPDATE `session` SET IsExpired = 1 WHERE session_expiration < :expiration', array('expiration' => time()));
149
$db->commitIfNecessary();
153
} catch (\PDOException $e) {
154
$this->log->error('Error closing session: %s', $e->getMessage());
158
$this->getDb()->close();
60
function open($save_path, $session_name)
62
$this->max_lifetime = ini_get('session.gc_maxlifetime');
69
$this->gc($this->max_lifetime);
166
73
function read($key)
168
//$this->log->debug('Session read');
75
$userAgent = substr(Sanitize::string($_SERVER['HTTP_USER_AGENT']), 0, 253);
76
$remoteAddr = Sanitize::string($_SERVER['REMOTE_ADDR']);
77
$securityToken = Sanitize::getString('SecurityToken');
171
79
$this->key = $key;
80
$newExp = time() + $this->max_lifetime;
173
$userAgent = substr($_SERVER['HTTP_USER_AGENT'], 0, 253);
82
$this->gc($this->max_lifetime);
176
$dbh = $this->getDb();
178
// Start a transaction
179
$this->beginTransaction();
85
$dbh = PDOConnect::init();
181
87
// Get this session
182
$sth = $dbh->getConnection()->prepare('
183
SELECT `session_data`, `isexpired`, `useragent`, `session_expiration`, `userId`
185
WHERE `session_id` = :session_id
187
$sth->execute(['session_id' => $key]);
88
$sth = $dbh->prepare('SELECT session_data, isexpired, securitytoken, useragent FROM session WHERE session_id = :session_id');
89
$sth->execute(array('session_id' => $key));
91
if (!$row = $sth->fetch())
92
return settype($empty, "string");
94
// What happens if the UserAgent has changed?
95
if ($row['useragent'] != $userAgent) {
96
// Make sure we are logged out (delete all data)
97
$usth = $dbh->prepare('DELETE FROM session WHERE session_id = :session_id');
98
$usth->execute(array('session_id' => $key));
100
throw new \Exception('Different UserAgent');
103
// We have the Key and the Remote Address.
104
if ($securityToken == null) {
105
// If there is no security token then obey the IsExpired
106
$this->isExpired = $row['isexpired'];
107
} elseif ($securityToken == $row['securitytoken']) {
108
// We have a security token, so dont require a login
109
$this->isExpired = 0;
111
$usth = $dbh->prepare('UPDATE session SET session_expiration = :expiry, isExpired = 0 WHERE session_id = :session_id');
112
$usth->execute(array('session_id' => $key, 'expiry' => $newExp));
114
// Its set - but its wrong - not good
115
Log::error('Incorrect SecurityToken from ' . $remoteAddr);
117
$this->isExpired = 1;
120
// Either way - update this SESSION so that the security token is NULL
121
$usth = $dbh->prepare('UPDATE `session` SET SecurityToken = NULL WHERE session_id = :session_id');
122
$usth->execute(array('session_id' => $key));
124
return ($row['session_data']);
125
} catch (\Exception $e) {
126
Log::error($e->getMessage());
128
return settype($empty, "string");
132
function write($key, $val)
134
$newExp = time() + $this->max_lifetime;
135
$lastaccessed = date("Y-m-d H:i:s");
137
$userAgent = substr(Sanitize::getString('HTTP_USER_AGENT', 'No user agent', $_SERVER), 0, 253);
138
$remoteAddr = Sanitize::getString('REMOTE_ADDR');
141
$dbh = PDOConnect::init();
143
$sth = $dbh->prepare('SELECT session_id FROM session WHERE session_id = :session_id');
144
$sth->execute(array('session_id' => $key));
189
146
if (!$row = $sth->fetch()) {
191
$this->insertSession($key, '', time(), time() + $this->maxLifetime);
193
$this->expired = false;
147
// Insert a new session
148
$SQL = 'INSERT INTO `session` (session_id, session_data, session_expiration, lastaccessed, lastpage, userid, isexpired, useragent, remoteaddr)
149
VALUES (:session_id, :session_data, :session_expiration, :lastaccessed, :lastpage, :userid, :isexpired, :useragent, :remoteaddr) ';
151
$isth = $dbh->prepare($SQL);
155
'session_id' => $key,
156
'session_data' => $val,
157
'session_expiration' => $newExp,
158
'lastaccessed' => $lastaccessed,
159
'lastpage' => 'login',
162
'useragent' => $userAgent,
163
'remoteaddr' => $remoteAddr
197
// Check the session hasn't expired
198
if ($row['session_expiration'] < time())
199
$this->expired = true;
201
$this->expired = $row['isexpired'];
203
// What happens if the UserAgent has changed?
204
if ($row['useragent'] != $userAgent) {
205
// Force delete this session
207
$this->pruneKey = true;
167
// Punch a very small hole in the authentication system
168
// we do not want to update the expiry time of a session if it is the Clock Timer going off
169
$autoRefresh = (isset($_REQUEST['autoRefresh']) && Sanitize::bool($_REQUEST['autoRefresh']));
171
if (!$this->refreshExpiry || $autoRefresh) {
173
// Update the existing session without the expiry
174
$SQL = "UPDATE session SET session_data = :session_data WHERE session_id = :session_id ";
176
$isth = $dbh->prepare($SQL);
179
array('session_id' => $key, 'session_data' => $val)
182
// Update the existing session
183
$SQL = "UPDATE `session` SET
184
session_data = :session_data,
185
session_expiration = :session_expiration,
186
lastaccessed = :lastaccessed,
187
remoteaddr = :remoteaddr
188
WHERE session_id = :session_id ";
190
$isth = $dbh->prepare($SQL);
194
'session_id' => $key,
195
'session_data' => $val,
196
'session_expiration' => $newExp,
197
'lastaccessed' => $lastaccessed,
198
'remoteaddr' => $remoteAddr
210
$this->userId = $row['userId'];
211
$this->sessionExpiry = $row['session_expiration'];
213
// Set the session data (expired or not)
214
$data = $row['session_data'];
217
return (string)$data;
219
} catch (\Exception $e) {
220
$this->log->error('Error reading session: %s', $e->getMessage());
222
return (string)$data;
229
public function write($key, $val)
231
//$this->log->debug('Session write');
233
// What should we do with expiry?
234
$expiry = ($this->refreshExpiry) ? time() + $this->maxLifetime : $this->sessionExpiry;
237
$this->updateSession($key, $val, time(), $expiry);
239
} catch (\PDOException $e) {
240
$this->log->error('Error writing session data: %s', $e->getMessage());
250
public function destroy($key)
252
//$this->log->debug('Session destroy');
254
$this->getDb()->update('DELETE FROM `session` WHERE session_id = :session_id', ['session_id' => $key]);
255
} catch (\PDOException $e) {
256
$this->log->error('Error destroying session: %s', $e->getMessage());
265
public function gc($maxLifetime)
267
//$this->log->debug('Session gc');
268
$this->gcCalled = true;
276
public function setUser($userId)
278
//$this->log->debug('Setting user Id to %d', $userId);
279
$_SESSION['userid'] = $userId;
280
$this->userId = $userId;
203
} catch (\Exception $e) {
204
Log::error($e->getMessage());
211
function destroy($key)
214
$dbh = PDOConnect::init();
216
$sth = $dbh->prepare('UPDATE session SET IsExpired = 1 WHERE session_id = :session_id');
217
$sth->execute(array('session_id', $key));
218
} catch (\Exception $e) {
219
Log::error($e->getMessage());
225
function gc($max_lifetime)
228
$dbh = PDOConnect::init();
230
// Delete sessions older than 10 times the max lifetime
231
$sth = $dbh->prepare('DELETE FROM `session` WHERE IsExpired = 1 AND session_expiration < :expiration');
232
$sth->execute(array('expiration' => (time() - ($max_lifetime * 10))));
234
// Update expired sessions as expired
235
$sth = $dbh->prepare('UPDATE `session` SET IsExpired = 1 WHERE session_expiration < :expiration');
236
$sth->execute(array('expiration' => time()));
237
} catch (\Exception $e) {
238
Log::error($e->getMessage());
242
function setUser($key, $userid)
244
$_SESSION['userid'] = $userid;
247
$dbh = PDOConnect::init();
249
// Delete sessions older than 10 times the max lifetime
250
$sth = $dbh->prepare('UPDATE `session` SET userid = :userid WHERE session_id = :session_id');
251
$sth->execute(array('session_id' => $key, 'userid' => $userid));
252
} catch (\Exception $e) {
253
Log::error($e->getMessage());
284
259
* Updates the session ID with a new one
286
public function regenerateSessionId()
288
//$this->log->debug('Session regenerate');
289
session_regenerate_id(true);
291
$this->key = session_id();
293
// PHP7 calls open/close on regenerate
295
if (version_compare(phpversion(), '7.0') === -1) {
296
$this->insertSession($this->key, '', time(), time() + $this->maxLifetime);
301
* Set this session to expired
304
public function setIsExpired($isExpired)
306
$this->expired = $isExpired;
261
public function regenerateSessionId($oldSessionID)
264
session_regenerate_id(false);
266
$new_sess_id = session_id();
268
$this->key = $new_sess_id;
271
$dbh = PDOConnect::init();
273
// Delete sessions older than 10 times the max lifetime
274
$sth = $dbh->prepare('UPDATE session SET session_id = :new_session_id WHERE session_id = :session_id');
275
$sth->execute(array('session_id' => $oldSessionID, 'new_session_id' => $new_sess_id));
276
} catch (\Exception $e) {
277
Log::error($e->getMessage());
282
function setPage($key, $lastpage)
284
$_SESSION['pagename'] = $lastpage;
287
$dbh = PDOConnect::init();
289
// Delete sessions older than 10 times the max lifetime
290
$sth = $dbh->prepare('UPDATE session SET lastpage = :lastpage WHERE session_id = :session_id');
291
$sth->execute(array('session_id' => $key, 'lastpage' => $lastpage));
292
} catch (\Exception $e) {
293
Log::error($e->getMessage());
298
function setIsExpired($isExpired)
300
$this->isExpired = $isExpired;
303
$dbh = PDOConnect::init();
305
// Delete sessions older than 10 times the max lifetime
306
$sth = $dbh->prepare('UPDATE session SET isexpired = :isexpired WHERE session_id = :session_id');
307
$sth->execute(array('session_id' => $this->key, 'isexpired' => $isExpired));
308
} catch (\Exception $e) {
309
Log::error($e->getMessage());
350
* Is the session expired?
353
public function isExpired()
355
return $this->expired;
360
* @return PdoStorageService
362
private function getDb()
364
if ($this->pdo == null)
365
$this->pdo = (new PdoStorageService($this->log))->setConnection();
371
* Helper method to begin a transaction.
373
* MySQLs default isolation, REPEATABLE READ, causes deadlock for different sessions
374
* due to http://www.mysqlperformanceblog.com/2013/12/12/one-more-innodb-gap-lock-to-avoid/ .
375
* So we change it to READ COMMITTED.
377
private function beginTransaction()
379
if (!$this->getDb()->getConnection()->inTransaction() && DBVERSION > 122) {
381
$this->getDb()->getConnection()->exec('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
382
} catch (\PDOException $e) {
383
// https://github.com/xibosignage/xibo/issues/787
384
// this only works if BINLOG format is set to MIXED or ROW
385
$this->log->error('Unable to set session transaction isolation level, message = ' . $e->getMessage());
387
$this->getDb()->getConnection()->beginTransaction();
394
private function commit()
396
if ($this->getDb()->getConnection()->inTransaction())
397
$this->getDb()->getConnection()->commit();
404
* @param $lastAccessed
407
private function insertSession($key, $data, $lastAccessed, $expiry)
409
//$this->log->debug('Session insert');
412
INSERT INTO `session` (session_id, session_data, session_expiration, lastaccessed, userid, isexpired, useragent, remoteaddr)
413
VALUES (:session_id, :session_data, :session_expiration, :lastAccessed, :userId, :expired, :useragent, :remoteaddr)
417
'session_id' => $key,
418
'session_data' => $data,
419
'session_expiration' => $expiry,
420
'lastAccessed' => date('Y-m-d H:i:s', $lastAccessed),
421
'userId' => $this->userId,
422
'expired' => ($this->expired) ? 1 : 0,
423
'useragent' => substr($_SERVER['HTTP_USER_AGENT'], 0, 253),
424
'remoteaddr' => $_SERVER['REMOTE_ADDR']
427
$this->getDb()->update($sql, $params);
434
* @param $lastAccessed
437
private function updateSession($key, $data, $lastAccessed, $expiry)
439
//$this->log->debug('Session update');
443
session_data = :session_data,
444
session_expiration = :session_expiration,
445
LastAccessed = :lastAccessed,
448
WHERE session_id = :session_id
452
'session_data' => $data,
453
'session_expiration' => $expiry,
454
'lastAccessed' => date('Y-m-d H:i:s', $lastAccessed),
455
'userId' => $this->userId,
456
'expired' => ($this->expired) ? 1 : 0,
460
$this->getDb()->update($sql, $params);
b'\\ No newline at end of file'