页面之间丢失的PHP会话 - 根据服务器的不同而表现不同

时间:2015-12-11 11:49:37

标签: php session redirect

我花了几个月的时间在我的域上开发应用程序。这是一个简单的概念。在开发过程中,我自己在我自己的域上托管它,但最近把它推到了我们的实际域。问题是会话不是在页面之间创建或保存的,我不能为我的生活找出原因。

为下面的代码墙道歉,但我更喜欢理论解释。

让我们从每个页面顶部的会话开始:

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访问服务器权限。真的是一些奇怪的行为。

任何线索?

4 个答案:

答案 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 文件中的这三行。

  • session.gc_divisor
  • 的session.gc_maxlifetime
  • session.gc_probability合

来自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。

希望有所帮助