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