
当在未启动会话或未登录状态下强制跳转登录页时,若验证逻辑未排除目标页面自身,将触发无限重定向循环;正确做法是先检查当前脚本是否为登录页(如 index.php),再决定是否执行跳转。
当在未启动会话或未登录状态下强制跳转登录页时,若验证逻辑未排除目标页面自身,将触发无限重定向循环;正确做法是先检查当前脚本是否为登录页(如 index.php),再决定是否执行跳转。
在 PHP Web 应用中,常见的登录保护逻辑是:在受保护页面顶部检查 $_SESSION['username'] 是否存在,若不存在则使用 header('Location: ./index.php') 跳转至登录页。但问题在于——该检查代码若也存在于 index.php 中,就会形成闭环:index.php → 检测到无 session → 重定向到 index.php → 再次检测 → 再次重定向……最终浏览器报错 “ERR_TOO_MANY_REDIRECTS”。
根本原因在于:session_start() 必须在任何输出(包括 header())之前调用,而你的原始代码将 session_start() 放在了判断逻辑之后,这不仅可能导致“headers already sent”错误,更使会话状态始终无法正确初始化,进一步加剧验证失效。
✅ 正确写法应满足两个前提:
- session_start() 必须置于脚本最前端(除注释和空格外);
- 跳转逻辑需主动排除登录页自身,避免自我重定向。
以下是修正后的 Session.php(建议重命名为 auth_check.php 并作为公共鉴权模块引入):
<?php // ✅ 第一步:立即启动会话(必须放在最开头)
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// ✅ 第二步:仅当不在登录页时才执行未登录跳转
$currentPage = basename($_SERVER['PHP_SELF']);
if ($currentPage !== 'index.php' && !isset($_SESSION['username'])) {
header('Location: ./index.php');
exit;
}
// ✅ 第三步:已登录用户继续执行后续逻辑(如数据库查询)
require "connessione.php";
$connessione = connessionedb("db");
$username = $_SESSION['username'];
$username = $connessione->real_escape_string($username);
$query = "SELECT * FROM utenti WHERE idUtente = ?";
$stmt = $connessione->prepare($query);
$stmt->bind_param('s', $username);
$stmt->execute();
$risultato = $stmt->get_result();
if ($risultato->num_rows !== 1) {
// 用户信息异常,强制登出并跳回首页
unset($_SESSION['username']);
session_destroy();
header('Location: ./index.php?error=invalid_user');
exit;
}
?>
? 关键改进说明:
- 使用 session_status() 安全判断会话状态,避免重复 session_start() 报错;
- 用 basename($_SERVER['PHP_SELF']) 精确匹配当前文件名(如 dashboard.php),比路径字符串比较更鲁棒;
- 改用预处理语句(prepare/bind_param)替代拼接 SQL,彻底杜绝 SQL 注入风险(原代码中 $connessione->real_escape_string() 仅对字符串转义,无法防御所有注入场景);
- 验证失败时主动销毁会话,防止残留无效 session;
- 所有 header() 后紧跟 exit,确保跳转后脚本立即终止。
⚠️ 注意事项:
- 切勿在 index.php 中引入此鉴权文件(否则仍会循环);它只应在 dashboard.php、profile.php 等需登录访问的页面顶部 require;
- 确保 index.php 中包含登录表单及服务端验证逻辑(如检查 POST 凭据、设置 $_SESSION['username']),且自身不包含上述跳转逻辑;
- 开发阶段可临时添加 error_log("Auth check on: $currentPage, session set: " . (isset($_SESSION['username']) ? 'yes' : 'no')); 辅助调试。
遵循以上结构,即可彻底消除重定向循环,构建安全、健壮的会话保护机制。










