mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 14:27:22 +01:00
Merge branch 'MDL-30026' of git://github.com/stronk7/moodle
This commit is contained in:
commit
da2e3c12db
@ -433,6 +433,7 @@ $string['secretalreadyused'] = 'Change password confirmation link was already us
|
||||
$string['sectionnotexist'] = 'This section does not exist';
|
||||
$string['sendmessage'] = 'Send message';
|
||||
$string['servicedonotexist'] = 'The service does not exist';
|
||||
$string['sessionwaiterr'] = 'Timed out while waiting for session lock.<br />Wait for your current requests to finish and try again later.';
|
||||
$string['sessioncookiesdisable'] = 'Incorrect use of require_key_login() - session cookies must be disabled!';
|
||||
$string['sessiondiskfull'] = 'The session partition is full. It is not possible to login at this time.<br /><br />Please notify server administrator.';
|
||||
$string['sessionerroruser'] = 'Your session has timed out. Please login again.';
|
||||
|
@ -2204,9 +2204,10 @@ abstract class moodle_database {
|
||||
/**
|
||||
* Obtain session lock
|
||||
* @param int $rowid id of the row with session record
|
||||
* @param int $timeout max allowed time to wait for the lock in seconds
|
||||
* @return bool success
|
||||
*/
|
||||
public function get_session_lock($rowid) {
|
||||
public function get_session_lock($rowid, $timeout) {
|
||||
$this->used_for_db_sessions = true;
|
||||
}
|
||||
|
||||
|
@ -1227,18 +1227,46 @@ s only returning name of SQL substring function, it now requires all parameters.
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_session_lock($rowid) {
|
||||
/**
|
||||
* Obtain session lock
|
||||
* @param int $rowid id of the row with session record
|
||||
* @param int $timeout max allowed time to wait for the lock in seconds
|
||||
* @return bool success
|
||||
*/
|
||||
public function get_session_lock($rowid, $timeout) {
|
||||
if (!$this->session_lock_supported()) {
|
||||
return;
|
||||
}
|
||||
parent::get_session_lock($rowid);
|
||||
parent::get_session_lock($rowid, $timeout);
|
||||
|
||||
$timeoutmilli = $timeout * 1000;
|
||||
|
||||
$fullname = $this->dbname.'-'.$this->prefix.'-session-'.$rowid;
|
||||
$sql = "sp_getapplock '$fullname', 'Exclusive', 'Session', 120000";
|
||||
// There is one bug in PHP/freetds (both reproducible with mssql_query()
|
||||
// and its mssql_init()/mssql_bind()/mssql_execute() alternative) for
|
||||
// stored procedures, causing scalar results of the execution
|
||||
// to be cast to boolean (true/fals). Here there is one
|
||||
// workaround that forces the return of one recordset resource.
|
||||
// $sql = "sp_getapplock '$fullname', 'Exclusive', 'Session', $timeoutmilli";
|
||||
$sql = "BEGIN
|
||||
DECLARE @result INT
|
||||
EXECUTE @result = sp_getapplock @Resource='$fullname',
|
||||
@LockMode='Exclusive',
|
||||
@LockOwner='Session',
|
||||
@LockTimeout='$timeoutmilli'
|
||||
SELECT @result
|
||||
END";
|
||||
$this->query_start($sql, null, SQL_QUERY_AUX);
|
||||
$result = mssql_query($sql, $this->mssql);
|
||||
$this->query_end($result);
|
||||
|
||||
if ($result) {
|
||||
$row = mssql_fetch_row($result);
|
||||
if ($row[0] < 0) {
|
||||
throw new dml_sessionwait_exception();
|
||||
}
|
||||
}
|
||||
|
||||
$this->free_result($result);
|
||||
}
|
||||
|
||||
|
@ -1203,10 +1203,17 @@ class mysqli_native_moodle_database extends moodle_database {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_session_lock($rowid) {
|
||||
parent::get_session_lock($rowid);
|
||||
/**
|
||||
* Obtain session lock
|
||||
* @param int $rowid id of the row with session record
|
||||
* @param int $timeout max allowed time to wait for the lock in seconds
|
||||
* @return bool success
|
||||
*/
|
||||
public function get_session_lock($rowid, $timeout) {
|
||||
parent::get_session_lock($rowid, $timeout);
|
||||
|
||||
$fullname = $this->dbname.'-'.$this->prefix.'-session-'.$rowid;
|
||||
$sql = "SELECT GET_LOCK('$fullname',120)";
|
||||
$sql = "SELECT GET_LOCK('$fullname', $timeout)";
|
||||
$this->query_start($sql, null, SQL_QUERY_AUX);
|
||||
$result = $this->mysqli->query($sql);
|
||||
$this->query_end($result);
|
||||
@ -1218,8 +1225,7 @@ class mysqli_native_moodle_database extends moodle_database {
|
||||
if (reset($arr) == 1) {
|
||||
return;
|
||||
} else {
|
||||
// try again!
|
||||
$this->get_session_lock($rowid);
|
||||
throw new dml_sessionwait_exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1610,19 +1610,28 @@ class oci_native_moodle_database extends moodle_database {
|
||||
return $this->dblocks_supported;
|
||||
}
|
||||
|
||||
public function get_session_lock($rowid) {
|
||||
/**
|
||||
* Obtain session lock
|
||||
* @param int $rowid id of the row with session record
|
||||
* @param int $timeout max allowed time to wait for the lock in seconds
|
||||
* @return bool success
|
||||
*/
|
||||
public function get_session_lock($rowid, $timeout) {
|
||||
if (!$this->session_lock_supported()) {
|
||||
return;
|
||||
}
|
||||
parent::get_session_lock($rowid);
|
||||
parent::get_session_lock($rowid, $timeout);
|
||||
|
||||
$fullname = $this->dbname.'-'.$this->prefix.'-session-'.$rowid;
|
||||
$sql = 'SELECT MOODLE_LOCKS.GET_LOCK(:lockname, :locktimeout) FROM DUAL';
|
||||
$params = array('lockname' => $fullname , 'locktimeout' => 120);
|
||||
$params = array('lockname' => $fullname , 'locktimeout' => $timeout);
|
||||
$this->query_start($sql, $params, SQL_QUERY_AUX);
|
||||
$stmt = $this->parse_query($sql);
|
||||
$this->bind_params($stmt, $params);
|
||||
$result = oci_execute($stmt, $this->commit_status);
|
||||
if ($result === false) { // Any failure in get_lock() raises error, causing return of bool false
|
||||
throw new dml_sessionwait_exception();
|
||||
}
|
||||
$this->query_end($result, $stmt);
|
||||
oci_free_statement($stmt);
|
||||
}
|
||||
|
@ -1153,7 +1153,13 @@ class pgsql_native_moodle_database extends moodle_database {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_session_lock($rowid) {
|
||||
/**
|
||||
* Obtain session lock
|
||||
* @param int $rowid id of the row with session record
|
||||
* @param int $timeout max allowed time to wait for the lock in seconds
|
||||
* @return bool success
|
||||
*/
|
||||
public function get_session_lock($rowid, $timeout) {
|
||||
// NOTE: there is a potential locking problem for database running
|
||||
// multiple instances of moodle, we could try to use pg_advisory_lock(int, int),
|
||||
// luckily there is not a big chance that they would collide
|
||||
@ -1161,9 +1167,40 @@ class pgsql_native_moodle_database extends moodle_database {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::get_session_lock($rowid);
|
||||
parent::get_session_lock($rowid, $timeout);
|
||||
|
||||
$timeoutmilli = $timeout * 1000;
|
||||
|
||||
$sql = "SET statement_timeout TO $timeoutmilli";
|
||||
$this->query_start($sql, null, SQL_QUERY_AUX);
|
||||
$result = pg_query($this->pgsql, $sql);
|
||||
$this->query_end($result);
|
||||
|
||||
if ($result) {
|
||||
pg_free_result($result);
|
||||
}
|
||||
|
||||
$sql = "SELECT pg_advisory_lock($rowid)";
|
||||
$this->query_start($sql, null, SQL_QUERY_AUX);
|
||||
$start = time();
|
||||
$result = pg_query($this->pgsql, $sql);
|
||||
$end = time();
|
||||
try {
|
||||
$this->query_end($result);
|
||||
} catch (dml_exception $ex) {
|
||||
if ($end - $start >= $timeout) {
|
||||
throw new dml_sessionwait_exception();
|
||||
} else {
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
pg_free_result($result);
|
||||
}
|
||||
|
||||
$sql = "SET statement_timeout TO DEFAULT";
|
||||
$this->query_start($sql, null, SQL_QUERY_AUX);
|
||||
$result = pg_query($this->pgsql, $sql);
|
||||
$this->query_end($result);
|
||||
|
||||
|
@ -4137,6 +4137,50 @@ class dml_test extends UnitTestCase {
|
||||
$DB2->dispose();
|
||||
}
|
||||
|
||||
public function test_session_locks() {
|
||||
$DB = $this->tdb;
|
||||
$dbman = $DB->get_manager();
|
||||
|
||||
// Open second connection
|
||||
$cfg = $DB->export_dbconfig();
|
||||
if (!isset($cfg->dboptions)) {
|
||||
$cfg->dboptions = array();
|
||||
}
|
||||
$DB2 = moodle_database::get_driver_instance($cfg->dbtype, $cfg->dblibrary);
|
||||
$DB2->connect($cfg->dbhost, $cfg->dbuser, $cfg->dbpass, $cfg->dbname, $cfg->prefix, $cfg->dboptions);
|
||||
|
||||
// Testing that acquiring a lock efectively locks
|
||||
// Get a session lock on connection1
|
||||
$rowid = rand(100, 200);
|
||||
$timeout = 1;
|
||||
$DB->get_session_lock($rowid, $timeout);
|
||||
|
||||
// Try to get the same session lock on connection2
|
||||
try {
|
||||
$DB2->get_session_lock($rowid, $timeout);
|
||||
$DB2->release_session_lock($rowid); // Should not be excuted, but here for safety
|
||||
$this->fail('An Exception is missing, expected due to session lock acquired.');
|
||||
} catch (exception $e) {
|
||||
$this->assertTrue($e instanceof dml_sessionwait_exception);
|
||||
$DB->release_session_lock($rowid); // Release lock on connection1
|
||||
}
|
||||
|
||||
// Testing that releasing a lock efectively frees
|
||||
// Get a session lock on connection1
|
||||
$rowid = rand(100, 200);
|
||||
$timeout = 1;
|
||||
$DB->get_session_lock($rowid, $timeout);
|
||||
// Release the lock on connection1
|
||||
$DB->release_session_lock($rowid);
|
||||
|
||||
// Get the just released lock on connection2
|
||||
$DB2->get_session_lock($rowid, $timeout);
|
||||
// Release the lock on connection2
|
||||
$DB2->release_session_lock($rowid);
|
||||
|
||||
$DB2->dispose();
|
||||
}
|
||||
|
||||
public function test_bound_param_types() {
|
||||
$DB = $this->tdb;
|
||||
$dbman = $DB->get_manager();
|
||||
|
@ -1286,17 +1286,33 @@ class sqlsrv_native_moodle_database extends moodle_database {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_session_lock($rowid) {
|
||||
/**
|
||||
* Obtain session lock
|
||||
* @param int $rowid id of the row with session record
|
||||
* @param int $timeout max allowed time to wait for the lock in seconds
|
||||
* @return bool success
|
||||
*/
|
||||
public function get_session_lock($rowid, $timeout) {
|
||||
if (!$this->session_lock_supported()) {
|
||||
return;
|
||||
}
|
||||
parent::get_session_lock($rowid);
|
||||
parent::get_session_lock($rowid, $timeout);
|
||||
|
||||
$timeoutmilli = $timeout * 1000;
|
||||
|
||||
$fullname = $this->dbname.'-'.$this->prefix.'-session-'.$rowid;
|
||||
$sql = "sp_getapplock '$fullname', 'Exclusive', 'Session', 120000";
|
||||
$sql = "sp_getapplock '$fullname', 'Exclusive', 'Session', $timeoutmilli";
|
||||
$this->query_start($sql, null, SQL_QUERY_AUX);
|
||||
$result = sqlsrv_query($this->sqlsrv, $sql);
|
||||
$this->query_end($result);
|
||||
|
||||
if ($result) {
|
||||
$row = sqlsrv_fetch_array($result);
|
||||
if ($row[0] < 0) {
|
||||
throw new dml_sessionwait_exception();
|
||||
}
|
||||
}
|
||||
|
||||
$this->free_result($result);
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,18 @@ class dml_connection_exception extends dml_exception {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DML db session wait exception - triggered when session lock request times out.
|
||||
*/
|
||||
class dml_sessionwait_exception extends dml_exception {
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct() {
|
||||
parent::__construct('sessionwaiterr');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DML read exception - triggered by SQL syntax errors, missing tables, etc.
|
||||
*/
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@ -25,6 +24,14 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if (!defined('SESSION_ACQUIRE_LOCK_TIMEOUT')) {
|
||||
/**
|
||||
* How much time to wait for session lock before displaying error (in seconds),
|
||||
* 2 minutes by default should be a reasonable time before telling users to wait and refresh browser.
|
||||
*/
|
||||
define('SESSION_ACQUIRE_LOCK_TIMEOUT', 60*2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method returning moodle_session object.
|
||||
* @return moodle_session
|
||||
@ -39,6 +46,7 @@ function session_get_instance() {
|
||||
$CFG->sessiontimeout = 7200;
|
||||
}
|
||||
|
||||
try {
|
||||
if (defined('SESSION_CUSTOM_CLASS')) {
|
||||
// this is a hook for webservices, key based login, etc.
|
||||
if (defined('SESSION_CUSTOM_FILE')) {
|
||||
@ -55,11 +63,17 @@ function session_get_instance() {
|
||||
// legacy limited file based storage - some features and auth plugins will not work, sorry
|
||||
$session = new legacy_file_session();
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
// prevent repeated inits
|
||||
$session = new emergency_session();
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moodle session abstraction
|
||||
*
|
||||
@ -90,6 +104,53 @@ interface moodle_session {
|
||||
public function session_exists($sid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fallback session handler when standard session init fails.
|
||||
* This prevents repeated attempts to init faulty handler.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage session
|
||||
* @copyright 2011 Petr Skoda {@link http://skodak.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class emergency_session implements moodle_session {
|
||||
|
||||
public function __construct() {
|
||||
// session not used at all
|
||||
$_SESSION = array();
|
||||
$_SESSION['SESSION'] = new stdClass();
|
||||
$_SESSION['USER'] = new stdClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate current session
|
||||
* @return void
|
||||
*/
|
||||
public function terminate_current() {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* No more changes in session expected.
|
||||
* Unblocks the sessions, other scripts may start executing in parallel.
|
||||
* @return void
|
||||
*/
|
||||
public function write_close() {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for existing session with id $sid
|
||||
* @param unknown_type $sid
|
||||
* @return boolean true if session found.
|
||||
*/
|
||||
public function session_exists($sid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class handling all session and cookies related stuff.
|
||||
*
|
||||
@ -138,7 +199,8 @@ abstract class session_stub implements moodle_session {
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates active moodle session
|
||||
* Terminate current session
|
||||
* @return void
|
||||
*/
|
||||
public function terminate_current() {
|
||||
global $CFG, $SESSION, $USER, $DB;
|
||||
@ -329,11 +391,12 @@ abstract class session_stub implements moodle_session {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inits session storage.
|
||||
* Init session storage.
|
||||
*/
|
||||
protected abstract function init_session_storage();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Legacy moodle sessions stored in files, not recommended any more.
|
||||
*
|
||||
@ -343,6 +406,9 @@ abstract class session_stub implements moodle_session {
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class legacy_file_session extends session_stub {
|
||||
/**
|
||||
* Init session storage.
|
||||
*/
|
||||
protected function init_session_storage() {
|
||||
global $CFG;
|
||||
|
||||
@ -382,6 +448,7 @@ class legacy_file_session extends session_stub {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recommended moodle session storage.
|
||||
*
|
||||
@ -391,9 +458,15 @@ class legacy_file_session extends session_stub {
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class database_session extends session_stub {
|
||||
/** @var stdClass $record session record */
|
||||
protected $record = null;
|
||||
|
||||
/** @var moodle_database $database session database */
|
||||
protected $database = null;
|
||||
|
||||
/** @var bool $failed session read/init failed, do not write back to DB */
|
||||
protected $failed = false;
|
||||
|
||||
public function __construct() {
|
||||
global $DB;
|
||||
$this->database = $DB;
|
||||
@ -409,6 +482,11 @@ class database_session extends session_stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for existing session with id $sid
|
||||
* @param unknown_type $sid
|
||||
* @return boolean true if session found.
|
||||
*/
|
||||
public function session_exists($sid){
|
||||
global $CFG;
|
||||
try {
|
||||
@ -422,6 +500,9 @@ class database_session extends session_stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init session storage.
|
||||
*/
|
||||
protected function init_session_storage() {
|
||||
global $CFG;
|
||||
|
||||
@ -441,31 +522,57 @@ class database_session extends session_stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open session handler
|
||||
*
|
||||
* {@see http://php.net/manual/en/function.session-set-save-handler.php}
|
||||
*
|
||||
* @param string $save_path
|
||||
* @param string $session_name
|
||||
* @return bool success
|
||||
*/
|
||||
public function handler_open($save_path, $session_name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close session handler
|
||||
*
|
||||
* {@see http://php.net/manual/en/function.session-set-save-handler.php}
|
||||
*
|
||||
* @return bool success
|
||||
*/
|
||||
public function handler_close() {
|
||||
if (isset($this->record->id)) {
|
||||
try {
|
||||
$this->database->release_session_lock($this->record->id);
|
||||
} catch (Exception $ex) {
|
||||
// ignore any problems
|
||||
}
|
||||
}
|
||||
$this->record = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read session handler
|
||||
*
|
||||
* {@see http://php.net/manual/en/function.session-set-save-handler.php}
|
||||
*
|
||||
* @param string $sid
|
||||
* @return string
|
||||
*/
|
||||
public function handler_read($sid) {
|
||||
global $CFG;
|
||||
|
||||
if ($this->record and $this->record->sid != $sid) {
|
||||
error_log('Weird error reading database session - mismatched sid');
|
||||
$this->failed = true;
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
if ($record = $this->database->get_record('sessions', array('sid'=>$sid))) {
|
||||
$this->database->get_session_lock($record->id);
|
||||
|
||||
} else {
|
||||
if (!$record = $this->database->get_record('sessions', array('sid'=>$sid))) {
|
||||
$record = new stdClass();
|
||||
$record->state = 0;
|
||||
$record->sid = $sid;
|
||||
@ -474,14 +581,25 @@ class database_session extends session_stub {
|
||||
$record->timecreated = $record->timemodified = time();
|
||||
$record->firstip = $record->lastip = getremoteaddr();
|
||||
$record->id = $this->database->insert_record_raw('sessions', $record);
|
||||
|
||||
$this->database->get_session_lock($record->id);
|
||||
}
|
||||
} catch (dml_exception $ex) {
|
||||
} catch (Exception $ex) {
|
||||
// do not rethrow exceptions here, we need this to work somehow before 1.9.x upgrade and during install
|
||||
error_log('Can not read or insert database sessions');
|
||||
$this->failed = true;
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
$this->database->get_session_lock($record->id, SESSION_ACQUIRE_LOCK_TIMEOUT);
|
||||
} catch (Exception $ex) {
|
||||
// This is a fatal error, better inform users.
|
||||
// It should not happen very often - all pages that need long time to execute
|
||||
// should close session soon after access control checks
|
||||
error_log('Can not obtain session lock');
|
||||
$this->failed = true;
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
// verify timeout
|
||||
if ($record->timemodified + $CFG->sessiontimeout < time()) {
|
||||
$ignoretimeout = false;
|
||||
@ -504,9 +622,11 @@ class database_session extends session_stub {
|
||||
$record->timemodified = time();
|
||||
try {
|
||||
$this->database->update_record('sessions', $record);
|
||||
} catch (dml_exception $ex) {
|
||||
} catch (Exception $ex) {
|
||||
// very unlikely error
|
||||
error_log('Can not refresh database session');
|
||||
return '';
|
||||
$this->failed = true;
|
||||
throw $ex;
|
||||
}
|
||||
} else {
|
||||
//time out session
|
||||
@ -517,9 +637,11 @@ class database_session extends session_stub {
|
||||
$record->firstip = $record->lastip = getremoteaddr();
|
||||
try {
|
||||
$this->database->update_record('sessions', $record);
|
||||
} catch (dml_exception $ex) {
|
||||
} catch (Exception $ex) {
|
||||
// very unlikely error
|
||||
error_log('Can not time out database session');
|
||||
return '';
|
||||
$this->failed = true;
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -532,11 +654,28 @@ class database_session extends session_stub {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write session handler.
|
||||
*
|
||||
* {@see http://php.net/manual/en/function.session-set-save-handler.php}
|
||||
*
|
||||
* NOTE: Do not write to output or throw any exceptions!
|
||||
* Hopefully the next page is going to display nice error or it recovers...
|
||||
*
|
||||
* @param string $sid
|
||||
* @param string $session_data
|
||||
* @return bool success
|
||||
*/
|
||||
public function handler_write($sid, $session_data) {
|
||||
global $USER;
|
||||
|
||||
// TODO: MDL-20625 we need to rollback all active transactions and log error if any open needed
|
||||
|
||||
if ($this->failed) {
|
||||
// do not write anything back - we failed to start the session properly
|
||||
return false;
|
||||
}
|
||||
|
||||
$userid = 0;
|
||||
if (!empty($USER->realuser)) {
|
||||
$userid = $USER->realuser;
|
||||
@ -563,16 +702,20 @@ class database_session extends session_stub {
|
||||
try {
|
||||
$this->database->set_field('sessions', 'state', 9, array('id'=>$this->record->id));
|
||||
} catch (Exception $ignored) {
|
||||
|
||||
}
|
||||
error_log('Can not write database session - please verify max_allowed_packet is at least 4M!');
|
||||
} else {
|
||||
error_log('Can not write database session');
|
||||
}
|
||||
return false;
|
||||
} catch (Exception $ex) {
|
||||
error_log('Can not write database session');
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// session already destroyed
|
||||
// fresh new session
|
||||
try {
|
||||
$record = new stdClass();
|
||||
$record->state = 0;
|
||||
$record->sid = $sid;
|
||||
@ -583,33 +726,56 @@ class database_session extends session_stub {
|
||||
$record->id = $this->database->insert_record_raw('sessions', $record);
|
||||
$this->record = $record;
|
||||
|
||||
try {
|
||||
$this->database->get_session_lock($this->record->id);
|
||||
} catch (dml_exception $ex) {
|
||||
error_log('Can not write new database session');
|
||||
$this->database->get_session_lock($this->record->id, SESSION_ACQUIRE_LOCK_TIMEOUT);
|
||||
} catch (Exception $ex) {
|
||||
// this should not happen
|
||||
error_log('Can not write new database session or acquire session lock');
|
||||
$this->failed = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy session handler
|
||||
*
|
||||
* {@see http://php.net/manual/en/function.session-set-save-handler.php}
|
||||
*
|
||||
* @param string $sid
|
||||
* @return bool success
|
||||
*/
|
||||
public function handler_destroy($sid) {
|
||||
session_kill($sid);
|
||||
|
||||
if (isset($this->record->id) and $this->record->sid === $sid) {
|
||||
try {
|
||||
$this->database->release_session_lock($this->record->id);
|
||||
} catch (Exception $ex) {
|
||||
// ignore problems
|
||||
}
|
||||
$this->record = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* GC session handler
|
||||
*
|
||||
* {@see http://php.net/manual/en/function.session-set-save-handler.php}
|
||||
*
|
||||
* @param int $ignored_maxlifetime moodle uses special timeout rules
|
||||
* @return bool success
|
||||
*/
|
||||
public function handler_gc($ignored_maxlifetime) {
|
||||
session_gc();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns true if legacy session used.
|
||||
* @return bool true if legacy(==file) based session used
|
||||
|
Loading…
x
Reference in New Issue
Block a user