Aleksander Machniak
2016-05-16 0b7e26c1bf6bc7a684eb3a214d92d3927306cd8a
commit | author | age
4df4ab 1 <?php
C 2
a95874 3 /**
4df4ab 4  +-----------------------------------------------------------------------+
C 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:                                                              |
a95874 13  |   Provide redis supported session management                          |
4df4ab 14  +-----------------------------------------------------------------------+
C 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
b4be89 30     /**
C 31      * @param Object $config
32      */
33     public function __construct($config)
4df4ab 34     {
b4be89 35         parent::__construct($config);
C 36
4df4ab 37         // instantiate Redis object
C 38         $this->redis = new Redis();
39
b4be89 40         if (!$this->redis) {
4df4ab 41             rcube::raise_error(array('code' => 604, 'type' => 'session',
C 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
b4be89 48         $hosts = $this->config->get('redis_hosts', array('localhost'));
4df4ab 49
C 50         // host config is wrong
b4be89 51         if (!is_array($hosts) || empty($hosts)) {
4df4ab 52             rcube::raise_error(array('code' => 604, 'type' => 'session',
C 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
b4be89 66         foreach ($hosts as $host) {
4df4ab 67             // explode individual fields
b4be89 68             list($host, $port, $database, $password) = array_pad(explode(':', $host, 4), 4, null);
4df4ab 69
C 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         }
7bbb86 172
AM 173         return '';
4df4ab 174     }
C 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) {
a95874 189             $data = serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $newvars));
AM 190             $this->redis->setex($key, $this->lifetime + 60, $data);
4df4ab 191         }
C 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     {
a95874 205         $data = serialize(array('changed' => time(), 'ip' => $this->ip, 'vars' => $vars));
AM 206
207         return $this->redis->setex($key, $this->lifetime + 60, $data);
4df4ab 208     }
a95874 209 }