
本文介绍使用 php session 实现表单提交后跳转刷新页面的同时,仍能安全显示错误或成功提示消息的方法,并彻底解决 f5 刷新导致的重复提交问题。
本文介绍使用 php session 实现表单提交后跳转刷新页面的同时,仍能安全显示错误或成功提示消息的方法,并彻底解决 f5 刷新导致的重复提交问题。
在 Web 开发中,常见需求是:用户提交登录表单后,若校验失败(如用户名为空、账号密码错误),需在原页面(如 index.php)顶部显示友好提示;同时为避免“重复提交”警告(浏览器提示“To display this page, Firefox must send information that will repeat any action…”),必须通过 header("Location: ...") 进行重定向(即 Post-Redirect-Get 模式,PRG)。但直接重定向会导致当前请求中的局部变量(如 $error1)丢失,无法在新加载的页面中显示。
✅ 正确解法是:将提示消息暂存于 $_SESSION,重定向后在目标页读取并立即销毁。这既满足 PRG 原则,又保证用户体验连贯。
✅ 实现步骤详解
- 开启会话:确保 session_start() 在文件最顶部(已存在);
- 提交时存入 Session:不再用局部变量 $error1,改用 $_SESSION['error1'] = "...";
- 统一重定向:所有分支(空用户名、登录失败)均执行 header("Location: index.php"); exit;;
- 展示并清理 Session 消息:在 HTML 表单上方检查 isset($_SESSION['error1']),输出后立即 unset(),避免多次显示。
✅ 修正后的关键代码段
<?php
session_start();
include("includes/config.php");
if (isset($_POST['submit'])) {
// 注意:此处 $username 尚未定义,应从 $_POST 中获取!
$username = $_POST['username'] ?? '';
if (empty($username)) {
$_SESSION['error1'] = "Please enter username.";
header("Location: index.php");
exit; // ⚠️ 必须 exit,防止后续代码执行
}
$username = mysqli_real_escape_string($con, $_POST['username']);
$password = mysqli_real_escape_string($con, $_POST['password']);
$sql = "SELECT * FROM admin_user WHERE username='$username' AND password='$password'";
$res = mysqli_query($con, $sql);
if (mysqli_num_rows($res) > 0) {
// 修复:$id 未定义,应从查询结果中获取
$row = mysqli_fetch_assoc($res);
$_SESSION["username"] = $username;
$_SESSION["id"] = $row['id']; // ✅ 正确赋值
$_SESSION['admin']['status'] = true;
header("Location: dashboard.php");
exit;
} else {
$_SESSION['error1'] = "Invalid username or password.";
header("Location: index.php");
exit;
}
}
?>
<!-- 消息展示区(在表单上方) -->
<?php if (isset($_SESSION['error1'])): ?>
<div class="alert alert-danger mb-4">
<?php echo htmlspecialchars($_SESSION['error1']); ?>
</div>
<?php unset($_SESSION['error1']); ?>
<?php endif; ?>
<!-- 登录表单 -->
<form method="post">
<div class="mb-3">
<label for="username" class="form-label">Username*</label>
<input type="text" name="username" class="form-control" id="username"
placeholder="Enter username" value="<?php echo htmlspecialchars($_POST['username'] ?? ''); ?>">
</div>
<div class="mb-3">
<label class="form-label" for="password-input">Password*</label>
<div class="position-relative auth-pass-inputgroup mb-3">
<input type="password" name="password" class="form-control pe-5"
placeholder="Enter password" id="password">
<button class="btn btn-link position-absolute end-0 top-0 text-decoration-none text-muted shadow-none"
type="button" id="password-addon"><i class="ri-eye-fill align-middle"></i></button>
</div>
</div>
<div class="mt-4">
<button class="btn btn-success w-100" name="submit" type="submit">Sign In</button>
</div>
</form>⚠️ 重要注意事项
- 务必添加 exit 或 die:每次 header() 后必须终止脚本,否则后续逻辑仍会执行,造成逻辑混乱或安全风险;
- 修复潜在漏洞:原始代码中 $id 未定义,已改为从查询结果中提取;同时对输出内容使用 htmlspecialchars() 防止 XSS;
- 保留用户输入:为提升体验,可将 $_POST['username'] 回填至输入框(如示例所示),避免用户重复输入;
- 扩展性建议:可封装为通用函数(如 setFlashMessage('error', '...') 和 getFlashMessage()),便于多处复用;
- 安全性提醒:mysqli_real_escape_string 仅防 SQL 注入,推荐升级为预处理语句(PDO/MySQLi prepared statements)。
遵循此方案,即可在保障安全(防重复提交、防 XSS、防 SQL 注入)的前提下,实现清晰、可靠的表单反馈体验。


















