. /** * Memcache based session handler. * * This is based on the memcached code. It lacks some features, such as * locking options, but appears to work in practice. * * @package core * @copyright 2014 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core\session; defined('MOODLE_INTERNAL') || die(); /** * Memcache based session handler. * * @package core * @copyright 2014 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class memcache extends handler { /** * Creates new instance of handler. */ public function __construct() { global $CFG; if (empty($CFG->session_memcache_save_path)) { $this->savepath = ''; } else { $this->savepath = $CFG->session_memcache_save_path; } if (empty($this->savepath)) { $this->servers = array(); } else { $this->servers = util::connection_string_to_memcache_servers($this->savepath); } if (!empty($CFG->session_memcache_acquire_lock_timeout)) { $this->acquiretimeout = (int)$CFG->session_memcache_acquire_lock_timeout; } } /** * Starts the session. * * @return bool success */ public function start() { $default = ini_get('max_execution_time'); set_time_limit($this->acquiretimeout); $result = parent::start(); set_time_limit($default); return $result; } /** * Inits session handler. */ public function init() { if (!extension_loaded('memcache')) { throw new exception('sessionhandlerproblem', 'error', '', null, 'memcache extension is not loaded'); } $version = phpversion('memcache'); if (!$version or version_compare($version, '2.2') < 0) { throw new exception('sessionhandlerproblem', 'error', '', null, 'memcache extension version must be at least 2.2'); } if (empty($this->savepath)) { throw new exception('sessionhandlerproblem', 'error', '', null, '$CFG->session_memcache_save_path must be specified in config.php'); } ini_set('session.save_handler', 'memcache'); ini_set('session.save_path', $this->savepath); } /** * Checks for existing session with given id. * * Note: this verifies the storage backend only, not the actual session records. * * @param string $sid PHP session ID * @return bool true if session found. */ public function session_exists($sid) { if (!$this->servers) { return false; } $memcache = $this->get_memcache(); $value = $memcache->get($sid); $memcache->close(); return ($value !== false); } /** * Gets the memcache object with all the servers added to it. * * @return \Memcache Initialised memcache object */ protected function get_memcache() { $memcache = new \Memcache(); foreach ($this->servers as $server) { $memcache->addServer($server[0], $server[1]); } return $memcache; } /** * Kills all active sessions, the core sessions table is purged afterwards. */ public function kill_all_sessions() { global $DB; if (!$this->servers) { return; } $memcache = $this->get_memcache(); // Note: this can be significantly improved by fetching keys from memcache, // but we need to make sure we are not deleting somebody else's sessions. $rs = $DB->get_recordset('sessions', array(), 'id DESC', 'id, sid'); foreach ($rs as $record) { $memcache->delete($record->sid); } $rs->close(); $memcache->close(); } /** * Kills one session, the session record is removed afterwards. * * @param string $sid PHP session ID */ public function kill_session($sid) { if (!$this->servers) { return; } $memcache = $this->get_memcache(); $memcache->delete($sid); $memcache->close(); } }