
7 changed files with 724 additions and 279 deletions
-
14config/defaults.inc.php
-
29program/lib/Roundcube/rcube.php
-
371program/lib/Roundcube/rcube_session.php
-
168program/lib/Roundcube/rcube_session_db.php
-
140program/lib/Roundcube/rcube_session_memcache.php
-
71program/lib/Roundcube/rcube_session_php.php
-
210program/lib/Roundcube/rcube_session_redis.php
@ -0,0 +1,168 @@ |
|||
<?php |
|||
|
|||
/* |
|||
+-----------------------------------------------------------------------+ |
|||
| This file is part of the Roundcube Webmail client | |
|||
| Copyright (C) 2005-2014, The Roundcube Dev Team | |
|||
| Copyright (C) 2011, Kolab Systems AG | |
|||
| | |
|||
| Licensed under the GNU General Public License version 3 or | |
|||
| any later version with exceptions for skins & plugins. | |
|||
| See the README file for a full license statement. | |
|||
| | |
|||
| PURPOSE: | |
|||
| Provide database supported session management | |
|||
+-----------------------------------------------------------------------+ |
|||
| Author: Thomas Bruederli <roundcube@gmail.com> | |
|||
| Author: Aleksander Machniak <alec@alec.pl> | |
|||
| Author: Cor Bosman <cor@roundcu.be> | |
|||
+-----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
/** |
|||
* Class to provide database session storage |
|||
* |
|||
* @package Framework |
|||
* @subpackage Core |
|||
* @author Thomas Bruederli <roundcube@gmail.com> |
|||
* @author Aleksander Machniak <alec@alec.pl> |
|||
* @author Cor Bosman <cor@roundcu.be> |
|||
*/ |
|||
class rcube_session_db extends rcube_session |
|||
{ |
|||
private $db; |
|||
private $table_name; |
|||
|
|||
public function __construct() |
|||
{ |
|||
// get db instance
|
|||
$this->db = rcube::get_instance()->get_dbh(); |
|||
|
|||
// session table name
|
|||
$this->table_name = $this->db->table_name('session', true); |
|||
|
|||
// register sessions handler
|
|||
$this->register_session_handler(); |
|||
|
|||
// register db gc handler
|
|||
$this->register_gc_handler(array($this, 'gc_db')); |
|||
} |
|||
|
|||
/** |
|||
* @param $save_path |
|||
* @param $session_name |
|||
* @return bool |
|||
*/ |
|||
public function open($save_path, $session_name) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function close() |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Handler for session_destroy() |
|||
* |
|||
* @param $key |
|||
* @return bool |
|||
*/ |
|||
public function destroy($key) |
|||
{ |
|||
if ($key) { |
|||
$this->db->query("DELETE FROM {$this->table_name} WHERE `sess_id` = ?", $key); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Read session data from database |
|||
* |
|||
* @param string Session ID |
|||
* |
|||
* @return string Session vars |
|||
*/ |
|||
public function read($key) |
|||
{ |
|||
$sql_result = $this->db->query( |
|||
"SELECT `vars`, `ip`, `changed`, " . $this->db->now() . " AS ts" |
|||
. " FROM {$this->table_name} WHERE `sess_id` = ?", $key); |
|||
|
|||
if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { |
|||
$this->time_diff = time() - strtotime($sql_arr['ts']); |
|||
$this->changed = strtotime($sql_arr['changed']); |
|||
$this->ip = $sql_arr['ip']; |
|||
$this->vars = base64_decode($sql_arr['vars']); |
|||
$this->key = $key; |
|||
|
|||
return !empty($this->vars) ? (string) $this->vars : ''; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* insert new data into db session store |
|||
* |
|||
* @param $key |
|||
* @param $vars |
|||
* @return bool |
|||
*/ |
|||
public function write($key, $vars) |
|||
{ |
|||
$now = $this->db->now(); |
|||
|
|||
$this->db->query("INSERT INTO {$this->table_name}" |
|||
. " (`sess_id`, `vars`, `ip`, `created`, `changed`)" |
|||
. " VALUES (?, ?, ?, $now, $now)", |
|||
$key, base64_encode($vars), (string)$this->ip); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* update session data |
|||
* |
|||
* @param $key |
|||
* @param $newvars |
|||
* @param $oldvars |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function update($key, $newvars, $oldvars) |
|||
{ |
|||
$now = $this->db->now(); |
|||
|
|||
// if new and old data are not the same, update data
|
|||
// else update expire timestamp only when certain conditions are met
|
|||
if ($newvars !== $oldvars) { |
|||
$this->db->query("UPDATE {$this->table_name} " |
|||
. "SET `changed` = $now, `vars` = ? WHERE `sess_id` = ?", |
|||
base64_encode($newvars), $key); |
|||
} |
|||
else if ($ts - $this->changed + $this->time_diff > $this->lifetime / 2) { |
|||
$this->db->query("UPDATE {$this->table_name} SET `changed` = $now" |
|||
. " WHERE `sess_id` = ?", $key); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Clean up db sessions. |
|||
*/ |
|||
public function gc_db() |
|||
{ |
|||
// just clean all old sessions when this GC is called
|
|||
$this->db->query("DELETE FROM " . $this->db->table_name('session') |
|||
. " WHERE changed < " . $this->db->now(-$this->gc_enabled)); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,140 @@ |
|||
<?php |
|||
|
|||
/* |
|||
+-----------------------------------------------------------------------+ |
|||
| This file is part of the Roundcube Webmail client | |
|||
| Copyright (C) 2005-2014, The Roundcube Dev Team | |
|||
| Copyright (C) 2011, Kolab Systems AG | |
|||
| | |
|||
| Licensed under the GNU General Public License version 3 or | |
|||
| any later version with exceptions for skins & plugins. | |
|||
| See the README file for a full license statement. | |
|||
| | |
|||
| PURPOSE: | |
|||
| Provide database supported session management | |
|||
+-----------------------------------------------------------------------+ |
|||
| Author: Thomas Bruederli <roundcube@gmail.com> | |
|||
| Author: Aleksander Machniak <alec@alec.pl> | |
|||
| Author: Cor Bosman <cor@roundcu.be> | |
|||
+-----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
/** |
|||
* Class to provide memcache session storage |
|||
* |
|||
* @package Framework |
|||
* @subpackage Core |
|||
* @author Thomas Bruederli <roundcube@gmail.com> |
|||
* @author Aleksander Machniak <alec@alec.pl> |
|||
* @author Cor Bosman <cor@roundcu.be> |
|||
*/ |
|||
class rcube_session_memcache extends rcube_session |
|||
{ |
|||
private $memcache; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->memcache = rcube::get_instance()->get_memcache(); |
|||
|
|||
if(! $this->memcache) { |
|||
rcube::raise_error(array('code' => 604, 'type' => 'db', |
|||
'line' => __LINE__, 'file' => __FILE__, |
|||
'message' => "Failed to connect to memcached. Please check configuration"), |
|||
true, true); |
|||
} |
|||
|
|||
// register sessions handler
|
|||
$this->register_session_handler(); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* @param $save_path |
|||
* @param $session_name |
|||
* @return bool |
|||
*/ |
|||
public function open($save_path, $session_name) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function close() |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Handler for session_destroy() with memcache backend |
|||
* |
|||
* @param $key |
|||
* @return bool |
|||
*/ |
|||
public function destroy($key) |
|||
{ |
|||
if ($key) { |
|||
// #1488592: use 2nd argument
|
|||
$this->memcache->delete($key, 0); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Read session data from memcache |
|||
* |
|||
* @param $key |
|||
* @return null|string |
|||
*/ |
|||
public function read($key) |
|||
{ |
|||
if ($value = $this->memcache->get($key)) { |
|||
$arr = unserialize($value); |
|||
$this->changed = $arr['changed']; |
|||
$this->ip = $arr['ip']; |
|||
$this->vars = $arr['vars']; |
|||
$this->key = $key; |
|||
|
|||
return !empty($this->vars) ? (string) $this->vars : ''; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* write data to memcache storage |
|||
* |
|||
* @param $key |
|||
* @param $vars |
|||
* @return bool |
|||
*/ |
|||
public function write($key, $vars) |
|||
{ |
|||
return $this->memcache->set($key, serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $vars)), |
|||
MEMCACHE_COMPRESSED, $this->lifetime + 60); |
|||
} |
|||
|
|||
/** |
|||
* update memcache session data |
|||
* |
|||
* @param $key |
|||
* @param $newvars |
|||
* @param $oldvars |
|||
* @return bool |
|||
*/ |
|||
public function update($key, $newvars, $oldvars) |
|||
{ |
|||
$ts = microtime(true); |
|||
|
|||
if ($newvars !== $oldvars || $ts - $this->changed > $this->lifetime / 3) { |
|||
return $this->memcache->set($key, serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $newvars)), |
|||
MEMCACHE_COMPRESSED, $this->lifetime + 60); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,71 @@ |
|||
<?php |
|||
|
|||
/* |
|||
+-----------------------------------------------------------------------+ |
|||
| This file is part of the Roundcube Webmail client | |
|||
| Copyright (C) 2005-2014, The Roundcube Dev Team | |
|||
| Copyright (C) 2011, Kolab Systems AG | |
|||
| | |
|||
| Licensed under the GNU General Public License version 3 or | |
|||
| any later version with exceptions for skins & plugins. | |
|||
| See the README file for a full license statement. | |
|||
| | |
|||
| PURPOSE: | |
|||
| Provide database supported session management | |
|||
+-----------------------------------------------------------------------+ |
|||
| Author: Thomas Bruederli <roundcube@gmail.com> | |
|||
| Author: Aleksander Machniak <alec@alec.pl> | |
|||
| Author: Cor Bosman <cor@roundcu.be> | |
|||
+-----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
/** |
|||
* Class to provide native php session storage |
|||
* |
|||
* @package Framework |
|||
* @subpackage Core |
|||
* @author Thomas Bruederli <roundcube@gmail.com> |
|||
* @author Aleksander Machniak <alec@alec.pl> |
|||
* @author Cor Bosman <cor@roundcu.be> |
|||
*/ |
|||
class rcube_session_php extends rcube_session { |
|||
|
|||
|
|||
/** |
|||
* native php sessions don't need a save handler |
|||
* we do need to define abstract function implementations but they are not used. |
|||
*/ |
|||
|
|||
public function open($save_path, $session_name) {} |
|||
public function close() {} |
|||
public function destroy($key) {} |
|||
public function read($key) {} |
|||
public function write($key, $vars) {} |
|||
public function update($key, $newvars, $oldvars) {} |
|||
|
|||
|
|||
/** |
|||
* Wrapper for session_write_close() |
|||
*/ |
|||
public function write_close() |
|||
{ |
|||
$_SESSION['__IP'] = $this->ip; |
|||
$_SESSION['__MTIME'] = time(); |
|||
|
|||
parent::write_close(); |
|||
} |
|||
|
|||
/** |
|||
* Wrapper for session_start() |
|||
*/ |
|||
public function start($config) |
|||
{ |
|||
parent::start($config); |
|||
|
|||
$this->key = session_id(); |
|||
$this->ip = $_SESSION['__IP']; |
|||
$this->changed = $_SESSION['__MTIME']; |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,210 @@ |
|||
<?php |
|||
|
|||
/* |
|||
+-----------------------------------------------------------------------+ |
|||
| This file is part of the Roundcube Webmail client | |
|||
| Copyright (C) 2005-2014, The Roundcube Dev Team | |
|||
| Copyright (C) 2011, Kolab Systems AG | |
|||
| | |
|||
| Licensed under the GNU General Public License version 3 or | |
|||
| any later version with exceptions for skins & plugins. | |
|||
| See the README file for a full license statement. | |
|||
| | |
|||
| PURPOSE: | |
|||
| Provide database supported session management | |
|||
+-----------------------------------------------------------------------+ |
|||
| Author: Thomas Bruederli <roundcube@gmail.com> | |
|||
| Author: Aleksander Machniak <alec@alec.pl> | |
|||
| Author: Cor Bosman <cor@roundcu.be> | |
|||
+-----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
/** |
|||
* Class to provide redis session storage |
|||
* |
|||
* @package Framework |
|||
* @subpackage Core |
|||
* @author Cor Bosman <cor@roundcu.be> |
|||
*/ |
|||
class rcube_session_redis extends rcube_session { |
|||
|
|||
private $redis; |
|||
|
|||
public function __construct() |
|||
{ |
|||
// instantiate Redis object
|
|||
$this->redis = new Redis(); |
|||
|
|||
if (! $this->redis) { |
|||
rcube::raise_error(array('code' => 604, 'type' => 'session', |
|||
'line' => __LINE__, 'file' => __FILE__, |
|||
'message' => "Failed to find Redis. Make sure php-redis is included"), |
|||
true, true); |
|||
} |
|||
|
|||
// get config instance
|
|||
$hosts = rcube::get_instance()->config->get('redis_hosts', array()); |
|||
|
|||
// host config is wrong
|
|||
if (!is_array($hosts) || empty($hosts) ) { |
|||
rcube::raise_error(array('code' => 604, 'type' => 'session', |
|||
'line' => __LINE__, 'file' => __FILE__, |
|||
'message' => "Redis host not configured"), |
|||
true, true); |
|||
} |
|||
|
|||
// only allow 1 host for now until we support clustering
|
|||
if (count($hosts) > 1) { |
|||
rcube::raise_error(array('code' => 604, 'type' => 'session', |
|||
'line' => __LINE__, 'file' => __FILE__, |
|||
'message' => "Redis cluster not yet supported"), |
|||
true, true); |
|||
} |
|||
|
|||
foreach($hosts as $config) { |
|||
// explode individual fields
|
|||
list($host, $port, $database, $password) = array_pad(explode(':', $config, 4), 4, null); |
|||
|
|||
// set default values if not set
|
|||
$host = ($host !== null) ? $host : '127.0.0.1'; |
|||
$port = ($port !== null) ? $port : 6379; |
|||
$database = ($database !== null) ? $database : 0; |
|||
|
|||
if ($this->redis->connect($host, $port) === false) { |
|||
rcube::raise_error( |
|||
array( |
|||
'code' => 604, |
|||
'type' => 'session', |
|||
'line' => __LINE__, |
|||
'file' => __FILE__, |
|||
'message' => "Could not connect to Redis server. Please check host and port" |
|||
), |
|||
true, |
|||
true |
|||
); |
|||
} |
|||
|
|||
if ($password != null && $this->redis->auth($password) === false) { |
|||
rcube::raise_error( |
|||
array( |
|||
'code' => 604, |
|||
'type' => 'session', |
|||
'line' => __LINE__, |
|||
'file' => __FILE__, |
|||
'message' => "Could not authenticate with Redis server. Please check password." |
|||
), |
|||
true, |
|||
true |
|||
); |
|||
} |
|||
|
|||
if ($database != 0 && $this->redis->select($database) === false) { |
|||
rcube::raise_error( |
|||
array( |
|||
'code' => 604, |
|||
'type' => 'session', |
|||
'line' => __LINE__, |
|||
'file' => __FILE__, |
|||
'message' => "Could not select Redis database. Please check database setting." |
|||
), |
|||
true, |
|||
true |
|||
); |
|||
} |
|||
} |
|||
|
|||
// register sessions handler
|
|||
$this->register_session_handler(); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* @param $save_path |
|||
* @param $session_name |
|||
* @return bool |
|||
*/ |
|||
public function open($save_path, $session_name) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function close() |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* remove data from store |
|||
* |
|||
* @param $key |
|||
* @return bool |
|||
*/ |
|||
public function destroy($key) |
|||
{ |
|||
if ($key) { |
|||
$this->redis->del($key); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* read data from redis store |
|||
* |
|||
* @param $key |
|||
* @return null |
|||
*/ |
|||
public function read($key) |
|||
{ |
|||
if ($value = $this->redis->get($key)) { |
|||
$arr = unserialize($value); |
|||
$this->changed = $arr['changed']; |
|||
$this->ip = $arr['ip']; |
|||
$this->vars = $arr['vars']; |
|||
$this->key = $key; |
|||
|
|||
return !empty($this->vars) ? (string) $this->vars : ''; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* write data to redis store |
|||
* |
|||
* @param $key |
|||
* @param $newvars |
|||
* @param $oldvars |
|||
* @return bool |
|||
*/ |
|||
public function update($key, $newvars, $oldvars) |
|||
{ |
|||
$ts = microtime(true); |
|||
|
|||
if ($newvars !== $oldvars || $ts - $this->changed > $this->lifetime / 3) { |
|||
$this->redis->setex($key, $this->lifetime + 60, serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $newvars))); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* write data to redis store |
|||
* |
|||
* @param $key |
|||
* @param $vars |
|||
* @return bool |
|||
*/ |
|||
public function write($key, $vars) |
|||
{ |
|||
return $this->redis->setex($key, $this->lifetime + 60, serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $vars))); |
|||
} |
|||
|
|||
|
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue