/
var
/
www
/
html
/
poli
/
lib
/
classes
/
session
/
Upload File
HOME
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * 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. * * Note: You may need to manually configure redundancy and fail-over * if you specify multiple servers. * * @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 { /** @var string $savepath save_path string */ protected $savepath; /** @var array $servers list of servers parsed from save_path */ protected $servers; /** @var int $acquiretimeout how long to wait for session lock */ protected $acquiretimeout = 120; /** * 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'); } // Check in case anybody mistakenly includes tcp://, which you // would do in the raw PHP config. We require the same format as // for memcached (without tcp://). Otherwse the code that splits it into // individual servers won't have worked properly. if (strpos($this->savepath, 'tcp://') !== false) { throw new exception('sessionhandlerproblem', 'error', '', null, '$CFG->session_memcache_save_path should not contain tcp://'); } ini_set('session.save_handler', 'memcache'); // The format of save_path is different for memcache (compared to memcached). // We are using the same format in config.php to avoid confusion. // It has to have tcp:// at the start of each entry. $memcacheformat = preg_replace('~(^|,\s*)~','$1tcp://', $this->savepath); ini_set('session.save_path', $memcacheformat); } /** * 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) { $result = false; foreach ($this->get_memcaches() as $memcache) { if ($result === false) { $value = $memcache->get($sid); if ($value !== false) { $result = true; } } $memcache->close(); } return $result; } /** * Gets the Memcache objects, one for each server. * The connects must be closed manually after use. * * Note: the servers are not automatically synchronised * when accessed via Memcache class, it needs to be * done manually by accessing all configured servers. * * @return \Memcache[] Array of initialised memcache objects */ protected function get_memcaches() { $result = array(); foreach ($this->servers as $server) { $memcache = new \Memcache(); $memcache->addServer($server[0], $server[1]); $result[] = $memcache; } return $result; } /** * Kills all active sessions, the core sessions table is purged afterwards. */ public function kill_all_sessions() { global $DB; if (!$this->servers) { return; } $memcaches = $this->get_memcaches(); // 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) { foreach ($memcaches as $memcache) { $memcache->delete($record->sid); } } $rs->close(); foreach ($memcaches as $memcache) { $memcache->close(); } } /** * Kills one session, the session record is removed afterwards. * * @param string $sid PHP session ID */ public function kill_session($sid) { foreach ($this->get_memcaches() as $memcache) { $memcache->delete($sid); $memcache->close(); } } }