Browse Source

[UPDATE] refactor session

Georgi Hristov 5 months ago
parent
commit
653dee7c4b

+ 1
- 1
include/history.php View File

@@ -17,7 +17,7 @@ class History {
17 17
 
18 18
     private static function session_id()
19 19
     {
20
-        return DBSession::truncated_session_id();
20
+        return EpesiSession::truncated_id();
21 21
     }
22 22
 	
23 23
 	public static function back() {

+ 358
- 254
include/session.php View File

@@ -8,322 +8,426 @@
8 8
  */
9 9
 defined("_VALID_ACCESS") || die('Direct access forbidden');
10 10
 
11
-
12 11
 require_once('database.php');
13 12
 
14
-class DBSession implements SessionHandlerInterface{
13
+class EpesiSession implements SessionHandlerInterface{
15 14
     const MAX_SESSION_ID_LENGTH = 128;
16
-    private static $lifetime;
17
-    private static $memcached;
18
-    private static $memcached_lock_time;
19
-    private static $session_fp;
20
-    private static $session_client_fp;
21
-    private static $session_type;
15
+    
16
+    /**
17
+     * @var EpesiSessionStorage
18
+     */
19
+    private static $storage;
20
+    
21
+    private static $storageMap = [
22
+    		'file' => EpesiSessionFileStorage::class,
23
+    		'memcache' => EpesiSessionMemcachedStorage::class,
24
+    		'memcached' => EpesiSessionMemcachedStorage::class,
25
+    		'sql' => EpesiSessionDBStorage::class,
26
+    ];
22 27
 
23
-    public static function truncated_session_id($session_id = null)
28
+    public static function truncated_id($session_id = null)
24 29
     {
25
-        if ($session_id === null) {
26
-            $session_id = session_id();
27
-        }
28
-        return substr($session_id, 0, self::MAX_SESSION_ID_LENGTH);
30
+        return substr($session_id?: session_id(), 0, self::MAX_SESSION_ID_LENGTH);
31
+    }
32
+    
33
+    public static function create()
34
+    {
35
+        return new static();
36
+    }
37
+    
38
+    public static function get($name)
39
+    {    	
40
+    	return self::storage()->read($name);
29 41
     }
42
+    
43
+    public static function set($name, $data)
44
+    {
45
+    	return self::storage()->write($name, $data);
46
+    }    
47
+    
48
+    public static function destroy_client($name, $i) {
49
+    	$name = self::truncated_id($name);
50
+    	
51
+    	self::storage()->destroy($name . '_' . $i);
52
+    	
53
+    	DB::Execute('DELETE FROM history WHERE session_name=%s AND client_id=%d',array($name,$i));
54
+    }    
30 55
 
31 56
     public function open($path, $name) {
32
-        self::$lifetime = min(ini_get("session.gc_maxlifetime"),2592000-1); //less then 30 days
33
-        switch(SESSION_TYPE) {
34
-            case 'file':
35
-            case 'sql':
36
-                self::$session_type = SESSION_TYPE;
37
-                break;
38
-            case 'memcache':
39
-                if(MEMCACHE_SESSION_SERVER) {
40
-                    $srv = explode(':',MEMCACHE_SESSION_SERVER,2);
41
-                    self::$memcached = new EpesiMemcache();
42
-                    
43
-                    if(!self::$memcached->addServer($srv[0],(isset($srv[1])?$srv[1]:11211)))
44
-                        trigger_error('Cannot connect to memcache server',E_USER_ERROR);
45
-                }
46
-                if(self::$memcached) self::$session_type = SESSION_TYPE;
47
-                else self::$session_type = 'file';
48
-                break;
49
-            default:
50
-                self::$session_type = 'file';
51
-        }
52
-        if(self::$session_type=='memcache') {
53
-            self::$memcached_lock_time = ini_get("max_execution_time");
54
-            if(!self::$memcached_lock_time) self::$memcached_lock_time = 60;
55
-            self::$memcached_lock_time += time();
56
-        }
57
+    	self::storage();
58
+    	
57 59
         return true;
58 60
     }
59
-
61
+    
62
+    /**
63
+     * @return EpesiSessionStorage
64
+     */
65
+    public static function storage() {
66
+    	$lifetime = min(ini_get('session.gc_maxlifetime'),2592000-1); //less then 30 days
67
+    	
68
+    	self::$storage = self::$storage?: EpesiSessionStorage::factory(self::getStorageClass(), $lifetime);
69
+    	
70
+    	return self::$storage;
71
+    }
72
+    
73
+    public static function getStorageClass() {
74
+    	$defaultClass = reset(self::$storageMap);
75
+    	
76
+    	$class = self::$storageMap[SESSION_TYPE]?? $defaultClass;
77
+    	
78
+    	return $class::active()? $class: $defaultClass;
79
+    }
80
+    
60 81
     public function close() {
61
-        //self::gc(self::$lifetime);
62 82
         return true;
63 83
     }
64 84
 
65 85
     public function read($name) {
66
-        $name = self::truncated_session_id($name);
86
+        $name = self::truncated_id($name);
67 87
         
68
-        //main session
69
-        switch(self::$session_type) {
70
-            case 'file':
71
-                if(!file_exists(FILE_SESSION_DIR)) mkdir(FILE_SESSION_DIR);
72
-                $sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name;
73
-                if(!file_exists($sess_file)) file_put_contents($sess_file,'');
74
-                self::$session_fp = fopen($sess_file,'r+');
75
-                if(!READ_ONLY_SESSION && !flock(self::$session_fp,LOCK_EX)) 
76
-                    trigger_error('Unable to get lock on session file='.$sess_file,E_USER_ERROR);
77
-                $ret = stream_get_contents(self::$session_fp);
78
-                break;
79
-            case 'memcache':
80
-                if(!READ_ONLY_SESSION && !self::$memcached->lock(MEMCACHE_SESSION_TOKEN.$name,self::$memcached_lock_time))
81
-                    trigger_error('Unable to get lock on session mem='.$name,E_USER_ERROR);
82
-                $ret = '';
83
-                for($i=0;; $i++) {
84
-                    $rr = self::$memcached->get(MEMCACHE_SESSION_TOKEN.$name.'/'.$i);
85
-                    if($rr==='' || $rr===false || $rr===null) break;
86
-                    $ret .= $rr;
87
-                }
88
-                break;
89
-            case 'sql':
90
-                $ret = DB::GetCol('SELECT data FROM session WHERE name = %s AND expires > %d'.(READ_ONLY_SESSION?'':' FOR UPDATE'), array($name, time()-self::$lifetime));
91
-                if($ret) $ret = $ret[0];
92
-                break;
93
-        }
94
-        if($ret) $_SESSION = unserialize($ret);
95
-
96
-        if(CID===false) return '';
88
+        // ----- main session -----
89
+        if ($mainData = self::storage()->read($name))
90
+        	$_SESSION = $mainData;
91
+        
92
+        if (CID===false) return '';
97 93
         
98 94
         if(!is_numeric(CID))
99 95
             trigger_error('Invalid client id.',E_USER_ERROR);
100 96
 
101 97
         if(isset($_SESSION['session_destroyed'][CID])) return '';
102
-            
103
-        switch(self::$session_type) {
104
-            case 'file':
105
-                $sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name.'_'.CID;
106
-                if(!file_exists($sess_file)) file_put_contents($sess_file,'');
107
-                self::$session_client_fp = fopen($sess_file,'r+');
108
-                if(!READ_ONLY_SESSION && !flock(self::$session_client_fp,LOCK_EX)) 
109
-                    trigger_error('Unable to get lock on session file='.$sess_file,E_USER_ERROR);
110
-                $ret = stream_get_contents(self::$session_client_fp);
111
-                break;
112
-            case 'memcache':
113
-                if(!READ_ONLY_SESSION && !self::$memcached->lock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID,self::$memcached_lock_time))
114
-                    trigger_error('Unable to get lock on session mem='.$name.'_'.CID,E_USER_ERROR);
115
-                $ret = '';
116
-                for($i=0;; $i++) {
117
-                    $rr = self::$memcached->get(MEMCACHE_SESSION_TOKEN.$name.'_'.CID.'/'.$i);
118
-                    if($rr==='' || $rr===false || $rr===null) break;
119
-                    $ret .= $rr;
120
-                }
121
-                break;
122
-            case 'sql':
123
-                $ret = DB::GetCol('SELECT data FROM session_client WHERE session_name = %s AND client_id=%d'.(READ_ONLY_SESSION?'':' FOR UPDATE'), array($name, CID));
124
-                if($ret) $ret = $ret[0];
125
-                break;
126
-        }
127
-        if($ret) $_SESSION['client'] = unserialize($ret);
98
+        
99
+        // ----- client session -----
100
+        if ($clientData = self::storage()->read($name . '_' . CID))
101
+        	$_SESSION['client'] = $clientData;
128 102
 
129
-        if(!isset($_SESSION['client']['__module_vars__']))
130
-            $_SESSION['client']['__module_vars__'] = array();
103
+        $_SESSION['client']['__module_vars__'] = $_SESSION['client']['__module_vars__']?? [];
131 104
     }
132 105
 
133 106
     public function write($name, $data) {
134 107
         if(READ_ONLY_SESSION) return true;
135
-        $name = self::truncated_session_id($name);
108
+        
109
+        $name = self::truncated_id($name);
110
+        
136 111
         if(defined('SESSION_EXPIRED')) {
137
-            if(self::$session_type=='memcache') {
138
-                if(CID!==false) {
139
-                    self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID);
140
-                }
141
-                self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name);
142
-            }
112
+        	foreach ([
113
+        			$name,
114
+        			$name .'_' . CID
115
+        	] as $key) {
116
+        		self::storage()->unlock($key);
117
+        	}
118
+        	
143 119
             return true;
144 120
         }
121
+        
145 122
         $ret = 1;
146 123
         if(CID!==false && isset($_SESSION['client']) && !isset($_SESSION['session_destroyed'][CID])) {
147
-            $data = serialize($_SESSION['client']);
148
-            
149
-            switch(self::$session_type) {
150
-                case 'file':
151
-                    ftruncate(self::$session_client_fp, 0);      // truncate file
152
-                    rewind(self::$session_client_fp);
153
-                    fwrite(self::$session_client_fp, $data);
154
-                    fflush(self::$session_client_fp);            // flush output before releasing the lock
155
-                    flock(self::$session_client_fp, LOCK_UN);    // release the lock
156
-                    fclose(self::$session_client_fp);
157
-                    break;
158
-                case 'memcache':
159
-                    if(self::$memcached->is_lock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID,self::$memcached_lock_time)) {
160
-                        $data = str_split($data,1000000); //something little less then 1MB
161
-                        $data[] = '';
162
-                        foreach($data as $i=>$d) {
163
-                            self::$memcached->set(MEMCACHE_SESSION_TOKEN.$name.'_'.CID.'/'.$i, $d, self::$lifetime);
164
-                        }
165
-                        self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name.'_'.CID);
166
-                    }
167
-                    break;
168
-                case 'sql':
169
-                    if(DB::is_mysql())
170
-                        $data = DB::qstr($data);
171
-                    else
172
-                        $data = '\''.DB::BlobEncode($data).'\'';
173
-                    $ret &= (bool) DB::Replace('session_client',array('data'=>$data,'session_name'=>DB::qstr($name),'client_id'=>CID),array('session_name','client_id'));
174
-                    break;
175
-            }
176
-        }
177
-        if(isset($_SESSION['client'])) unset($_SESSION['client']);
178
-        $data = serialize($_SESSION);
179
-        switch(self::$session_type) {
180
-            case 'file':
181
-                ftruncate(self::$session_fp, 0);      // truncate file
182
-                rewind(self::$session_fp);
183
-                fwrite(self::$session_fp, $data);
184
-                fflush(self::$session_fp);            // flush output before releasing the lock
185
-                flock(self::$session_fp, LOCK_UN);    // release the lock
186
-                fclose(self::$session_fp);
187
-                $ret &= (bool) DB::Replace('session',array('expires'=>time(),'name'=>DB::qstr($name)),'name');
188
-                break;
189
-            case 'memcache':
190
-                if(self::$memcached->is_lock(MEMCACHE_SESSION_TOKEN.$name,self::$memcached_lock_time)) {
191
-                    $data = str_split($data,1000000); //something little less then 1MB
192
-                    $data[] = '';
193
-                    foreach($data as $i=>$d) {
194
-                        self::$memcached->set(MEMCACHE_SESSION_TOKEN.$name.'/'.$i, $d, self::$lifetime);
195
-                    }
196
-                    self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name);
197
-                    $ret &= (bool) DB::Replace('session',array('expires'=>time(),'name'=>DB::qstr($name)),'name');
198
-                }
199
-                break;
200
-            case 'sql':
201
-                if(DB::is_mysql())
202
-                    $data = DB::qstr($data);
203
-                else
204
-                    $data = '\''.DB::BlobEncode($data).'\'';
205
-                $ret &= (bool) DB::Replace('session',array('expires'=>time(),'data'=>$data,'name'=>DB::qstr($name)),'name');
206
-                break;
124
+        	$ret &= self::storage()->write($name . '_' . CID, $_SESSION['client']);
207 125
         }
