0);
if ($handle) fclose($handle);
if ($tries == 0)
{
// failed to start session.
if (FS_SESSION_DEBUG) echo "Failed to start session in $dir
";
return "Failed to start session in $dir
";
}
$session = array();
$session['sid'] = $sid;
$session['accessed'] = time();
global $FS_CONTEXT;
$session['context'] = $FS_CONTEXT;
$GLOBALS['FS_SESSION'] = $session;
// store the session now,
// to make sure its already available to sub-scripts that attempt to
// access the session information before this script has terminated.
return fs_store_session();
}
else // need to load existing session.
{
// garbage collect first.
$gc = fs_session_gc();
if (is_string($gc)) return $gc;
$file = "$dir/session_$sid";
if (file_exists($file))
{
$handle = @fopen($file,"r");
if ($handle != false)
{
$fresh = false;
$str = @fgets($handle);
fclose($handle);
if ($str != false)
{
$session = unserialize($str);
$accessed = isset($session['accessed'])? (int)$session['accessed'] : 0;
$fresh = time() - $accessed < SESSION_TIMEOUT;
if ($fresh)
{
$GLOBALS['FS_SESSION'] = $session;
}
}
return $fresh;
}
else
{
if (FS_SESSION_DEBUG) echo "Error opening session file $file
";
return "Error opening session file $file";
}
}
else
{
if (FS_SESSION_DEBUG) echo "Session file not found : $file
";
return false;
}
}
}
/**
* Stores a session object, called automatically when the script processing is complete.
*/
function fs_store_session()
{
if (isset($GLOBALS['FS_SESSION']))
{
$session_initialized = fs_initialize_session_dir(true);
if ($session_initialized !== true) return $session_initialized;
global $FS_CONTEXT;
$session = $GLOBALS['FS_SESSION'];
$session['context'] = $FS_CONTEXT;
$session['accessed'] = time();
$sid = $session['sid'];
$dir = $GLOBALS['FS_TEMP_DIR'];
$handle = @fopen("$dir/session_$sid","w+");
fputs($handle,serialize($session));
fclose($handle);
}
return true;
}
/**
* Garbage collect stale session.
* this is called automatically and perform its operation at most every GC_INTERVAL_SECONDS.
*/
function fs_session_gc()
{
$session_initialized = fs_initialize_session_dir(true);
if ($session_initialized !== true) return $session_initialized;
$last_gc = 0;
$dir = $GLOBALS['FS_TEMP_DIR'];
$fname = "$dir/last_gc";
if (file_exists($fname))
{
$f = file($fname);
if (isset($f[0]) && is_numeric($f[0])) $last_gc = (int)$f[0];
}
if (time() - $last_gc > GC_INTERVAL_SECONDS)
{
//echo "running gc";
$dh = opendir($dir);
while (false !== ($filename = readdir($dh)))
{
if ($filename != 'last_gc' && $filename != '.' && $filename != '..')
{
$fn = "$dir/$filename";
if (strstr($filename,'session_') != $filename || @is_dir($fn))
{
continue;
}
$rotten = false;
$fd = @fopen($fn, "r");
if ($fd == false)
{
if (FS_SESSION_DEBUG) echo "Error opening $fn
";
// error opening the file, assume invalid and (try to) gc it.
$rotten = true;
}
else
{
$str = fgets($fd);
fclose($fd);
if ($str == false)
{
// error reading the file, assume invalid and gc it.
$rotten = true;
}
else
{
$session = @unserialize($str);
if ($session != false)
{
$accessed = (int)$session['accessed'];
//echo "elapsed " . (time() - $accessed) . "
";
$rotten = time() - $accessed >= SESSION_TIMEOUT;
}
else
{
if (FS_SESSION_DEBUG) echo "Error unserialzing $fn
";
// bad file.
$rotten = true;
}
}
}
if ($rotten)
{
if (FS_SESSION_DEBUG) echo "Session GC: unlinking $filename";
if(!@unlink($fn))
{
if (FS_SESSION_DEBUG) echo "Error unlinking $fn
";
}
}
}
}
if (fs_is_writable_and_readable($fname))
{
$fd = fopen($fname,"w+");
fputs($fd,time());
fclose($fd);
}
else
{
return "$fname is not writeable by PHP user";
}
}
}
/**
* WARNING: This is one tricky function from hell.
* DO NOT TOUCH if you are not 100% sure you know what you are doing, many people have died to get this function to where it is today.
*/
function fs_initialize_session_dir($silent_test = false)
{
// only detect the temp dir once.
if (isset($GLOBALS['FS_TEMP_DIR'])) return true;
$help_url = "http://firestats.cc/wiki/ErrorInitializingSessionsDir";
$text = sprintf("
Error initializing sessions directory, read this for help
%%s");
// user may override the detection of temp dir with FS_TEMP_DIR
if (defined("FS_TEMP_DIR"))
{
$temp_dir = FS_TEMP_DIR;
}
else
{
$temp_dir = sys_get_temp_dir();
}
$home_temp_dir = dirname(dirname(__FILE__));
$home_temp_dir .= "/".SESSIONS_DIR;
// if FS_TEMP_DIR is NOT defined
// AND one the following coditions is true, then try to use sessions directory under firestats directory:
// 1. home_temp exists
// 2. can't detect temp directory
// 3. php is running in safe mode
// 4. temp is not writable.
if(!defined("FS_TEMP_DIR") &&
(@is_dir($home_temp_dir) ||
ini_get('safe_mode') == 1 ||
$temp_dir === false ||
!fs_is_dir_writable_and_readable($temp_dir)))
{
// sessions dir not found?
// we require that the user create the directory because
// if we create it the user will not be able to delete it.
if (!@is_dir($home_temp_dir))
{
return fs_session_die($silent_test, sprintf($text,"Directory ,'$home_temp_dir' does not exist, please create it"));
}
$temp_dir = $home_temp_dir;
}
else // temp directory exists, normal flow.
{
// make sure the dir ends with /
fs_fix_dir1($temp_dir);
// if FS_TEMP_DIR is not defined, append fs_sessions to the temp dir.
if (!defined("FS_TEMP_DIR"))
{
$temp_dir .= SESSIONS_DIR;
if (!is_dir($temp_dir)) // sessions dir not found inside temp dir, attempt to create it.
{
if (!mkdir($temp_dir, 0700))
{
return fs_session_die($silent_test, sprintf($text,"Failed to create '$temp_dir'"));
}
}
}
else
{
// just make sure the directory the user defined exists.
if (!is_dir($temp_dir))
{
return fs_session_die($silent_test, sprintf($text,"Directory ,'$temp_dir' does not exist"));
}
}
}
// make sure the dir ends with /
fs_fix_dir1($temp_dir);
if (!fs_is_dir_writable_and_readable($temp_dir))
{
return fs_session_die($silent_test, sprintf($text,"Directory ,'$temp_dir' is not writable or readable by the PHP user"));
}
// unfortunatelly, not all systems has posix_getuid, also - this cause problems when safe_mode is turned on.
// if we run on a system that does not have it, and also happens to
// have multiple (system) users accessing firestats, we are screwed.
if (CREATE_USER_DIR == true && function_exists("posix_getuid") && ini_get('safe_mode') != 1)
{
$temp_dir .= posix_getuid();
// make sure the dir ends with /
fs_fix_dir1($temp_dir);
}
if (!@file_exists($temp_dir) && !mkdir($temp_dir, 0700))
{
return fs_session_die($silent_test, sprintf($text,"Failed to create '$temp_dir'"));
}
$GLOBALS['FS_TEMP_DIR'] = $temp_dir;
// create an index.html inside the sessions dir to prevent directory listing
// if this failes it's not important because it means session files creation will also fail, so there is nothing to hide.
if (!@file_exists($temp_dir."index.html"))
{
$handle = @fopen($temp_dir."index.html","w+");
if ($handle !== false)
{
@fputs($handle,"Move along, nothing to see here.");
@fclose($handle);
}
}
return true;
}
function fs_ensure_sys_get_temp_dir_available()
{
if ( !function_exists('sys_get_temp_dir') )
{
// Based on http://www.phpit.net/
// article/creating-zip-tar-archives-dynamically-php/2/
function sys_get_temp_dir()
{
// Try to get from environment variable
if ( !empty($_ENV['TMP']) )
{
return realpath( $_ENV['TMP'] );
}
else if ( !empty($_ENV['TMPDIR']) )
{
return realpath( $_ENV['TMPDIR'] );
}
else if ( !empty($_ENV['TEMP']) )
{
return realpath( $_ENV['TEMP'] );
}
// Detect by creating a temporary file
else
{
// Try to use system's temporary directory
// as random name shouldn't exist
$temp_file = @tempnam( md5(uniqid(rand(), TRUE)), '' );
if ( $temp_file )
{
$temp_dir = realpath( dirname($temp_file) );
if (!@unlink( $temp_file )) return FALSE;
return $temp_dir;
}
else
{
return FALSE;
}
}
}
}
}
function fs_is_dir_writable_and_readable($dir)
{
fs_fix_dir1($dir);
return fs_is_writable_and_readable($dir);
}
function fs_is_writable_and_readable($path)
{
//will work in despite of Windows ACLs bug
//NOTE: use a trailing slash for folders!!!
//see http://bugs.php.net/bug.php?id=27609
//see http://bugs.php.net/bug.php?id=30931
if ($path{strlen($path)-1}=='/') // recursively return a temporary file path
return fs_is_writable_and_readable($path.uniqid(mt_rand()).'.tmp');
else if (@is_dir($path))
return fs_is_writable_and_readable($path.'/'.uniqid(mt_rand()).'.tmp');
// check tmp file for read/write capabilities
$f = @fopen($path, 'w+');
if ($f === false)
return false;
$res = fputs($f,'test');
if ($res === false)
{
fclose($f);
return false;
}
$data = file_get_contents($path);
if ($data === false)
{
fclose($f);
return false;
}
if ('test' !== $data)
{
fclose($f);
return false;
}
fclose($f);
@unlink($path);
return true;
}
function fs_resume_existing_session()
{
$sid = null;
if (isset($_REQUEST['sid']) && !empty($_REQUEST['sid']))
{
$sid = $_REQUEST['sid'];
}
else
if (isset($_POST['sid']) && !empty($_POST['sid']))
{
$sid = $_POST['sid'];
}
else
if (isset($_COOKIE['FS_SESSION_ID']))
{
$sid = $_COOKIE['FS_SESSION_ID'];
}
else
return "sid not specified";
$res = fs_session_start($sid);
global $FS_SESSION;
if (is_bool($res) && $res)
{
global $FS_CONTEXT;
$FS_CONTEXT = $FS_SESSION['context'];
return true;
}
else
{
if (is_string($res))
{
return $res;
}
else
{
return "Session expired";
}
}
}
function fs_session_die($silent_test, $msg)
{
if ($silent_test)
return $msg;
else
die($msg);
}
function fs_fix_dir1(&$dir)
{
// make sure the dir ends with /
$last = substr($dir, strlen($dir) - 1 );
if ($last != "/" && $last != '\\') $dir .= "/";
return $dir;
}
?>