/** * This function generates the unique index for a specific lock key. * Once an index is assigned to a key, it never changes - so this is * statically cached. * * @param string $key * @return int * @throws \moodle_exception */ protected function get_index_from_key($key) { if (isset(self::$lockidcache[$key])) { return self::$lockidcache[$key]; } $index = 0; $record = $this->db->get_record('lock_db', array('resourcekey' => $key)); if ($record) { $index = $record->id; } if (!$index) { $record = new \stdClass(); $record->resourcekey = $key; try { $index = $this->db->insert_record('lock_db', $record); } catch (\dml_exception $de) { // Race condition - never mind - now the value is guaranteed to exist. $record = $this->db->get_record('lock_db', array('resourcekey' => $key)); if ($record) { $index = $record->id; } } } if (!$index) { throw new \moodle_exception('Could not generate unique index for key'); } self::$lockidcache[$key] = $index; return $index; }
/** * 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; } else { if (!empty($USER->id)) { $userid = $USER->id; } } if (isset($this->record->id)) { $data = base64_encode($session_data); // There might be some binary mess :-( // Skip db update if nothing changed, // do not update the timemodified each second. $hash = sha1($data); if ($this->lasthash === $hash and $this->record->userid == $userid and time() - $this->record->timemodified < 20 and $this->record->lastip == getremoteaddr()) { // No need to update anything! return true; } $this->record->sessdata = $data; $this->record->userid = $userid; $this->record->timemodified = time(); $this->record->lastip = getremoteaddr(); try { $this->database->update_record_raw('sessions', $this->record); $this->lasthash = $hash; } catch (dml_exception $ex) { if ($this->database->get_dbfamily() === 'mysql') { 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 { // fresh new session try { $record = new stdClass(); $record->state = 0; $record->sid = $sid; $record->sessdata = base64_encode($session_data); // there might be some binary mess :-( $record->userid = $userid; $record->timecreated = $record->timemodified = time(); $record->firstip = $record->lastip = getremoteaddr(); $record->id = $this->database->insert_record_raw('sessions', $record); $this->record = $this->database->get_record('sessions', array('id' => $record->id)); $this->lasthash = sha1($record->sessdata); $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; }
/** * 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; }
/** * @param stdClass $instance * @param $name * @param moodle_database $DB * @return int|mixed id of the group * @throws coding_exception * @throws moodle_exception */ private function get_group(stdClass $instance, $name, moodle_database $DB) { $idnumber = "autoenrol|{$instance->id}|{$name}"; $group = $DB->get_record('groups', array('idnumber' => $idnumber, 'courseid' => $instance->courseid)); if ($group == null) { $newgroupdata = new stdclass(); $newgroupdata->courseid = $instance->courseid; $newgroupdata->name = $name; $newgroupdata->idnumber = $idnumber; $newgroupdata->description = get_string('auto_desc', 'enrol_autoenrol'); $group = groups_create_group($newgroupdata); } else { $group = $group->id; } return $group; }
/** * 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) { if (!($session = $this->database->get_record('sessions', array('sid' => $sid), 'id, sid'))) { if ($sid == session_id()) { $this->recordid = null; $this->lasthash = null; } return true; } if ($this->recordid and $session->id == $this->recordid) { try { $this->database->release_session_lock($this->recordid); } catch (\Exception $ex) { // Ignore problems. } $this->recordid = null; $this->lasthash = null; } $this->database->delete_records('sessions', array('id' => $session->id)); return true; }