126
+        
127
+        unset($_SESSION['client']);
128
+        
129
+        $ret &= self::storage()->write($name, $_SESSION);
130
+        
131
+		$ret &= (bool) DB::Replace('session', [
132
+				'expires' => time(),
133
+				'name' => DB::qstr($name)
134
+		], 'name');
208 135
 
209 136
         return $ret > 0;
210 137
     }
211 138
     
212
-    public static function destroy_client($name,$i) {
213
-        $name = self::truncated_session_id($name);
214
-        switch(self::$session_type) {
215
-            case 'file':
216
-                $sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name.'_'.$i;
217
-                @unlink($sess_file);
218
-                break;
219
-            case 'memcache':
220
-                for($k=0;;$k++)
221
-                    if(!self::$memcached->delete(MEMCACHE_SESSION_TOKEN.$name.'_'.$i.'/'.$k)) break;
222
-                self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name.'_'.$i);
223
-                break;
224
-            case 'sql':
225
-                DB::Execute('DELETE FROM session_client WHERE session_name=%s AND client_id=%d',array($name,$i));
226
-                break;
227
-        }
228
-        DB::Execute('DELETE FROM history WHERE session_name=%s AND client_id=%d',array($name,$i));
229
-    }
230
-
231 139
     public function destroy($name) {
232
-        $name = self::truncated_session_id($name);
140
+        $name = self::truncated_id($name);
233 141
         $cids = DB::GetCol('SELECT DISTINCT client_id FROM history WHERE session_name=%s',array($name));
234 142
         foreach($cids as $i)
235 143
             self::destroy_client($name,$i);
236 144
         
237
-        switch(self::$session_type) {
238
-            case 'file':
239
-                $sess_file = rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.$name;
240
-                @unlink($sess_file);
241
-                break;
242
-            case 'memcache':
243
-                for($k=0;;$k++)
244
-                    if(!self::$memcached->delete(MEMCACHE_SESSION_TOKEN.$name.'/'.$k)) break;
245
-                self::$memcached->unlock(MEMCACHE_SESSION_TOKEN.$name);
246
-                break;
247
-        }
145
+        self::storage()->destroy($name);
146
+        
248 147
         DB::BeginTrans();
249 148
         DB::Execute('DELETE FROM history WHERE session_name=%s',array($name));
250
-        DB::Execute('DELETE FROM session_client WHERE session_name=%s',array($name));
251 149
         DB::Execute('DELETE FROM session WHERE name=%s',array($name));
252 150
         DB::CommitTrans();
253 151
         return true;
254 152
     }
