‪TYPO3CMS  ‪main
FileSessionHandler.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
24 
29 class ‪FileSessionHandler implements \SessionHandlerInterface
30 {
32 
38  private string ‪$sessionPath;
39 
44 
45  public function ‪__construct(
46  string ‪$sessionPath,
48  private readonly ‪HashService $hashService
49  ) {
50  $this->sessionPath = rtrim(‪$sessionPath, '/') . '/';
51  $this->expirationTimeInMinutes = ‪$expirationTimeInMinutes;
52  // Start our PHP session early so that hasSession() works
53  session_save_path($this->‪getSessionSavePath());
54  }
55 
62  private function ‪getSessionSavePath()
63  {
64  if (empty(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
65  throw new \TYPO3\CMS\Install\Exception(
66  'No encryption key set to secure session',
67  1371243449
68  );
69  }
70  $sessionSavePath = $this->sessionPath . $this->hashService->hmac('session:' . ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'], self::class);
71  $this->‪ensureSessionSavePathExists($sessionSavePath);
72  return $sessionSavePath;
73  }
74 
80  private function ‪getSessionFile(string $id)
81  {
82  $sessionSavePath = $this->‪getSessionSavePath();
83  return $sessionSavePath . '/hash_' . $this->‪getSessionHash($id);
84  }
85 
89  public function ‪open(string $path, string $name): bool
90  {
91  return true;
92  }
93 
97  public function ‪close(): bool
98  {
99  return true;
100  }
101 
105  public function ‪read(string $id): string|false
106  {
107  $sessionFile = $this->‪getSessionFile($id);
108  $content = '';
109  if (file_exists($sessionFile)) {
110  if ($fd = fopen($sessionFile, 'rb')) {
111  $lockres = flock($fd, LOCK_SH);
112  if ($lockres) {
113  $length = (int)filesize($sessionFile);
114  if ($length > 0) {
115  $content = (string)fread($fd, $length);
116  }
117  flock($fd, LOCK_UN);
118  }
119  fclose($fd);
120  }
121  }
122  // Do a "test write" of the session file after opening it. The real session data is written in
123  // __destruct() and we can not create a sane error message there anymore, so this test should fail
124  // before if final session file can not be written due to permission problems.
125  $this->‪write($id, $content);
126  return $content;
127  }
128 
132  public function ‪write(string $id, string $data): bool
133  {
134  $sessionFile = $this->‪getSessionFile($id);
135  $result = false;
136  $changePermissions = !@is_file($sessionFile);
137  if ($fd = fopen($sessionFile, 'cb')) {
138  if (flock($fd, LOCK_EX)) {
139  ftruncate($fd, 0);
140  $res = fwrite($fd, $data);
141  if ($res !== false) {
142  fflush($fd);
143  $result = true;
144  }
145  flock($fd, LOCK_UN);
146  }
147  fclose($fd);
148  // Change the permissions only if the file has just been created
149  if ($changePermissions) {
150  ‪GeneralUtility::fixPermissions($sessionFile);
151  }
152  }
153  if (!$result) {
154  throw new ‪Exception(
155  'Session file not writable. Please check permission on ' .
156  $this->sessionPath . ' and its subdirectories.',
157  1424355157
158  );
159  }
160  return true;
161  }
162 
166  public function ‪destroy(string $id): bool
167  {
168  $sessionFile = $this->‪getSessionFile($id);
169  return @unlink($sessionFile);
170  }
171 
177  public function ‪gc(int $maxLifeTime): int|false
178  {
179  $sessionSavePath = $this->‪getSessionSavePath();
180  $files = glob($sessionSavePath . '/hash_*');
181  if (!is_array($files)) {
182  return 0;
183  }
184  $deleted = 0;
185  foreach ($files as $filename) {
186  if (filemtime($filename) + $this->expirationTimeInMinutes * 60 < time()) {
187  @unlink($filename);
188  $deleted++;
189  }
190  }
191  return $deleted;
192  }
193 
205  public function ‪__destruct()
206  {
207  session_write_close();
208  }
209 
215  public function ‪getSessionId(): string|false
216  {
217  return session_id();
218  }
219 
228  private function ‪getSessionHash(string $sessionId = ''): string
229  {
230  if (empty(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
231  throw new \TYPO3\CMS\Install\Exception(
232  'No encryption key set to secure session',
233  1371243450
234  );
235  }
236  if (!$sessionId) {
237  $sessionId = (string)($this->‪getSessionId() ?: '');
238  }
239  return md5(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . '|' . $sessionId);
240  }
241 
249  private function ‪ensureSessionSavePathExists(string $sessionSavePath): void
250  {
251  if (!is_dir($sessionSavePath)) {
252  try {
253  ‪GeneralUtility::mkdir_deep($sessionSavePath);
254  } catch (\RuntimeException $exception) {
255  throw new \TYPO3\CMS\Install\Exception(
256  'Could not create session folder in ' . $this->sessionPath . '. Make sure it is writeable!',
257  1294587484
258  );
259  }
260  $htaccessContent = '
261 # Apache < 2.3
262 <IfModule !mod_authz_core.c>
263  Order allow,deny
264  Deny from all
265  Satisfy All
266 </IfModule>
267 
268 # Apache ≥ 2.3
269 <IfModule mod_authz_core.c>
270  Require all denied
271 </IfModule>
272  ';
273  ‪GeneralUtility::writeFile($sessionSavePath . '/.htaccess', $htaccessContent);
274  $indexContent = '<!DOCTYPE html>';
275  $indexContent .= '<html><head><title></title><meta http-equiv=Refresh Content="0; Url=../../"/>';
276  $indexContent .= '</head></html>';
277  ‪GeneralUtility::writeFile($sessionSavePath . '/index.html', $indexContent);
278  }
279  }
280 }
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\getSessionFile
‪string getSessionFile(string $id)
Definition: FileSessionHandler.php:80
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\destroy
‪destroy(string $id)
Definition: FileSessionHandler.php:166
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\getSessionSavePath
‪string getSessionSavePath()
Definition: FileSessionHandler.php:62
‪TYPO3\CMS\Install\Service\Exception
Definition: ConfigurationChangedException.php:18
‪TYPO3\CMS\Core\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Install\Service\Session
Definition: FileSessionHandler.php:18
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler
Definition: FileSessionHandler.php:30
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\close
‪close()
Definition: FileSessionHandler.php:97
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep(string $directory)
Definition: GeneralUtility.php:1654
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\open
‪open(string $path, string $name)
Definition: FileSessionHandler.php:89
‪TYPO3\CMS\Core\Security\BlockSerializationTrait
Definition: BlockSerializationTrait.php:28
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\__destruct
‪__destruct()
Definition: FileSessionHandler.php:205
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\$sessionPath
‪string $sessionPath
Definition: FileSessionHandler.php:38
‪TYPO3\CMS\Core\Utility\GeneralUtility\writeFile
‪static bool writeFile(string $file, string $content, bool $changePermissions=false)
Definition: GeneralUtility.php:1469
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\ensureSessionSavePathExists
‪ensureSessionSavePathExists(string $sessionSavePath)
Definition: FileSessionHandler.php:249
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\getSessionId
‪string false getSessionId()
Definition: FileSessionHandler.php:215
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\__construct
‪__construct(string $sessionPath, int $expirationTimeInMinutes, private readonly HashService $hashService)
Definition: FileSessionHandler.php:45
‪TYPO3\CMS\Core\Utility\GeneralUtility\fixPermissions
‪static bool fixPermissions(string $path, bool $recursive=false)
Definition: GeneralUtility.php:1496
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\$expirationTimeInMinutes
‪int $expirationTimeInMinutes
Definition: FileSessionHandler.php:43
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\getSessionHash
‪string getSessionHash(string $sessionId='')
Definition: FileSessionHandler.php:228
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\gc
‪gc(int $maxLifeTime)
Definition: FileSessionHandler.php:177
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\write
‪write(string $id, string $data)
Definition: FileSessionHandler.php:132
‪TYPO3\CMS\Core\Crypto\HashService
Definition: HashService.php:27
‪TYPO3\CMS\Install\Service\Session\FileSessionHandler\read
‪read(string $id)
Definition: FileSessionHandler.php:105