PHP会话无法持久化求助:登录状态跳转后丢失
解决PHP会话持久化与循环重定向问题
核心问题分析
你的代码存在三个关键问题导致会话无法持久化和循环重定向:
- 登录状态判断逻辑混乱,变量作用域错误导致无法识别已登录状态
isGranted函数未处理会话变量不存在的情况- 业务逻辑与视图输出耦合,导致页面结构混乱
具体修复方案
1. 修复isGranted函数
确保函数安全判断会话状态,避免未定义索引警告:
function isGranted() { // 先检查变量是否存在,再判断值是否为true return isset($_SESSION['granted']) && $_SESSION['granted'] === true; }
2. 重构页面逻辑,统一状态判断
将登录状态检查放在页面最前端,分离业务逻辑和视图渲染:
- 先处理登出请求
- 再判断是否已登录:已登录则展示内容,未登录则处理登录请求或显示表单
3. 修复变量作用域与参数错误
页面底部的判断条件中,$_POST['username']应为$_POST['userName'],且$result是函数内部变量,外部无法访问,需完全重构这部分逻辑。
修改后的完整代码
<?php session_start(); // 数据库常量(请自行补充) if ($_SERVER['HTTP_HOST'] == 'localhost') { define('HOST', 'localhost'); define('USER', 'your_db_user'); define('PASS', 'your_db_pass'); define('DB', 'your_db_name'); } else { // 线上环境常量 define('HOST', 'your_prod_host'); define('USER', 'your_prod_user'); define('PASS', 'your_prod_pass'); define('DB', 'your_prod_db'); } // 连接数据库 function connectToDatabase() { $conn = mysqli_connect(HOST, USER, PASS, DB); if (!$conn) { die("Connection failed: " . mysqli_connect_error()); } return $conn; } // 验证用户名密码,返回登录状态 function checkUserNameAndPassword($username, $password) { $conn = connectToDatabase(); // 建议使用预处理语句避免SQL注入(即使是作业也养成好习惯) $sql = "SELECT * FROM users WHERE username = ? AND password = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("ss", $username, $password); $stmt->execute(); $result = $stmt->get_result(); $isValid = $result->num_rows == 1; if ($isValid) { $_SESSION['granted'] = true; setcookie('name', $username, time() + 3600); } $stmt->close(); $conn->close(); return $isValid; } // 安全判断登录状态 function isGranted() { return isset($_SESSION['granted']) && $_SESSION['granted'] === true; } // 处理登出 if (isset($_GET['logout']) && $_GET['logout'] == 'true') { $_SESSION = array(); session_destroy(); header("Location: index.php"); exit; } // 处理登录请求 $loginSuccess = false; if ($_SERVER['REQUEST_METHOD'] == 'POST') { if (isset($_POST['userName']) && isset($_POST['password'])) { $username = $_POST['userName']; $password = $_POST['password']; $loginSuccess = checkUserNameAndPassword($username, $password); } } ?> <!doctype html> <html lang="en"> <head> <title>Insecure Passwords</title> <link rel="stylesheet" href="css/style.css" type="text/css"> </head> <body> <?php if (isGranted() || $loginSuccess): ?> <!-- 已登录状态 --> <div class="navbar"> <a href=".">Home</a> <a href="?logout=true">Logout</a> </div> <div class="form"> <div class="access">ACCESS GRANTED</div> </div> <div class="table"> <table> <tr> <th class="title">Agent</th><th class="title">Code Name</th> </tr> <?php $fileContents = file_get_contents("includes/fbi.txt"); $lines = explode('||>><<||', $fileContents); foreach ($lines as $line) { $pair = explode(',', $line); if (count($pair) < 2) continue; // 跳过无效行 $agent = ucfirst($pair[0]); $codename = $pair[1]; // 格式化代号 if (strpos($codename, ' ') !== false) { $words = explode(' ', $codename); foreach ($words as &$word) { $word = ucfirst($word); } $codename = implode(' ', $words); } else { $codename = ucfirst($codename); } echo "<tr><td>{$agent}</td><td>{$codename}</td></tr>"; } ?> </table> </div> <?php else: ?> <!-- 未登录状态 --> <div class="form"> <?php if ($_SERVER['REQUEST_METHOD'] == 'POST'): ?> <div class="access">ACCESS DENIED<br></div> <p>Please enter valid credentials.</p> <?php endif; ?> <form method="post" name="logIn"> <input type="text" placeholder="User Name" name="userName"><br><br> <input type="password" placeholder="Password" name="password"><br><br> <div class="submit"> <input type="submit" name="sub-button"> <input type="reset" name="reset-button"> </div> </form> </div> <?php endif; ?> </body> </html>
关键修改说明
- 统一状态判断:通过
isGranted()函数在视图中统一判断登录状态,确保刷新或跳转后能正确识别会话 - 分离逻辑与视图:将登录验证的业务逻辑和页面渲染分离,避免函数内直接输出HTML导致的结构混乱
- 修复变量问题:修正POST参数名错误,解决函数内部变量无法在外部访问的问题
- 安全处理会话:
isGranted()先检查会话变量是否存在,避免未定义索引警告 - 优化SQL查询:使用预处理语句(可选,但建议养成习惯)
内容的提问来源于stack exchange,提问作者WastelandSniper
相关产品推荐
相关产品推荐

