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