|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2009-2011 Ernesto Baschny <ernst@cron-it.de> 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 00028 /** 00029 * Secure session handling for the install tool. 00030 * 00031 * @author Ernesto Baschny <ernst@cron-it.de> 00032 * 00033 * @package TYPO3 00034 * @subpackage tx_install 00035 * 00036 * @version $Id: class.tx_install_session.php 10636 2011-02-25 16:30:29Z baschny $ 00037 */ 00038 class tx_install_session { 00039 00040 /** 00041 * The path to our typo3temp (where we can write our sessions). Set in the 00042 * constructor. 00043 * 00044 * @var string 00045 */ 00046 private $typo3tempPath; 00047 00048 /** 00049 * Path where to store our session files in typo3temp. %s will be 00050 * non-guesseable. 00051 * 00052 * @var string 00053 */ 00054 private $sessionPath = 'sessions%s'; 00055 00056 /** 00057 * the cookie to store the session ID of the install tool 00058 * 00059 * @var string 00060 */ 00061 private $cookieName = 'Typo3InstallTool'; 00062 00063 /** 00064 * time (minutes) to expire an ununsed session 00065 * 00066 * @var integer 00067 */ 00068 private $expireTimeInMinutes = 60; 00069 00070 /** 00071 * time (minutes) to generate a new session id for our current session 00072 * 00073 * @var integer 00074 */ 00075 private $regenerateSessionIdTime = 5; 00076 00077 /** 00078 * part of the referer when the install tool has been called from the backend 00079 * 00080 * @var string 00081 */ 00082 private $backendFile = 'backend.php'; 00083 00084 /** 00085 * Constructor. Starts PHP session handling in our own private store 00086 * 00087 * Side-effect: might set a cookie, so must be called before any other output. 00088 */ 00089 public function __construct() { 00090 $this->typo3tempPath = PATH_site . 'typo3temp/'; 00091 00092 // Start our PHP session early so that hasSession() works 00093 $sessionSavePath = $this->getSessionSavePath(); 00094 if (!is_dir($sessionSavePath)) { 00095 if (!t3lib_div::mkdir($sessionSavePath)) { 00096 throw new Exception('<p><strong>Could not create session folder in typo3temp/.</strong></p><p>Make sure it is writeable!</p>'); 00097 } 00098 t3lib_div::writeFile($sessionSavePath.'/.htaccess', 'Order deny, allow'."\n".'Deny from all'."\n"); 00099 $indexContent = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">'; 00100 $indexContent .= '<HTML><HEAD<TITLE></TITLE><META http-equiv=Refresh Content="0; Url=../../">'; 00101 $indexContent .= '</HEAD></HTML>'; 00102 t3lib_div::writeFile($sessionSavePath.'/index.html', $indexContent); 00103 } 00104 // Register our "save" session handler 00105 session_set_save_handler( 00106 array($this, 'open'), 00107 array($this, 'close'), 00108 array($this, 'read'), 00109 array($this, 'write'), 00110 array($this, 'destroy'), 00111 array($this, 'gc') 00112 ); 00113 session_save_path($sessionSavePath); 00114 session_name($this->cookieName); 00115 ini_set('session.cookie_path', t3lib_div::getIndpEnv('TYPO3_SITE_PATH')); 00116 // Always call the garbage collector to clean up stale session files 00117 ini_set('session.gc_probability', 100); 00118 ini_set('session.gc_divisor', 100); 00119 ini_set('session.gc_maxlifetime', $this->expireTimeInMinutes*2*60); 00120 if (version_compare(phpversion(), '5.2', '<')) { 00121 ini_set('session.cookie_httponly', TRUE); 00122 } 00123 if (ini_get('session.auto_start')) { 00124 $sessionCreationError = '<p><strong>Error: session.auto-start is enabled</strong></p>'; 00125 $sessionCreationError .= '<p>The PHP option session.auto-start is enabled. Disable this option in php.ini or .htaccess:</p>'; 00126 $sessionCreationError .= '<pre>php_value session.auto_start Off</pre>'; 00127 throw new Exception($sessionCreationError); 00128 } else if (defined('SID')) { 00129 $sessionCreationError = '<p><strong>Error: Session already started by session_start().</strong></p>'; 00130 $sessionCreationError .= '<p>Make sure no installed extension is starting a session in its ext_localconf.php or ext_tables.php.</p>'; 00131 throw new Exception($sessionCreationError); 00132 } 00133 session_start(); 00134 } 00135 00136 /** 00137 * Returns the path where to store our session files 00138 */ 00139 private function getSessionSavePath() { 00140 return sprintf( 00141 $this->typo3tempPath . $this->sessionPath, 00142 md5( 00143 'session:' . 00144 $GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'] 00145 ) 00146 ); 00147 } 00148 00149 /** 00150 * Starts a new session 00151 * 00152 * @return string The session ID 00153 */ 00154 public function startSession() { 00155 $_SESSION['created'] = time(); 00156 // Be sure to use our own session id, so create a new one 00157 return $this->renewSession(); 00158 } 00159 00160 /** 00161 * Destroys a session 00162 * 00163 */ 00164 public function destroySession() { 00165 session_destroy(); 00166 } 00167 00168 /** 00169 * Generates a new session ID and sends it to the client. 00170 * 00171 * Also moves session information from the old session to the new one 00172 * (in PHP 5.1 or later) 00173 * 00174 * @return string the new session ID 00175 */ 00176 private function renewSession() { 00177 if (version_compare(phpversion(), '5.1', '<')) { 00178 session_regenerate_id(TRUE); 00179 } else { 00180 session_regenerate_id(); 00181 } 00182 return session_id(); 00183 } 00184 00185 /** 00186 * Checks whether we already have an active session. 00187 * 00188 * @return boolean true if there is an active session, false otherwise 00189 */ 00190 public function hasSession() { 00191 return (isset($_SESSION['created'])); 00192 } 00193 00194 /** 00195 * Returns the session ID of the running session. 00196 * 00197 * @return string the session ID 00198 */ 00199 public function getSessionId() { 00200 return session_id(); 00201 } 00202 00203 /** 00204 * Returns a session hash, which can only be calculated by the server. 00205 * Used to store our session files without exposing the session ID. 00206 * 00207 * @param string An alternative session ID. Defaults to our current session ID 00208 * 00209 * @return string the session hash 00210 */ 00211 private function getSessionHash($sessionId = '') { 00212 if (!$sessionId) { 00213 $sessionId = $this->getSessionId(); 00214 } 00215 return md5($GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'].'|'.$sessionId); 00216 } 00217 00218 /** 00219 * Marks this session as an "authorized" one (login successful). 00220 * Should only be called if: 00221 * a) we have a valid session running 00222 * b) the "password" or some other authorization mechanism really matched 00223 * 00224 * @return void 00225 */ 00226 public function setAuthorized() { 00227 $_SESSION['authorized'] = TRUE; 00228 $_SESSION['lastSessionId'] = time(); 00229 $_SESSION['tstamp'] = time(); 00230 $_SESSION['expires'] = (time() + ($this->expireTimeInMinutes*60)); 00231 // Renew the session id to avoid session fixation 00232 $this->renewSession(); 00233 } 00234 00235 /** 00236 * Check if we have an already authorized session 00237 * 00238 * @return boolean True if this session has been authorized before (by a correct password) 00239 */ 00240 public function isAuthorized() { 00241 if (!$_SESSION['authorized']) { 00242 return FALSE; 00243 } 00244 if ($_SESSION['expires'] < time()) { 00245 // This session has already expired 00246 return FALSE; 00247 } 00248 return TRUE; 00249 } 00250 00251 /** 00252 * Check if our session is expired. 00253 * Useful only right after a false "isAuthorized" to see if this is the 00254 * reason for not being authorized anymore. 00255 * 00256 * @return boolean True if an authorized session exists, but is expired 00257 */ 00258 public function isExpired() { 00259 if (!$_SESSION['authorized']) { 00260 // Session never existed, means it is not "expired" 00261 return FALSE; 00262 } 00263 if ($_SESSION['expires'] < time()) { 00264 // This session was authorized before, but has expired 00265 return TRUE; 00266 } 00267 return FALSE; 00268 } 00269 00270 /** 00271 * Refreshes our session information, rising the expire time. 00272 * Also generates a new session ID every 5 minutes to minimize the risk of 00273 * session hijacking. 00274 * 00275 * @return void 00276 */ 00277 public function refreshSession() { 00278 $_SESSION['tstamp'] = time(); 00279 $_SESSION['expires'] = time() + ($this->expireTimeInMinutes*60); 00280 if (time() > $_SESSION['lastSessionId']+$this->regenerateSessionIdTime*60) { 00281 // Renew our session ID 00282 $_SESSION['lastSessionId'] = time(); 00283 $this->renewSession(); 00284 } 00285 } 00286 00287 00288 /************************* 00289 * 00290 * PHP session handling with "secure" session files (hashed session id) 00291 * see http://www.php.net/manual/en/function.session-set-save-handler.php 00292 * 00293 *************************/ 00294 00295 /** 00296 * Returns the file where to store our session data 00297 * 00298 * @return string A filename 00299 */ 00300 private function getSessionFile($id) { 00301 $sessionSavePath = $this->getSessionSavePath(); 00302 return $sessionSavePath . '/hash_' . $this->getSessionHash($id); 00303 } 00304 00305 /** 00306 * Open function. See @session_set_save_handler 00307 * 00308 * @param string $savePath 00309 * @param string $sessionName 00310 * @return boolean 00311 */ 00312 public function open($savePath, $sessionName) { 00313 return TRUE; 00314 } 00315 00316 /** 00317 * Close function. See @session_set_save_handler 00318 * 00319 * @return boolean 00320 */ 00321 public function close() { 00322 return TRUE; 00323 } 00324 00325 /** 00326 * Read session data. See @session_set_save_handler 00327 * 00328 * @param string The session id 00329 * 00330 * @return string 00331 */ 00332 public function read($id) { 00333 $sessionFile = $this->getSessionFile($id); 00334 return (string) @file_get_contents($sessionFile); 00335 } 00336 00337 /** 00338 * Write session data. See @session_set_save_handler 00339 * 00340 * @param string The session id 00341 * @param string The data to be stored 00342 * 00343 * @return boolean 00344 */ 00345 public function write($id, $sessionData) { 00346 $sessionFile = $this->getSessionFile($id); 00347 return t3lib_div::writeFile($sessionFile, $sessionData); 00348 } 00349 00350 /** 00351 * Destroys one session. See @session_set_save_handler 00352 * 00353 * @param string The session id 00354 * 00355 * @return string 00356 */ 00357 public function destroy($id) { 00358 $sessionFile = $this->getSessionFile($id); 00359 return(@unlink($sessionFile)); 00360 } 00361 00362 /** 00363 * Garbage collect session info. See @session_set_save_handler 00364 * 00365 * @param integer The setting of session.gc_maxlifetime 00366 * 00367 * @return boolean 00368 */ 00369 public function gc($maxLifeTime) { 00370 $sessionSavePath = $this->getSessionSavePath(); 00371 $files = glob($sessionSavePath . '/hash_*'); 00372 if (!is_array($files)) { 00373 return TRUE; 00374 } 00375 foreach ($files as $filename) { 00376 if (filemtime($filename) + ($this->expireTimeInMinutes*60) < time()) { 00377 @unlink($filename); 00378 } 00379 } 00380 return TRUE; 00381 } 00382 00383 /** 00384 * Writes the session data at the end, to overcome a PHP APC bug. 00385 * 00386 * Writes the session data in a proper context that is not affected by the APC bug: 00387 * http://pecl.php.net/bugs/bug.php?id=16721. 00388 * 00389 * This behaviour was introduced in #17511, where self::write() made use of t3lib_div 00390 * which due to the APC bug throws a "Fatal error: Class 't3lib_div' not found" 00391 * (and the session data is not saved). Calling session_write_close() at this point 00392 * seems to be the most easy solution, acording to PHP author. 00393 * 00394 * @return void 00395 */ 00396 public function __destruct() { 00397 session_write_close(); 00398 } 00399 } 00400 00401 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/install/mod/class.tx_install_session.php'])) { 00402 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/install/mod/class.tx_install_session.php']); 00403 } 00404 00405 ?>
1.8.0