最近我注意到正在创建许多空白会话,我不知道为什么,因为我相信我正在以正确的方式做所有事情。
当用户登录或注册时创建会话时,我们会检查用户是否使用isset($_COOKIE['auth'])
登录属于登录或注册期间创建的会话。
如果存在该cookie,那么我们开始会话,这有助于我们避免为未注册用户启动数千个会话并创建大量会话文件。
会话设置:
php文件
session_save_path("/home/user/sessions");
session_set_cookie_params("86400", "/");
session_name("auth");
的php.ini
session.gc_maxlifetime = 90000
session.cookie_lifetime = 90000
session.use_trans_sid = 0
session.use_only_cookies = 1
创建登录会话(成功登录时)
session_start();
session_regenerate_id(true);
$_SESSION['userId'] = $userId;
$_SESSION['created'] = time();
session_write_close();
header("Location: $_SERVER[HTTP_REFERER]");
检查是否应恢复会话
然后,我们会根据是否设置auth
会话Cookie来检查是否为用户启动会话。
只有在用户注册或登录之前才会设置:
if(isset($_COOKIE['auth'])){
session_start();
session_write_close();
}
检查用户是否已登录
要检查用户是否已登录,我们将使用以下函数:
function isAuthenticated(){
if (!isset($_SESSION['userId']))
return false;
else
return true;
}
退出
function logOut(){
session_start();
session_destroy();
setcookie('auth', "", 0);
unset($_SESSION);
unset($_COOKIE['auth']);
return true;
}
由于某种原因,我在会话文件夹中收到了大量空(filesize 0)会话文件。
这些来自哪里?
session_regenerate_id(true)
是否会创建新的会话文件并将旧会话文件保留为空?这是我能想到空会话文件的唯一原因吗?
答案 0 :(得分:2)
bool session_regenerate_id([bool $delete_old_session = false]);
查看php manual了解详情。
session_regenerate_id()
会将当前会话ID替换为新会话ID,并保留当前会话信息。
保留旧会话文件,并在每次运行session_register_id()
时生成新的会话文件。 session_register_id()
使用新的session_id创建一个新会话但保留旧会话信息,所以是的,session_register_id()
在将信息更新到新会话文件后将旧会话文件保留为空。
答案 1 :(得分:1)
session_regenerate_id(true)是否创建新的会话文件并离开 旧会话文件为空?这是我能想到的唯一原因 空会话文件?
调用session_regenerate_id(true)
会尝试删除会话文件,但如果失败则会返回false(请参阅下面的相关php源代码)。因此,我建议您验证会话功能是否成功运行,即
if(!session_start()) {
//log error
}
if(!session_regenerate_id(true)) {
//log error
}
还要检查您的垃圾收集器运行频率的设置。也许它运行的可能性非常低,你会看到孤立的会话累积起来。每次运行php时,下面的设置将以1/100(1%)的概率运行垃圾收集器。尝试删除所有孤儿,方法是将单个运行的值设置为1,然后将值设置为1/100,如下所示。
session.gc_probability = 1
session.gc_divisor = 100
最后,您的注销方法会在浏览器关闭时使会话cookie失效。请立即尝试将其过期
setcookie('auth', null, -1);
session_regenerate_id的PHP源
https://github.com/php/php-src/blob/master/ext/session/session.c
请注意对PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC)
/* {{{ proto bool session_regenerate_id([bool delete_old_session])
Update the current session id with a newly generated one. If delete_old_session is set to true, remove the old session. */
static PHP_FUNCTION(session_regenerate_id)
{
zend_bool del_ses = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &del_ses) == FAILURE) {
return;
}
if (SG(headers_sent) && PS(use_cookies)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot regenerate session id - headers already sent");
RETURN_FALSE;
}
if (PS(session_status) == php_session_active) {
if (PS(id)) {
if (del_ses && PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed");
RETURN_FALSE;
}
efree(PS(id));
PS(id) = NULL;
}
PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
if (PS(id)) {
PS(send_cookie) = 1;
php_session_reset_id(TSRMLS_C);
RETURN_TRUE;
} else {
PS(id) = STR_EMPTY_ALLOC();
}
}
RETURN_FALSE;
}
<强> PS_DESTROY_FUNC 强>
https://github.com/php/php-src/blob/master/ext/session/mod_files.c
注意VCWD_UNLINK
这是从磁盘中删除文件的命令。
PS_DESTROY_FUNC(files)
{
char buf[MAXPATHLEN];
PS_FILES_DATA;
if (!ps_files_path_create(buf, sizeof(buf), data, key)) {
return FAILURE;
}
if (data->fd != -1) {
ps_files_close(data);
if (VCWD_UNLINK(buf) == -1) {
/* This is a little safety check for instances when we are dealing with a regenerated session
* that was not yet written to disk. */
if (!VCWD_ACCESS(buf, F_OK)) {
return FAILURE;
}
}
}
return SUCCESS;
}
答案 2 :(得分:0)
header("Location: $_SERVER[HTTP_REFERER]");
不应该是header("Location: $_SERVER['HTTP_REFERER']");
吗?或者这只是一些愚蠢的事情。
编辑:
根据PHP.net,您应该使用delete_old_session
参数。看看HERE
答案 3 :(得分:0)
只需2美分:用户(无论是否登录)在特定时间内使用该网站,通常称为“会话”。始终启动会话并保留会话变量以查看是否有人进行了身份验证是不是一个问题。现在,如果有人登录,您似乎只尝试启动会话,这比仅仅启动会话和检查变量的相同行为会增加更多的开销。
如果您将会话超时保持在低水平,则会有人自动注销。根据站点流量,您可以将GC设置为更频繁或更不频繁地启动。 (见:http://www.php.net/manual/en/session.configuration.php#ini.session.gc-divisor)
如果硬盘是会话的瓶颈(过多的会话文件等),请创建一个小型RAMdisk来存储会话信息。