TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
SessionService.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Install\Service;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 
23 {
30  private $basePath;
31 
38  private $sessionPath = 'InstallToolSessions/%s';
39 
45  private $cookieName = 'Typo3InstallTool';
46 
52  private $expireTimeInMinutes = 60;
53 
60 
66  public function __construct()
67  {
68  $this->basePath = PATH_site . 'typo3temp/var/';
69  // Start our PHP session early so that hasSession() works
70  $sessionSavePath = $this->getSessionSavePath();
71  // Register our "save" session handler
72  session_set_save_handler([$this, 'open'], [$this, 'close'], [$this, 'read'], [$this, 'write'], [$this, 'destroy'], [$this, 'gc']);
73  session_save_path($sessionSavePath);
74  session_name($this->cookieName);
75  ini_set('session.cookie_path', GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'));
76  // Always call the garbage collector to clean up stale session files
77  ini_set('session.gc_probability', 100);
78  ini_set('session.gc_divisor', 100);
79  ini_set('session.gc_maxlifetime', $this->expireTimeInMinutes * 2 * 60);
80  if (\TYPO3\CMS\Core\Utility\PhpOptionsUtility::isSessionAutoStartEnabled()) {
81  $sessionCreationError = 'Error: session.auto-start is enabled.<br />';
82  $sessionCreationError .= 'The PHP option session.auto-start is enabled. Disable this option in php.ini or .htaccess:<br />';
83  $sessionCreationError .= '<pre>php_value session.auto_start Off</pre>';
84  throw new \TYPO3\CMS\Install\Exception($sessionCreationError, 1294587485);
85  } elseif (defined('SID')) {
86  $sessionCreationError = 'Session already started by session_start().<br />';
87  $sessionCreationError .= 'Make sure no installed extension is starting a session in its ext_localconf.php or ext_tables.php.';
88  throw new \TYPO3\CMS\Install\Exception($sessionCreationError, 1294587486);
89  }
90  session_start();
91  }
92 
99  private function getSessionSavePath()
100  {
101  if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
102  throw new \TYPO3\CMS\Install\Exception(
103  'No encryption key set to secure session',
104  1371243449
105  );
106  }
107  $sessionSavePath = sprintf(
108  $this->basePath . $this->sessionPath,
109  GeneralUtility::hmac('session:' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])
110  );
111  $this->ensureSessionSavePathExists($sessionSavePath);
112  return $sessionSavePath;
113  }
114 
122  private function ensureSessionSavePathExists($sessionSavePath)
123  {
124  if (!is_dir($sessionSavePath)) {
125  try {
126  GeneralUtility::mkdir_deep($sessionSavePath);
127  } catch (\RuntimeException $exception) {
128  throw new \TYPO3\CMS\Install\Exception(
129  'Could not create session folder in typo3temp/. Make sure it is writeable!',
130  1294587484
131  );
132  }
133  $htaccessContent = '
134 # Apache < 2.3
135 <IfModule !mod_authz_core.c>
136  Order allow,deny
137  Deny from all
138  Satisfy All
139 </IfModule>
140 
141 # Apache ≥ 2.3
142 <IfModule mod_authz_core.c>
143  Require all denied
144 </IfModule>
145  ';
146  GeneralUtility::writeFile($sessionSavePath . '/.htaccess', $htaccessContent);
147  $indexContent = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">';
148  $indexContent .= '<HTML><HEAD<TITLE></TITLE><META http-equiv=Refresh Content="0; Url=../../">';
149  $indexContent .= '</HEAD></HTML>';
150  GeneralUtility::writeFile($sessionSavePath . '/index.html', $indexContent);
151  }
152  }
153 
159  public function startSession()
160  {
161  $_SESSION['active'] = true;
162  // Be sure to use our own session id, so create a new one
163  return $this->renewSession();
164  }
165 
169  public function destroySession()
170  {
171  session_destroy();
172  }
173 
177  public function resetSession()
178  {
179  $_SESSION = [];
180  $_SESSION['active'] = false;
181  }
182 
188  private function renewSession()
189  {
190  session_regenerate_id();
191  return session_id();
192  }
193 
199  public function hasSession()
200  {
201  return $_SESSION['active'] === true;
202  }
203 
209  public function getSessionId()
210  {
211  return session_id();
212  }
213 
222  private function getSessionHash($sessionId = '')
223  {
224  if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) {
225  throw new \TYPO3\CMS\Install\Exception(
226  'No encryption key set to secure session',
227  1371243450
228  );
229  }
230  if (!$sessionId) {
231  $sessionId = $this->getSessionId();
232  }
233  return md5($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . '|' . $sessionId);
234  }
235 
244  public function setAuthorized()
245  {
246  $_SESSION['authorized'] = true;
247  $_SESSION['lastSessionId'] = time();
248  $_SESSION['tstamp'] = time();
249  $_SESSION['expires'] = time() + $this->expireTimeInMinutes * 60;
250  // Renew the session id to avoid session fixation
251  $this->renewSession();
252  }
253 
259  public function isAuthorized()
260  {
261  if (!$_SESSION['authorized']) {
262  return false;
263  }
264  if ($_SESSION['expires'] < time()) {
265  // This session has already expired
266  return false;
267  }
268  return true;
269  }
270 
278  public function isExpired()
279  {
280  if (!$_SESSION['authorized']) {
281  // Session never existed, means it is not "expired"
282  return false;
283  }
284  if ($_SESSION['expires'] < time()) {
285  // This session was authorized before, but has expired
286  return true;
287  }
288  return false;
289  }
290 
298  public function refreshSession()
299  {
300  $_SESSION['tstamp'] = time();
301  $_SESSION['expires'] = time() + $this->expireTimeInMinutes * 60;
302  if (time() > $_SESSION['lastSessionId'] + $this->regenerateSessionIdTime * 60) {
303  // Renew our session ID
304  $_SESSION['lastSessionId'] = time();
305  $this->renewSession();
306  }
307  }
308 
315  public function addMessage(\TYPO3\CMS\Install\Status\StatusInterface $message)
316  {
317  if (!is_array($_SESSION['messages'])) {
318  $_SESSION['messages'] = [];
319  }
320  $_SESSION['messages'][] = $message;
321  }
322 
328  public function getMessagesAndFlush()
329  {
330  $messages = [];
331  if (is_array($_SESSION['messages'])) {
332  $messages = $_SESSION['messages'];
333  }
334  $_SESSION['messages'] = [];
335  return $messages;
336  }
337 
338  /*************************
339  *
340  * PHP session handling with "secure" session files (hashed session id)
341  * see http://www.php.net/manual/en/function.session-set-save-handler.php
342  *
343  *************************/
350  private function getSessionFile($id)
351  {
352  $sessionSavePath = $this->getSessionSavePath();
353  return $sessionSavePath . '/hash_' . $this->getSessionHash($id);
354  }
355 
363  public function open($savePath, $sessionName)
364  {
365  return true;
366  }
367 
373  public function close()
374  {
375  return true;
376  }
377 
384  public function read($id)
385  {
386  $sessionFile = $this->getSessionFile($id);
387  $content = '';
388  if (file_exists($sessionFile)) {
389  if ($fd = fopen($sessionFile, 'rb')) {
390  $lockres = flock($fd, LOCK_SH);
391  if ($lockres) {
392  $content = fread($fd, filesize($sessionFile));
393  flock($fd, LOCK_UN);
394  }
395  fclose($fd);
396  }
397  }
398  // Do a "test write" of the session file after opening it. The real session data is written in
399  // __destruct() and we can not create a sane error message there anymore, so this test should fail
400  // before if final session file can not be written due to permission problems.
401  $this->write($id, $content);
402  return $content;
403  }
404 
413  public function write($id, $sessionData)
414  {
415  $sessionFile = $this->getSessionFile($id);
416  $result = false;
417  $changePermissions = !@is_file($sessionFile);
418  if ($fd = fopen($sessionFile, 'cb')) {
419  if (flock($fd, LOCK_EX)) {
420  ftruncate($fd, 0);
421  $res = fwrite($fd, $sessionData);
422  if ($res !== false) {
423  fflush($fd);
424  $result = true;
425  }
426  flock($fd, LOCK_UN);
427  }
428  fclose($fd);
429  // Change the permissions only if the file has just been created
430  if ($changePermissions) {
431  GeneralUtility::fixPermissions($sessionFile);
432  }
433  }
434  if (!$result) {
435  throw new Exception(
436  'Session file not writable. Please check permission on typo3temp/var/InstallToolSessions and its subdirectories.',
437  1424355157
438  );
439  }
440  return $result;
441  }
442 
449  public function destroy($id)
450  {
451  $sessionFile = $this->getSessionFile($id);
452  return @unlink($sessionFile);
453  }
454 
461  public function gc($maxLifeTime)
462  {
463  $sessionSavePath = $this->getSessionSavePath();
464  $files = glob($sessionSavePath . '/hash_*');
465  if (!is_array($files)) {
466  return true;
467  }
468  foreach ($files as $filename) {
469  if (filemtime($filename) + $this->expireTimeInMinutes * 60 < time()) {
470  @unlink($filename);
471  }
472  }
473  return true;
474  }
475 
489  public function __destruct()
490  {
491  session_write_close();
492  }
493 }
addMessage(\TYPO3\CMS\Install\Status\StatusInterface $message)
static mkdir_deep($directory, $deepDirectory= '')
static writeFile($file, $content, $changePermissions=false)
static fixPermissions($path, $recursive=false)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static hmac($input, $additionalSecret= '')