/** * 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)))) { $record = new stdClass(); $record->state = 0; $record->sid = $sid; $record->sessdata = null; $record->userid = 0; $record->timecreated = $record->timemodified = time(); $record->firstip = $record->lastip = getremoteaddr(); $record->id = $this->database->insert_record_raw('sessions', $record); } } 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; if (!empty($record->userid)) { // skips not logged in if ($user = $this->database->get_record('user', array('id' => $record->userid))) { if (!isguestuser($user)) { $authsequence = get_enabled_auth_plugins(); // auths, in sequence foreach ($authsequence as $authname) { $authplugin = get_auth_plugin($authname); if ($authplugin->ignore_timeout_hook($user, $record->sid, $record->timecreated, $record->timemodified)) { $ignoretimeout = true; break; } } } } } if ($ignoretimeout) { //refresh session $record->timemodified = time(); try { $this->database->update_record('sessions', $record); } catch (Exception $ex) { // very unlikely error error_log('Can not refresh database session'); $this->failed = true; throw $ex; } } else { //time out session $record->state = 0; $record->sessdata = null; $record->userid = 0; $record->timecreated = $record->timemodified = time(); $record->firstip = $record->lastip = getremoteaddr(); try { $this->database->update_record('sessions', $record); } catch (Exception $ex) { // very unlikely error error_log('Can not time out database session'); $this->failed = true; throw $ex; } } } $data = is_null($record->sessdata) ? '' : base64_decode($record->sessdata); unset($record->sessdata); // conserve memory $this->record = $record; return $data; }
/** * 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 { // Do not fetch full record yet, wait until it is locked. if (!($record = $this->database->get_record('sessions', array('sid' => $sid), 'id, userid'))) { $record = new stdClass(); $record->state = 0; $record->sid = $sid; $record->sessdata = null; $record->userid = 0; $record->timecreated = $record->timemodified = time(); $record->firstip = $record->lastip = getremoteaddr(); $record->id = $this->database->insert_record_raw('sessions', $record); } } 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 { if (!empty($CFG->sessionlockloggedinonly) and (isguestuser($record->userid) or empty($record->userid))) { // No session locking for guests and not-logged-in users, // these users mostly read stuff, there should not be any major // session race conditions. Hopefully they do not access other // pages while being logged-in. } else { $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; } // Finally read the full session data because we know we have the lock now. if (!($record = $this->database->get_record('sessions', array('id' => $record->id)))) { error_log('Cannot read session record'); $this->failed = true; return ''; } // verify timeout if ($record->timemodified + $CFG->sessiontimeout < time()) { $ignoretimeout = false; if (!empty($record->userid)) { // skips not logged in if ($user = $this->database->get_record('user', array('id' => $record->userid))) { // Refresh session if logged as a guest if (isguestuser($user)) { $ignoretimeout = true; } else { $authsequence = get_enabled_auth_plugins(); // auths, in sequence foreach ($authsequence as $authname) { $authplugin = get_auth_plugin($authname); if ($authplugin->ignore_timeout_hook($user, $record->sid, $record->timecreated, $record->timemodified)) { $ignoretimeout = true; break; } } } } } if ($ignoretimeout) { //refresh session $record->timemodified = time(); try { $this->database->update_record('sessions', $record); } catch (Exception $ex) { // very unlikely error error_log('Can not refresh database session'); $this->failed = true; throw $ex; } } else { //time out session $record->state = 0; $record->sessdata = null; $record->userid = 0; $record->timecreated = $record->timemodified = time(); $record->firstip = $record->lastip = getremoteaddr(); try { $this->database->update_record('sessions', $record); } catch (Exception $ex) { // very unlikely error error_log('Can not time out database session'); $this->failed = true; throw $ex; } } } if (is_null($record->sessdata)) { $data = ''; $this->lasthash = sha1(''); } else { $data = base64_decode($record->sessdata); $this->lasthash = sha1($record->sessdata); } unset($record->sessdata); // conserve memory $this->record = $record; return $data; }