
当在未启动会话或未登录时强制跳转登录页,却未排除目标页面自身,会导致浏览器反复重定向,形成无限循环。解决方案是添加请求路径判断,确保仅在非登录页执行跳转逻辑。
当在未启动会话或未登录时强制跳转登录页,却未排除目标页面自身,会导致浏览器反复重定向,形成无限循环。解决方案是添加请求路径判断,确保仅在非登录页执行跳转逻辑。
在 PHP Web 应用中,常见的登录保护逻辑是:若用户未登录(即 $_SESSION['username'] 未设置),则通过 header('Location: ./index.php') 跳转至首页(登录入口)。但上述代码存在一个关键缺陷——它未校验当前请求是否已位于 index.php。
观察原始代码:
if(!isset($_SESSION['username']))
{
header('Location: ./index.php');
exit;
}
session_start(); // ⚠️ 错误:session_start() 在检查之后才调用!
// ... 后续数据库验证逻辑
该写法存在双重问题:
- session_start() 调用位置错误:必须在任何输出(包括 header())之前调用,否则会触发 headers already sent 错误。而此处 session_start() 写在重定向判断之后,属于严重语法隐患;
- 无路径防护导致重定向循环:当用户直接访问 index.php 时,因 $_SESSION['username'] 未设置,仍会再次执行 header('Location: ./index.php'),造成浏览器持续 302 跳转,形成 Redirect Loop。
✅ 正确做法需同时满足两点:
- 前置调用 session_start()(建议放在文件最顶部);
- 跳转前判断当前脚本路径,避免对 index.php 自身生效。
推荐修正后的完整结构如下(以 Session.php 或受保护页面为例):
<?php session_start(); // ✅ 必须最先执行
// 仅当不在登录页且未登录时跳转
if (basename($_SERVER['PHP_SELF']) !== 'index.php' && !isset($_SESSION['username'])) {
header('Location: ./index.php');
exit;
}
// ✅ 此时可安全使用 $_SESSION
require "connessione.php";
$connessione = connessionedb("db");
$username = $_SESSION['username'];
$username = $connessione->real_escape_string($username);
$query = "SELECT * FROM utenti WHERE idUtente = '$username'";
$risultato = mysqli_query($connessione, $query);
$num_record = mysqli_num_rows($risultato);
if ($num_record !== 1) {
header('Location: ./index.php');
$connessione->close(); // 注意:原代码中变量名是 $connessione,非 $con
exit;
}
?>
? 关键注意事项:
- 使用 basename($_SERVER['PHP_SELF']) 比直接匹配 '/index.php' 更健壮,避免因 URL 重写或路径差异导致误判;
- 数据库连接关闭应使用正确变量名(示例中为 $connessione->close());
- 建议后续升级为预处理语句(mysqli_prepare)以彻底规避 SQL 注入风险,real_escape_string 仅为临时缓解;
- 若项目使用现代框架(如 Laravel、Symfony),应优先采用其内置认证中间件,而非手动 session 控制。
遵循以上结构,即可彻底消除重定向循环,同时保障会话安全与代码健壮性。










