我花了几个月的时间在我的域上开发应用程序。这是一个简单的概念。在开发过程中,我自己在我自己的域上托管它,但最近把它推到了我们的实际域。问题是会话不是在页面之间创建或保存的,我不能为我的生活找出原因。
为下面的代码墙道歉,但我更喜欢理论解释。
让我们从每个页面顶部的会话开始:
function sec_session_start() {
$session_name = 'login';
$secure = false;
$httponly = true;
ini_set('session.use_only_cookies', 1);
session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly);
session_name($session_name);
session_start();
session_regenerate_id();
}
然后我如何检查用户是否已登录。我添加了return x;
而不是false
进行调试。我将此附加到重定向网址。
function login_check($mysqli) {
if(isset($_SESSION['id'], $_SESSION['login_string'], $_SESSION['type'])) {
$id = $_SESSION['id'];
$login_string = $_SESSION['login_string'];
$user_browser = $_SERVER['HTTP_USER_AGENT'];
if($_SESSION['type'] == 1 || $_SESSION['type'] == 2) // Admin user
{
if ($stmt = $mysqli->prepare("SELECT `password` FROM `users` WHERE `id` = ? LIMIT 1")) {
$stmt->bind_param('s', $id);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows == 1) {
$stmt->bind_result($password);
$stmt->fetch();
$login_check = hash('sha512', $password.$user_browser);
if($login_check == $login_string) {
return true;
} else {
return 1;
}
} else {
return 2;
}
} else {
return 3;
}
} else if($_SESSION['type'] == 3) { // Standard user
if($stmt=$mysqli->prepare("SELECT `password` FROM `proj` WHERE `id` = ? LIMIT 1"))
{
$stmt->bind_param("s", $_SESSION['id']);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows == 1)
{
$stmt->bind_result($db_key);
$stmt->fetch();
$login_check = hash('sha512', $db_key.$user_browser);
if($login_check == $login_string) {
return true;
} else {
return 4;
}
}
}
} else {
return 5;
}
} else {
return 6;
}
}
我有两个登录页面,一个用于管理员,一个用于用户。
管理:
<?php
ini_set('display_errors','On');
error_reporting(E_ALL);
include_once "../functions.php";
include_once "../db_connect.php";
sec_session_start();
if(login_check($mysqli) === true) {
header('Location: ../index.php');
}
else
{
// Login form
}
用户:
<?php
ini_set('display_errors','On');
error_reporting(E_ALL);
include_once "../functions.php";
include_once "../db_connect.php";
sec_session_start();
if(login_check($mysqli) === true) {
header('Location: ../index.php');
}
else
{
// Login form
}
完全相同,除了文件来源,因为管理员login.php
位于/admin
。尽管如此,第一个显示正确的登录表单,而第二个重定向到index.php
(即使在隐身,对我来说是一个谜),导致重定向循环(如index.php
发送回来为nog登录)。
除此之外,当我使用正确的凭据登录时,它确实会将我引导至index.php
,仅将我重定向回login.php
,错误代码为6
。
如果您需要更多信息或代码示例,请发表评论,我现在感到迷失在自己的项目中。
感谢任何帮助, 谢谢
更新17月12日:
经过几个小时的调试后,我们得出结论,问题不在于代码,而在于服务器配置。一个简单的例子:
<?php
session_start();
echo session_id();
?>
如果在生产服务器上打开此文件并刷新页面,则会在每个请求中显示一个新的会话ID。我目前不知道为什么。我已经确认创建了会话文件以及cookie。它包含正确的信息,可以通过SSH访问服务器权限。真的是一些奇怪的行为。
任何线索?
答案 0 :(得分:5)
我已经完成了你的代码,除了一件事之外我没有发现任何不寻常的东西。
您永远不应该使用==
进行字符串比较===
即可。
$something = 0;
echo ('password123' == $something) ? 'true' : 'false';
运行上面的代码,您将找到会话丢失的原因。在您的函数login_check中,您使用==
来比较两个字符串
if($login_check == $login_string)
将其替换为:
if($login_check === $login_string)
否则每件事都绝对没法。如果改变这个小东西不能解决你的问题,那就告诉我。
您在会话开始前连接到数据库。我建议您导入您的功能,然后启动您的会话,然后连接到您的数据库。
include_once "../functions.php";
sec_session_start();
include_once "../db_connect.php";
答案 1 :(得分:4)
检查会话是否已经启动并确保只执行一次:
使用PHP&gt; = 5.4:
function sec_session_start() {
if (session_status() == PHP_SESSION_NONE) {
$session_name = 'login';
$secure = false;
$httponly = true;
ini_set('session.use_only_cookies', 1);
session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly);
session_name($session_name);
session_start();
session_regenerate_id();
}
}
PHP 5.4之前:
function sec_session_start() {
if (session_id() == '') {
$session_name = 'login';
$secure = false;
$httponly = true;
ini_set('session.use_only_cookies', 1);
session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly);
session_name($session_name);
session_start();
session_regenerate_id();
}
}
此外,为什么每次都必须重新生成会话?
答案 2 :(得分:0)
我几个月前在我的生产服务器上遇到了类似的问题,其中会话过期(就像在你的情况下会话在页面之间丢失)并且用户突然从我的网站中退出。因此,经过几天的调试,所有内容都归结为 php.ini 文件中的这三行。
来自the manual,
session.gc_probability 与session.gc_divisor一起用于管理gc(垃圾收集)例程启动的概率。默认为1。
session.gc_divisor 与session.gc_probability相结合,定义了每次会话初始化时gc(垃圾收集)进程启动的概率。通过使用gc_probability / gc_divisor计算概率,例如, 1/100表示GC进程在每个请求上启动的可能性为1%。 session.gc_divisor默认为100。
session.gc_maxlifetime 指定数据被视为“垃圾”并可能被清除的秒数。会话开始时可能会收集垃圾(取决于session.gc_probability和session.gc_divisor)。
这些是我在 php.ini 文件中的原始会话配置,它实际上首先创造了整个滋扰,
session.gc_divisor 1000 1000
session.gc_maxlifetime 1440 1440
session.gc_probability 0 0
所以这意味着垃圾收集器将以session.gc_probability除以session.gc_divisor的概率开始。并使用该选项的默认值(分别为0和1000),垃圾收集概率= session.gc_probability / session.gc_divisor即0/1000 = 0%,我认为这是不正确的,加上session.gc_maxlifetime对我来说似乎太低了
所以,我决定在我的 php.ini 文件中更改会话配置并包含这些值,
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 28800
从那时起,它的工作正常。 所以我的建议是,检查 php.ini 文件中的这三个值,如有必要,根据需要进行更改。
答案 3 :(得分:0)
我过去有类似的经历,我不记得我是如何解决这个问题的,但是从我记忆中来看,它与会话cookie 和变量顺序<相关/ strong>在PHP中。
在php.ini中查找以下这一行,
variables_order = "GPCS"
以某种方式,更改这些变量的顺序会影响PHP会话。
如果通过任何更改,像我一样,您无法更改服务器上的设置,您还可以尝试使用常规Cookie复制会话Cookie:
session_start();
set_cookie(session_name(), session_id());
另外注意,不同的浏览器在会话cookie上也有不同的行为,例如:safari。在safari上,无论变量顺序如何,我都必须复制cookie。
希望有所帮助