@@ -73,6 +73,16 @@ class FileHandler extends BaseHandler implements \SessionHandlerInterface
7373 */
7474 protected $ fileNew ;
7575
76+ /**
77+ * @var boolean
78+ */
79+ protected $ matchIP = false ;
80+
81+ /**
82+ * @var string
83+ */
84+ protected $ sessionIDRegex ;
85+
7686 //--------------------------------------------------------------------
7787
7888 /**
@@ -91,14 +101,19 @@ public function __construct($config, string $ipAddress)
91101 }
92102 else
93103 {
94- $ sessionPath = rtrim (ini_get ('session.save_path ' ), '/ \\' );
104+ $ sessionPath = rtrim (ini_get ('session.save_path ' ), '/ \\' );
105+
95106 if (! $ sessionPath )
96- {
107+ {
97108 $ sessionPath = WRITEPATH . 'session ' ;
98109 }
99110
100- $ this ->savePath = $ sessionPath ;
111+ $ this ->savePath = $ sessionPath ;
101112 }
113+
114+ $ this ->matchIP = $ config ->sessionMatchIP ;
115+
116+ $ this ->configureSessionIDRegex ();
102117 }
103118
104119 //--------------------------------------------------------------------
@@ -130,8 +145,8 @@ public function open($savePath, $name): bool
130145
131146 $ this ->savePath = $ savePath ;
132147 $ this ->filePath = $ this ->savePath . '/ '
133- . $ name // we'll use the session cookie name as a prefix to avoid collisions
134- . ($ this ->matchIP ? md5 ($ this ->ipAddress ) : '' );
148+ . $ name // we'll use the session cookie name as a prefix to avoid collisions
149+ . ($ this ->matchIP ? md5 ($ this ->ipAddress ) : '' );
135150
136151 return true ;
137152 }
@@ -219,7 +234,7 @@ public function write($sessionID, $sessionData): bool
219234 {
220235 // If the two IDs don't match, we have a session_regenerate_id() call
221236 // and we need to close the old handle and open a new one
222- if ($ sessionID !== $ this ->sessionID && ( ! $ this ->close () || $ this ->read ($ sessionID ) === false ))
237+ if ($ sessionID !== $ this ->sessionID && (! $ this ->close () || $ this ->read ($ sessionID ) === false ))
223238 {
224239 return false ;
225240 }
@@ -302,13 +317,15 @@ public function destroy($session_id): bool
302317 {
303318 if ($ this ->close ())
304319 {
305- return is_file ($ this ->filePath . $ session_id ) ? (unlink ($ this ->filePath . $ session_id ) && $ this ->destroyCookie ()) : true ;
320+ return is_file ($ this ->filePath . $ session_id )
321+ ? (unlink ($ this ->filePath . $ session_id ) && $ this ->destroyCookie ()) : true ;
306322 }
307323 elseif ($ this ->filePath !== null )
308324 {
309325 clearstatcache ();
310326
311- return is_file ($ this ->filePath . $ session_id ) ? (unlink ($ this ->filePath . $ session_id ) && $ this ->destroyCookie ()) : true ;
327+ return is_file ($ this ->filePath . $ session_id )
328+ ? (unlink ($ this ->filePath . $ session_id ) && $ this ->destroyCookie ()) : true ;
312329 }
313330
314331 return false ;
@@ -336,20 +353,28 @@ public function gc($maxlifetime): bool
336353
337354 $ ts = time () - $ maxlifetime ;
338355
356+ $ pattern = $ this ->matchIP === true
357+ ? '[0-9a-f]{32} '
358+ : '' ;
359+
339360 $ pattern = sprintf (
340- '/^%s[0-9a-f]{%d}$/ ' , preg_quote ($ this ->cookieName , '/ ' ), ($ this ->matchIP === true ? 72 : 40 )
361+ '#\A%s ' . $ pattern . $ this ->sessionIDRegex . '\z# ' ,
362+ preg_quote ($ this ->cookieName )
341363 );
342364
343365 while (($ file = readdir ($ directory )) !== false )
344366 {
345367 // If the filename doesn't match this pattern, it's either not a session file or is not ours
346- if (! preg_match ($ pattern , $ file ) || ! is_file ($ this ->savePath . '/ ' . $ file ) || ($ mtime = filemtime ($ this ->savePath . '/ ' . $ file )) === false || $ mtime > $ ts
368+ if (! preg_match ($ pattern , $ file )
369+ || ! is_file ($ this ->savePath . DIRECTORY_SEPARATOR . $ file )
370+ || ($ mtime = filemtime ($ this ->savePath . DIRECTORY_SEPARATOR . $ file )) === false
371+ || $ mtime > $ ts
347372 )
348373 {
349374 continue ;
350375 }
351376
352- unlink ($ this ->savePath . ' / ' . $ file );
377+ unlink ($ this ->savePath . DIRECTORY_SEPARATOR . $ file );
353378 }
354379
355380 closedir ($ directory );
@@ -358,4 +383,36 @@ public function gc($maxlifetime): bool
358383 }
359384
360385 //--------------------------------------------------------------------
386+
387+ /**
388+ * Configure Session ID regular expression
389+ */
390+ protected function configureSessionIDRegex ()
391+ {
392+ $ bitsPerCharacter = (int )ini_get ('session.sid_bits_per_character ' );
393+ $ SIDLength = (int )ini_get ('session.sid_length ' );
394+
395+ if (($ bits = $ SIDLength * $ bitsPerCharacter ) < 160 )
396+ {
397+ // Add as many more characters as necessary to reach at least 160 bits
398+ $ SIDLength += (int )ceil ((160 % $ bits ) / $ bitsPerCharacter );
399+ ini_set ('session.sid_length ' , $ SIDLength );
400+ }
401+
402+ // Yes, 4,5,6 are the only known possible values as of 2016-10-27
403+ switch ($ bitsPerCharacter )
404+ {
405+ case 4 :
406+ $ this ->sessionIDRegex = '[0-9a-f] ' ;
407+ break ;
408+ case 5 :
409+ $ this ->sessionIDRegex = '[0-9a-v] ' ;
410+ break ;
411+ case 6 :
412+ $ this ->sessionIDRegex = '[0-9a-zA-Z,-] ' ;
413+ break ;
414+ }
415+
416+ $ this ->sessionIDRegex .= '{ ' . $ SIDLength . '} ' ;
417+ }
361418}
0 commit comments