255 153
 
256 154
     public function gc($lifetime) {
257
-        $t = time()-$lifetime;
258
-        $ret = DB::Execute('SELECT name FROM session WHERE expires <= %d',array($t));
155
+        $before = time() - $lifetime;
156
+        $ret = DB::Execute('SELECT name FROM session WHERE expires <= %d', [$before]);
259 157
         while($row = $ret->FetchRow()) {
260 158
             self::destroy($row['name']);
261 159
         }
160
+        
161
+        self::storage()->cleanup($before);
262 162
 
263
-        if(FILE_SESSION_DIR) {
264
-            $files = @glob(rtrim(FILE_SESSION_DIR,'\\/').'/'.FILE_SESSION_TOKEN.'*');
265
-            if(!$files) return true;
266
-            foreach($files as $sess_file) {
267
-                if(filemtime($sess_file)<$t) @unlink($sess_file);
268
-            }
269
-        }
270 163
         return true;
271 164
     }
272 165
 }
273 166
 
274
-class EpesiMemcache {
275
-    private $memcached = null;
276
-    private $mcd = false;
277
-    
278
-    public function __construct() {
279
-        if(extension_loaded('memcached')) {
280
-            $this->memcached = new Memcached();
281
-            $this->mcd = true;
282
-        } elseif(extension_loaded('memcache')) {
283
-            $this->memcached = new Memcache();
284
-        } else {
285
-            trigger_error('Missing memcache PHP extension',E_USER_ERROR);
286
-        }
287
-    }
288
-    
289
-    public function add($key,$var,$exp=null) {
290
-        if($this->mcd) return $this->memcached->add($key,$var,$exp);
291
-        return $this->memcached->add($key,$var,null,$exp);
292
-    }
293
-    
294
-    public function set($key,$var,$exp=null) {
295
-        if($this->mcd) return $this->memcached->set($key,$var,$exp);
296
-        return $this->memcached->set($key,$var,null,$exp);
297
-    }
167
+abstract class EpesiSessionStorage {
168
+	protected $lifetime;
169
+	
170
+	public static function factory($class, $lifetime) {
171
+		return new $class($lifetime);
172
+	}
173
+	
174
+	public function __construct($lifetime) {
175
+		$this->setLifetime($lifetime);
176
+	}
177
+	
178
+	public static function active() {
179
+		return true;
180
+	}
181
+	
182
+	public static function tokenize($key) {
183
+		return $key;
184
+	}
185
+	
186
+	/**
187
+	 * Read value from storage corresponding to key
188
+	 * 
189
+	 * @param string $key
190
+	 */
191
+	abstract public function read($key);
192
+	
193
+	/**
194
+	 * Write value to storage
195
+	 * 
196
+	 * @param string $key
197
+	 * @param mixed $value
198
+	 */
199
+	abstract public function write($key, $value);
200
+	
201
+	abstract public function destroy($key);
202
+	
203
+	public function lock($key) {}
204
+	
205
+	public function unlock($key) {}
206
+	
207
+	public function cleanup($lifetime) {}
208
+	
209
+	public function getLifetime() {
210
+		return $this->lifetime;
211
+	}
298 212
 
299
-    public function is_lock($key,$exp=null) {
300
-        $key .= '#lock';
301
-        $v = $this->memcached->get($key);
302
-        return $v==$exp || ($exp===null && $v);
303
-    }
304
-    
305
-    public function lock($key,$exp) {
306
-        $key .= '#lock';
307
-        while(!$this->add($key,$exp,$exp) || $this->memcached->get($key)!=$exp) {
308
-            if(time()>$exp) return false;
309
-            usleep(100);
310
-        }
311
-        return true;
312
-    }
313
-    
314
-    public function unlock($key) {
315
-        $this->memcached->delete($key.'#lock');
316
-    }
317
-    
318
-    public function __call($f,$a) {
319
-        return call_user_func_array(array($this->memcached,$f),$a);
320
-    }
213
+	public function setLifetime($lifetime) {
214
+		$this->lifetime = $lifetime;
215
+		
216
+		return $this;
217
+	}
218
+}
219
+
220
+class EpesiSessionFileStorage extends EpesiSessionStorage {
221
+	protected static $filePointers;
222
+	
223
+	public static function tokenize($name) {
224
+		return FILE_SESSION_TOKEN . $name;
225
+	}
226
+	
227
+	public function read($name) {		
228
+		$file = self::getFile($name);		
229
+		
230
+		$filePointer = self::getFilePointer($file);
231
+		
232
+		if(!READ_ONLY_SESSION && !flock($filePointer, LOCK_EX))
233
+			trigger_error('Unable to get lock on session file=' . $file, E_USER_ERROR);
234
+		
235
+		$ret = stream_get_contents($filePointer);
236
+			
237
+		return $ret? unserialize($ret): '';
238
+	}
239
+	
240
+	public function write($name, $data) {
241
+		$filePointer = self::getFilePointer(self::getFile($name));
242
+		
243
+		ftruncate($filePointer, 0);      // truncate file
244
+		rewind($filePointer);
245
+		fwrite($filePointer, serialize($data));
246
+		fflush($filePointer);            // flush output before releasing the lock
247
+		flock($filePointer, LOCK_UN);    // release the lock
248
+		fclose($filePointer);
249
+		
250
+		return true;
251
+	}
252
+	
253
+	public function destroy($name) {
254
+		@unlink(self::getFile($name));
255
+	}
256
+	
257
+	public function cleanup($before) {
258
+		if(!FILE_SESSION_DIR) return;
259
+		
260
+		$files = @glob(rtrim(FILE_SESSION_DIR,'\\/'). DIRECTORY_SEPARATOR . FILE_SESSION_TOKEN . '*');
261
+		if(!$files) return true;
262
+		foreach($files as $file) {
263
+			if (filemtime($file) < $before) @unlink($file);
264
+		}
265
+	}
266
+
267
+	protected static function getFile($name) {
268
+		if(!file_exists(FILE_SESSION_DIR)) mkdir(FILE_SESSION_DIR);
269
+		
270
+		return rtrim(FILE_SESSION_DIR,'\\/') . DIRECTORY_SEPARATOR . self::tokenize($name);
271
+	}
272
+	
273
+	protected static function getFilePointer($file) {
274
+		if(!file_exists($file)) file_put_contents($file, '');
275
+		
276
+		$key = md5($file);
277
+		
278
+		self::$filePointers[$key] = self::$filePointers[$key]?? fopen($file, 'r+');
279
+		
280
+		return self::$filePointers[$key];
281
+	}
282
+}
283
+
284
+class EpesiSessionDBStorage extends EpesiSessionStorage {
285
+	public function read($name) {
286
+		$ret = DB::GetCol('SELECT 
287
+								data 
288
+							FROM 
289
+								session 
290
+							WHERE 
291
+								name = %s AND 
292
+								expires > %d' . (READ_ONLY_SESSION? '': ' FOR UPDATE'), [$name, time() - $this->getLifetime()]);
293
+		
294
+		return $ret? unserialize($ret[0]): '';
295
+	}
296
+	
297
+	public function write($name, $data) {
298
+		$data = serialize($data);
299
+
300
+		return (bool) DB::Replace('session', [
301
+				'expires' => time(),
302
+				'data' => DB::is_mysql()? DB::qstr($data): '\''.DB::BlobEncode($data).'\'',
303
+				'name' => DB::qstr($name)
304
+		], 'name');
305
+	}
306
+	
307
+	public function destroy($name) {
308
+		DB::Execute('DELETE FROM session WHERE name=%s', [$name]);
309
+	}	
310
+}
311
+
312
+class EpesiSessionMemcachedStorage extends EpesiSessionStorage {
313
+	private $memcached;
314
+	private $mcd = false;
315
+	private $lockTime;
316
+	
317
+	public static function active() {
318
+		return MEMCACHE_SESSION_SERVER? true: false;		
319
+	}
320
+	
321
+	public static function tokenize($name) {
322
+		return MEMCACHE_SESSION_TOKEN . $name;
323
+	}
324
+	
325
+	public function __construct($lifetime) {
326
+		parent::__construct($lifetime);
327
+		
328
+		if(extension_loaded('memcached')) {
329
+			$this->memcached = new Memcached();
330
+			$this->mcd = true;
331
+		} elseif(extension_loaded('memcache')) {
332
+			$this->memcached = new Memcache();
333
+		} else {
334
+			trigger_error('Missing memcache PHP extension',E_USER_ERROR);
335
+		}
336
+		
337
+		$this->lockTime = time() + (ini_get('max_execution_time')?: 60);
338
+		
339
+		$srv = explode(':', MEMCACHE_SESSION_SERVER, 2);
340
+			
341
+		if(!$this->memcached->addServer($srv[0], $srv[1]?? 11211))
342
+			trigger_error('Cannot connect to memcache server',E_USER_ERROR);
343
+	}
344
+	
345
+	public function read($name) {
346
+		$key = self::tokenize($name);
347
+		
348
+		if(!READ_ONLY_SESSION && !$this->lock($key))
349
+			trigger_error('Unable to get lock on session mem=' . $name, E_USER_ERROR);
350
+			
351
+		$ret = '';
352
+		for($i=0;; $i++) {
353
+			$rr = $this->get($key . '/' . $i);
354
+			if ($rr==='' || $rr===false || $rr===null) break;
355
+			$ret .= $rr;
356
+		}
357
+		
358
+		return $ret? unserialize($ret): '';
359
+	}
360
+	
361
+	public function write($name, $data) {
362
+		$key = self::tokenize($name);
363
+		
364
+		if (!$this->isLocked($key)) $this->lock($key);
365
+		
366
+		$data = str_split(serialize($data), 1000000); //something little less then 1MB
367
+		$data[] = '';
368
+		foreach($data as $i => $d) {
369
+			$this->memcached->set($key . '/' . $i, $d, $this->getLifetime());
370
+		}
371
+		
372
+		$this->unlock($key);
373
+				
374
+		return true;
375
+	}	
376
+	
377
+	public function destroy($name) {
378
+		for ($k=0;;$k++) {
379
+			if (!$this->memcached->delete(self::tokenize($name) . '/' . $k)) break;
380
+		}			
381
+		
382
+		$this->unlock(self::tokenize($name));
383
+	}
384
+	
385
+	public function add($key, $var, $exp=null) {
386
+		if ($this->mcd) return $this->memcached->add($key, $var, $exp);
387
+		
388
+		return $this->memcached->add($key, $var, null, $exp);
389
+	}
390
+	
391
+	public function set($key, $var, $exp=null) {
392
+		if ($this->mcd) return $this->memcached->set($key, $var, $exp);
393
+		
394
+		return $this->memcached->set($key, $var, null, $exp);
395
+	}
396
+	
397
+	public function isLocked($key) {
398
+		$key .= '#lock';
399
+		$exp = $this->lockTime;
400
+		
401
+		$v = $this->memcached->get($key);
402
+		
403
+		return $v==$exp || ($exp===null && $v);
404
+	}
405
+	
406
+	public function lock($key) {
407
+		$key .= '#lock';
408
+		$exp = $this->lockTime;
409
+
410
+		while(!$this->add($key, $exp, $exp) || $this->memcached->get($key) != $exp) {
411
+			if(time() > $exp) return false;
412
+			usleep(100);
413
+		}
414
+		
415
+		return true;
416
+	}
417
+	
418
+	public function unlock($key) {
419
+		$this->memcached->delete($key.'#lock');
420
+	}
421
+	
422
+	public function __call($method, $args) {
423
+		return call_user_func_array([$this->memcached, $method], $args);
424
+	}
321 425
 }
322 426
 
323 427
 // remember that even with SET_SESSION = false, class defined below is declared
324 428
 if(!SET_SESSION) {
325 429
     if(!isset($_SESSION) || !is_array($_SESSION))
326
-    	$_SESSION = array();
430
+    	$_SESSION = [];
327 431
     return;
328 432
 }
329 433
 
@@ -334,7 +438,7 @@ if(defined('EPESI_PROCESS')) {
334 438
     ini_set('session.gc_probability', 0);
335 439
 }
336 440
 
337
-session_set_save_handler(new DBSession());
441
+session_set_save_handler(EpesiSession::create());
338 442
 
339 443
 if(extension_loaded('apc') || extension_loaded('eaccelerator') || extension_loaded('xcache')) //fix for class DBSession not found
340 444
     register_shutdown_function('session_write_close');

+ 1
- 1
init_js.php View File

@@ -30,7 +30,7 @@ $_SESSION['num_of_clients'] = $client_id_next;
30 30
 
31 31
 //DBSession::destroy_client(session_id(),$client_id);
32 32
 if($client_id-5>=0) {
33
-    DBSession::destroy_client(session_id(),$client_id-5);
33
+    EpesiSession::destroy_client(session_id(),$client_id-5);
34 34
     $_SESSION['session_destroyed'][$client_id-5] = 1;
35 35
 }
36 36
 session_commit();

+ 2
- 5
modules/CRM/Roundcube/RC/config/config.inc.php View File

@@ -18,11 +18,8 @@ global $E_SESSION,$E_SESSION_ID;
18 18
 $E_SESSION_ID = $_COOKIE[session_name()];
19 19
 if(!$E_SESSION_ID)
20 20
     $E_SESSION_ID = $_REQUEST[session_name()];
21
-$tmp = $_SESSION;
22
-DBSession::open('',$E_SESSION_ID);
23
-DBSession::read($E_SESSION_ID);
24
-$E_SESSION = $_SESSION;
25
-$_SESSION = $tmp;
21
+
22
+$E_SESSION = EpesiSession::get($E_SESSION_ID);
26 23
 
27 24
 chdir($d);
28 25
 $data_dir = EPESI_LOCAL_DIR.'/'.DATA_DIR.'/CRM_Roundcube/tmp/';

+ 2
- 4
modules/CRM/Roundcube/RC/plugins/epesi_archive/epesi_archive.php View File

@@ -128,10 +128,8 @@ class epesi_archive extends rcube_plugin
128 128
         $rcmail->output->show_message($this->gettext('archived'), 'confirmation');
129 129
     }
130 130
     global $E_SESSION_ID,$E_SESSION;
131
-    $tmp = $_SESSION;
132
-    $_SESSION = $E_SESSION;
133
-    DBSession::write($E_SESSION_ID,'');
134
-    $_SESSION = $tmp;
131
+
132
+    EpesiSession::set($E_SESSION_ID, $E_SESSION);
135 133
   }
