如何用PHP结合HTTP_REFERER实现页面自刷新后仍正常工作的返回按钮
问题原因
- 你遇到的变量被意外覆盖的核心原因是存在二次请求:大概率是你的.htaccess重写规则没有过滤真实存在的静态资源,页面的favicon.ico、空src的img标签、空href的link标签等都会触发浏览器自动请求当前域名的对应路径,该请求也被转发到了index.php执行。第二次请求的
HTTP_REFERER就是当前页面地址,所以会触发更新逻辑覆盖原有值。 - 你使用的内部重写规则(不带[R]跳转标记的htaccess规则)不会修改
$_SERVER["HTTP_REFERER"]的取值,该变量是浏览器发起请求时携带的请求头,服务端内部路径转发不会修改请求头内容。 - 原有代码没有做空值判断:如果用户直接访问站点、或者浏览器禁用了REFERER传递,
$_SERVER["HTTP_REFERER"]不存在会触发PHP警告,正则匹配失败时$start为空也会导致逻辑错误。
修复方案
第一步:排查并解决二次请求问题
修改你的.htaccess规则,仅当请求路径不是真实存在的文件或目录时才转发到index.php,避免静态资源请求进入PHP逻辑:
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [L]
你也可以在index.php顶部加日志逻辑,打印每次请求的URI和REFERER,确认是否存在多余请求:
file_put_contents('./request_log.txt', date('Y-m-d H:i:s') . ' | URI:' . $_SERVER['REQUEST_URI'] . ' | REFERER:' . ($_SERVER['HTTP_REFERER'] ?? '空') . PHP_EOL, FILE_APPEND);
第二步:优化来源存储逻辑
方案1:优化现有REFERER判断逻辑
session_start(); // 初始化默认来源页为首页 if (!isset($_SESSION['referer'])) { $_SESSION['referer'] = '/'; } if (isset($_SERVER['HTTP_REFERER'])) { $referer = $_SERVER['HTTP_REFERER']; // 生成当前页面完整地址 $current_scheme = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http'; $current_url = $current_scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; // 提取来源页域名,仅处理本站内的来源 $referer_host = parse_url($referer, PHP_URL_HOST); if ($referer_host === $_SERVER['HTTP_HOST'] && $referer !== $current_url) { $_SESSION['referer'] = $referer; } } // 返回按钮调用方式 // <a href="<?php echo htmlspecialchars($_SESSION['referer']); ?>">返回</a>
方案2:更稳定的历史栈方案(不依赖HTTP_REFERER)
如果不想受浏览器REFERER传递策略影响,可以用会话存储访问历史栈:
session_start(); // 初始化访问历史栈 if (!isset($_SESSION['visit_history'])) { $_SESSION['visit_history'] = []; } $current_path = $_SERVER['REQUEST_URI']; // 仅当当前路径和栈顶路径不一致时才入栈,避免刷新重复入栈 if (empty($_SESSION['visit_history']) || end($_SESSION['visit_history']) !== $current_path) { array_push($_SESSION['visit_history'], $current_path); // 最多保留5条历史,避免会话数据过大 if (count($_SESSION['visit_history']) > 5) { array_shift($_SESSION['visit_history']); } } // 生成返回地址:栈长度≥2则取倒数第二条,否则返回首页 $back_url = count($_SESSION['visit_history']) >= 2 ? $_SESSION['visit_history'][count($_SESSION['visit_history']) - 2] : '/';
内容的提问来源于stack exchange,提问作者David Edwards
相关产品推荐
相关产品推荐

