PHP会话变量无法传递到我的已登录页面,但会话ID可以。

5

我正在使用 PHP 4.3.9, Apache/2.0.52

我正在尝试创建一个登录系统,将DB值注册到会话中,在登录后它们可用。 但是,一旦被重定向后,我会失去会话变量。

我在我的登录表单页面和重定向的页面上使用以下代码来打印会话ID/值:

echo '<font color="red">session id:</font> ' . session_id() . '<br>';
echo '<font color="red">session first name:</font> ' . $_SESSION['first_name'] . '<br>';
echo '<font color="red">session user id:</font> ' . $_SESSION['user_id'] . '<br>';
echo '<font color="red">session user level:</font> ' . $_SESSION['user_level'] . '<br><br>';

这是我登录页面中打印出的内容(我只是注释掉了重定向到已登录页面的标题)。这也是来自我的数据库的正确信息,所以目前一切正常。

session id: 1ce7ca8e7102b6fa4cf5b61722aecfbc
session first name: elvis
session user id: 2
session user level: 1

这是我重定向/登录页面上打印的内容(当我取消header/redirect的注释时)。会话ID相同,但我没有获取到任何单个会话变量的值。
session id: 1ce7ca8e7102b6fa4cf5b61722aecfbc
session first name:
session user id:
session user level:

我收到以下错误信息:
未定义的索引:first_name 未定义的索引:user_id 未定义的索引:user_level
我有一个全局的 header.php 文件,我的 loggedIN.php 没有调用它,但 loggedOUT.php 调用了它 - 以销毁会话:
header.php
<?php
ob_start();
session_start();

//if NOT on loggedout.php, check for cookie. if exists, they haven't explicity logged out so take user to loggedin.php
if (!strpos($_SERVER['PHP_SELF'], 'loggedout.php')) {
    /*if (isset($_COOKIE['access'])) {
        header('Location: www.mydomain.com/loggedin.php');
    }*/
} else {
    //if on loggedout.php delete cookie
    //setcookie('access', '', time()-3600);

    //destroy session
    $_SESSION = array();
    session_destroy();
    setcookie(session_name(), '', time()-3600);
}

//defines constants and sets up custom error handler
require_once('config.php');

?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

some page layout stuff

Login portion is eventually called via include

footer stuff

我的loggedIN.php仅仅是启动会话而已。

<?php
session_start();
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

我的登录脚本的逻辑,其中关键部分是我将DB结果直接获取到$_SESSION中(在下半部分):

if (isset($_POST['login'])) {
        //access db
        require_once(MYSQL);

        //initialize an errors array for non-filled out form fields
        $errors = array();

        //setup $_POST aliases, clean for db and trim any whitespace
        $email  = mysql_real_escape_string(trim($_POST['email']), $dbc);
        $pass   = mysql_real_escape_string(trim($_POST['pass']), $dbc);

        if (empty($email)) {
            $errors[] = 'Please enter your e-mail address.';
        }

        if (empty($pass)) {
            $errors[] = 'Please enter your password.';
        }

        //if all fields filled out and everything is OK
        if (empty($errors)) {
            //check db for a match
            $query = "SELECT user_id, first_name, user_level 
                    FROM the rest of my sql here, blah blah blah";

            $result = @mysql_query($query, $dbc) 
                OR trigger_error("Query: $query\n<br />MySQL Error: " . mysql_error($dbc));

            if (@mysql_num_rows($result) == 1) { //a match was made, OK to login

                //register the retrieved values into $_SESSION
                $_SESSION = mysql_fetch_array($result);
                mysql_free_result($result);
                mysql_close($dbc);
                /*              
                setcookie('access'); //if "remember me" not checked, session cookie, expires when browser closes
                                     //in FF you must close the tab before quitting/relaunching, otherwise cookie persists

                //"remember me" checked?
                if(isset($_POST['remember'])){ //expire in 1 hour (3600 = 60 seconds * 60 minutes)
                    setcookie('access', md5(uniqid(rand())), time()+60); //EXPIRES IN ONE MINUTE FOR TESTING
                }
                */

echo '<font color="red">cookie:</font> ' . print_r($_COOKIE) . '<br><br>';
echo '<font color="red">session id:</font> ' . session_id() . '<br>';
echo '<font color="red">session first name:</font> ' . $_SESSION['first_name'] . '<br>';
echo '<font color="red">session user id:</font> ' . $_SESSION['user_id'] . '<br>';
echo '<font color="red">session user level:</font> ' . $_SESSION['user_level'] . '<br><br>';

                ob_end_clean();
                session_write_close();

                $url = BASE_URL . 'loggedin_test2.php';
                header("Location: $url");
                exit();
            } else {
            //wrong username/password combo
            echo '<div id="errors"><span>Either the e-mail address or password entered is incorrect or you have not activated your account. Please try again.</span></div>';
            }

            //clear $_POST so the form isn't sticky
            $_POST = array();
        } else { 
        //report the errors
        echo '<div id="errors"><span>The following error(s) occurred:</span>';

            echo '<ul>';
            foreach($errors as $error) {
                echo "<li>$error</li>";
            }
            echo '</ul></div>';
        }

    } // end isset($_POST['login'])

如果我在登录页面注释掉头部重定向,我可以使用来自数据库的正确信息回显$_SESSION变量。但是一旦重定向到登录页面,它们就消失/未设置。有人有任何想法吗?我已经花了一整天的时间,但似乎离解决问题更远了。顺便说一下,我最近制作了两个简单的测试页面,一个开始会话,设置了一些变量,有一个表单提交,重定向到第二个页面,仅读取/输出会话变量。这一切似乎都很正常,只是我在主应用程序中遇到了一些问题。
4个回答

8

我在你的登录脚本中没有看到 session_start()。如果你没有启动会话,我认为php不会保存你放置在 $_SESSION 数组中的任何数据。另外,为了安全起见,我建议将变量明确地放入 $_SESSION 数组中,而不仅是用$_SESSION = mysql_fetch_array($result);完全覆盖整个数组。


嘿,将数据库值手动放入$_SESSION数组中似乎解决了问题。非常感谢!这是因为我被困在使用PHP 4.3.9吗? - magenta
1
@magenta 我猜这是因为使用 $_SESSION = array( ... ) 时,你并没有修改 $_SESSION 对象,而是丢弃了引用并替换成其他内容。是的,4.3.9 版本确实相当古老 :) - redShadow

3
尝试执行以下操作:

session_regenerate_id(true); 

在此之前

session_write_close();

此外,我认为编写登录脚本的最佳方式是:

将登录逻辑处理在用户试图访问的主页中。

  1. 如果用户未经身份验证,则会被退回到登录页面
  2. 如果用户已通过身份验证,则会获得 $_SESSION["auth"] 或其他内容
  3. 然后当用户浏览需要进行身份验证的主页或其他页面时,只需检查是否设置了 $_SESSION["auth"]。

这样就不会出现在重定向之前会话未保存的问题。


我的登录脚本的逻辑是基于这篇文章:https://dev59.com/cUjSa4cB1Zd3GeqPJN4h - Léo Léopold Hertz 준영

0

0

...我可以补充其他答案,即session_start()有时会失败或出现奇怪的问题,如果不放在脚本的最开始位置。在您的头文件脚本中,请尝试:

而不是

<?php
ob_start();
session_start();

放置

<?php
session_start();
ob_start();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接