136 134
 
137 135
   private function archive($uids,$verbose=true) {

+ 1
- 1
modules/Tools/WhoIsOnline/WhoIsOnlineCommon_0.php View File

@@ -33,7 +33,7 @@ class Tools_WhoIsOnlineCommon extends ModuleCommon {
33 33
 if(!array_key_exists('tools_whoisonline', $_SESSION)
34 34
    || $_SESSION['tools_whoisonline'] != Base_AclCommon::get_user()) {
35 35
     $current_user = Base_AclCommon::get_user();
36
-    $session_id = DBSession::truncated_session_id();
36
+    $session_id = EpesiSession::truncated_id();
37 37
     if ($current_user && Base_User_SettingsCommon::get('Tools_WhoIsOnline','show_me')) {
38 38
         if (DB::GetOne('SELECT COUNT(*) FROM tools_whoisonline_users WHERE session_name=%s', array($session_id)) == 0) {
39 39
             @DB::Execute('INSERT INTO tools_whoisonline_users(session_name,user_login_id) VALUES(%s,%d)',array($session_id, $current_user));

+ 5
- 7
monitoring.php View File

@@ -64,19 +64,17 @@ function test_database() {
64 64
 function test_session() {
65 65
     $tag = microtime(1);
66 66
     $session_id = 'monitoring_'.md5(DATABASE_NAME.'#'.DATABASE_HOST.'#'.DATABASE_DRIVER);
67
-    DBSession::open('','');
68
-    DBSession::read($session_id);
67
+    $_SESSION = EpesiSession::get($session_id);
69 68
     $_SESSION['monitoring'] = $tag;
70 69
     $_SESSION['client']['monitoring'] = $tag;
71
-    DBSession::write($session_id,'');
72
-    $_SESSION = array();
73
-    DBSession::read($session_id);
70
+    EpesiSession::set($session_id, $_SESSION);
71
+    $_SESSION = EpesiSession::get($session_id);
74 72
     if(!isset($_SESSION['monitoring']) || !isset($_SESSION['client']['monitoring']) || $_SESSION['monitoring'] != $tag || $_SESSION['client']['monitoring'] != $tag) {
75
-        DBSession::write($session_id,'');
73
+    	EpesiSession::set($session_id, $_SESSION);
76 74
         if(isset($_GET['number']) && $_GET['number']) die('999999');
77 75
         die('error: session');
78 76
     }
79
-    DBSession::write($session_id,'');
77
+    EpesiSession::set($session_id, $_SESSION);
80 78
 }
81 79
 
82 80
 function test_data_directory() {

+ 1
- 1
process.php View File

@@ -33,7 +33,7 @@ if(!isset($_SESSION['num_of_clients'])) {
33 33
 	Epesi::redirect();
34 34
 	Epesi::send_output();
35 35
 	define('SESSION_EXPIRED',1);
36
-	DBSession::destroy_client(session_id(),CID);
36
+	EpesiSession::destroy_client(session_id(),CID);
37 37
 } else {
38 38
 	Epesi::process($_POST['url'],isset($_POST['history'])?$_POST['history']:false);
39 39
 }

Loading…
Cancel
Save