Skip to content

Instantly share code, notes, and snippets.

@dcai
Last active April 6, 2016 15:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dcai/fc0eab6479728140319a to your computer and use it in GitHub Desktop.
Save dcai/fc0eab6479728140319a to your computer and use it in GitHub Desktop.
moodle redis session handler
<?php
/**
* Redis based session handler.
*
* @copyright 2015 Dongsheng Cai {@link http://dongsheng.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
*
* 1. Copy this file to $CFG->dirroot/lib/classes/session/redis.php
*
* 2. Add following lines to config.php:
*
* $CFG->session_handler_class = '\core\session\redis';
* $CFG->session_redis_save_path = 'tcp://127.0.0.1:6379?prefix=m27sess:';
* $CFG->session_redis_acquire_lock_timeout = 120;
*
*/
namespace core\session;
defined('MOODLE_INTERNAL') || die();
class redis extends handler {
protected $savepath;
protected $acquiretimeout = 120;
protected $servers = array();
public function __construct() {
global $CFG;
if (empty($CFG->session_redis_save_path)) {
$this->savepath = '';
} else {
$this->savepath = $CFG->session_redis_save_path;
}
if (!empty($this->savepath)) {
$this->servers = self::parse_connection_string($this->savepath);
}
if (!empty($CFG->session_redis_acquire_lock_timeout)) {
$this->acquiretimeout = (int)$CFG->session_redis_acquire_lock_timeout;
} else {
$this->acquiretimeout = ini_get('max_execution_time');
}
}
public function init() {
if (!extension_loaded('redis')) {
throw new exception('sessionhandlerproblem', 'error', '', null,
'redis extension is not loaded');
}
if (empty($this->savepath)) {
throw new exception('sessionhandlerproblem', 'error', '', null,
'$CFG->session_redis_save_path must be specified in config.php');
}
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', $this->savepath);
}
public function start() {
set_time_limit($this->acquiretimeout);
$result = parent::start();
return $result;
}
public function session_exists($sid) {
$result = false;
foreach ($this->get_redis_servers() as $redis) {
if ($result === false) {
if ($redis->exists($sid)) {
$result = true;
}
}
$redis->close();
}
return $result;
}
public function get_redis_servers() {
$result = array();
foreach ($this->servers as $server) {
$redis = new \Redis();
if ($server->type === 'tcp') {
$redis->connect($server->host, $server->port, $this->acquiretimeout);
} else {
$redis->connect($server->path, null, $this->acquiretimeout);
}
if (!empty($server->options)) {
foreach($server->options as $key=>$value) {
if ($key === 'prefix') {
$redis->setOption(\Redis::OPT_PREFIX, $value);
}
}
}
$result[] = $redis;
}
return $result;
}
public function kill_all_sessions() {
global $DB;
if (!$this->servers) {
return;
}
$redisservers = $this->get_redis_servers();
$rs = $DB->get_recordset('sessions', array(), 'id DESC', 'id, sid');
foreach ($rs as $record) {
foreach ($redisservers as $redis) {
$redis->delete($record->sid);
}
}
$rs->close();
foreach ($redisservers as $redis) {
$redis->close();
}
}
public function kill_session($sid) {
foreach ($this->get_redis_servers() as $redis) {
$redis->delete($sid);
$redis->close();
}
}
public static function parse_connection_string($str) {
$servers = array();
$conns = explode(',', $str);
foreach ($conns as $conn) {
$conn = trim($conn);
if (strpos($conn, 'unix') === 0) {
$conn = preg_replace('/^unix/', 'file', $conn, 1);
}
$parts = parse_url($conn);
$server = new \stdClass;
$server->type = $parts['scheme'];
if (!empty($parts['host'])) {
$server->host = $parts['host'];
}
if (!empty($parts['port'])) {
$server->port = $parts['port'];
} else {
$server->port = 6379;
}
if (!empty($parts['path'])) {
$server->path = $parts['path'];
}
$query = $parts['query'];
$options = array();
parse_str($query, $options);
$server->options = $options;
$servers[] = $server;
}
return $servers;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment