You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rcube_session_redis.php 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <?php
  2. /**
  3. +-----------------------------------------------------------------------+
  4. | This file is part of the Roundcube Webmail client |
  5. | Copyright (C) 2005-2014, The Roundcube Dev Team |
  6. | |
  7. | Licensed under the GNU General Public License version 3 or |
  8. | any later version with exceptions for skins & plugins. |
  9. | See the README file for a full license statement. |
  10. | |
  11. | PURPOSE: |
  12. | Provide redis supported session management |
  13. +-----------------------------------------------------------------------+
  14. | Author: Cor Bosman <cor@roundcu.be> |
  15. +-----------------------------------------------------------------------+
  16. */
  17. /**
  18. * Class to provide redis session storage
  19. *
  20. * @package Framework
  21. * @subpackage Core
  22. * @author Cor Bosman <cor@roundcu.be>
  23. */
  24. class rcube_session_redis extends rcube_session {
  25. private $redis;
  26. /**
  27. * @param Object $config
  28. */
  29. public function __construct($config)
  30. {
  31. parent::__construct($config);
  32. // instantiate Redis object
  33. $this->redis = new Redis();
  34. if (!$this->redis) {
  35. rcube::raise_error(array('code' => 604, 'type' => 'session',
  36. 'line' => __LINE__, 'file' => __FILE__,
  37. 'message' => "Failed to find Redis. Make sure php-redis is included"),
  38. true, true);
  39. }
  40. // get config instance
  41. $hosts = $this->config->get('redis_hosts', array('localhost'));
  42. // host config is wrong
  43. if (!is_array($hosts) || empty($hosts)) {
  44. rcube::raise_error(array('code' => 604, 'type' => 'session',
  45. 'line' => __LINE__, 'file' => __FILE__,
  46. 'message' => "Redis host not configured"),
  47. true, true);
  48. }
  49. // only allow 1 host for now until we support clustering
  50. if (count($hosts) > 1) {
  51. rcube::raise_error(array('code' => 604, 'type' => 'session',
  52. 'line' => __LINE__, 'file' => __FILE__,
  53. 'message' => "Redis cluster not yet supported"),
  54. true, true);
  55. }
  56. foreach ($hosts as $host) {
  57. // explode individual fields
  58. list($host, $port, $database, $password) = array_pad(explode(':', $host, 4), 4, null);
  59. // set default values if not set
  60. $host = ($host !== null) ? $host : '127.0.0.1';
  61. $port = ($port !== null) ? $port : 6379;
  62. $database = ($database !== null) ? $database : 0;
  63. if ($this->redis->connect($host, $port) === false) {
  64. rcube::raise_error(
  65. array(
  66. 'code' => 604,
  67. 'type' => 'session',
  68. 'line' => __LINE__,
  69. 'file' => __FILE__,
  70. 'message' => "Could not connect to Redis server. Please check host and port"
  71. ),
  72. true,
  73. true
  74. );
  75. }
  76. if ($password != null && $this->redis->auth($password) === false) {
  77. rcube::raise_error(
  78. array(
  79. 'code' => 604,
  80. 'type' => 'session',
  81. 'line' => __LINE__,
  82. 'file' => __FILE__,
  83. 'message' => "Could not authenticate with Redis server. Please check password."
  84. ),
  85. true,
  86. true
  87. );
  88. }
  89. if ($database != 0 && $this->redis->select($database) === false) {
  90. rcube::raise_error(
  91. array(
  92. 'code' => 604,
  93. 'type' => 'session',
  94. 'line' => __LINE__,
  95. 'file' => __FILE__,
  96. 'message' => "Could not select Redis database. Please check database setting."
  97. ),
  98. true,
  99. true
  100. );
  101. }
  102. }
  103. // register sessions handler
  104. $this->register_session_handler();
  105. }
  106. /**
  107. * @param $save_path
  108. * @param $session_name
  109. * @return bool
  110. */
  111. public function open($save_path, $session_name)
  112. {
  113. return true;
  114. }
  115. /**
  116. * @return bool
  117. */
  118. public function close()
  119. {
  120. return true;
  121. }
  122. /**
  123. * remove data from store
  124. *
  125. * @param $key
  126. * @return bool
  127. */
  128. public function destroy($key)
  129. {
  130. if ($key) {
  131. $this->redis->del($key);
  132. }
  133. return true;
  134. }
  135. /**
  136. * read data from redis store
  137. *
  138. * @param $key
  139. * @return null
  140. */
  141. public function read($key)
  142. {
  143. if ($value = $this->redis->get($key)) {
  144. $arr = unserialize($value);
  145. $this->changed = $arr['changed'];
  146. $this->ip = $arr['ip'];
  147. $this->vars = $arr['vars'];
  148. $this->key = $key;
  149. return !empty($this->vars) ? (string) $this->vars : '';
  150. }
  151. return '';
  152. }
  153. /**
  154. * write data to redis store
  155. *
  156. * @param $key
  157. * @param $newvars
  158. * @param $oldvars
  159. * @return bool
  160. */
  161. public function update($key, $newvars, $oldvars)
  162. {
  163. $ts = microtime(true);
  164. if ($newvars !== $oldvars || $ts - $this->changed > $this->lifetime / 3) {
  165. $data = serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $newvars));
  166. $this->redis->setex($key, $this->lifetime + 60, $data);
  167. }
  168. return true;
  169. }
  170. /**
  171. * write data to redis store
  172. *
  173. * @param $key
  174. * @param $vars
  175. * @return bool
  176. */
  177. public function write($key, $vars)
  178. {
  179. $data = serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $vars));
  180. return $this->redis->setex($key, $this->lifetime + 60, $data);
  181. }
  182. }