HOWTO · PHP
在 PHP 中返回上一页
本教程介绍如何在 PHP 中返回上一页
本页内容
要将访客带回包含表单的页面,可以从 $_SERVER 读取可选的 HTTP_REFERER 值,只接受你允许的本地目标,并在生成响应内容之前用 header() 发送 Location 标头。来源页信息不一定存在,因此应设置安全的本地回退目标。
在 PHP 中使用 HTTP_REFERER 请求头返回上一页
index.php 中的表单可以提交到 home.php 之类的处理程序。浏览器可能会在 HTTP_REFERER 请求头中发送表单所在页面的 URL,PHP 则通过 $_SERVER['HTTP_REFERER'] 提供该值。浏览器和隐私设置可能会省略此标头,客户端也可以提供任意值,因此未经验证时不要据此重定向。这个标头只是请求附带的信息,并非可靠的浏览历史记录;即使它不存在,应用也应能正常工作。
在 index.php 中,表单可以随提交一并发送一条消息:
<form action="home.php" method="post"><input type="hidden" name="message" value="Saved."><button type="submit">Submit</button></form>
下面是完整的 home.php 处理程序,它只接受本地路径 /index.php。此示例使用了 str_contains(),因此需要 PHP 8.0 或更高版本。它会保留该页面已有的查询参数,添加提交的消息;如果来源页信息缺失或指向其他位置,则回退到 /index.php。从命令行运行时,示例会使用一组模拟请求数据并打印重定向目标,方便在本地看到成功路径;通过 Web 请求运行时,它会发送 303 重定向并退出。
<?php
// home.php
$isCli = PHP_SAPI === 'cli';
// Provide a sample request when running this file directly with PHP CLI.
if ($isCli) {
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['HTTP_REFERER'] = 'https://example.test/index.php?tab=profile';
$_POST['message'] = 'Saved.';
}
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
http_response_code(405);
exit;
}
$message = $_POST['message'] ?? 'Your form was submitted.';
if (!is_string($message)) {
$message = 'Your form was submitted.';
}
$destination = '/index.php';
$referrer = $_SERVER['HTTP_REFERER'] ?? '';
$parts = parse_url($referrer);
if (is_array($parts) && ($parts['path'] ?? '') === '/index.php') {
$query = [];
parse_str($parts['query'] ?? '', $query);
$destination = '/index.php';
if ($query !== []) {
$destination .= '?' . http_build_query($query);
}
}
$separator = str_contains($destination, '?') ? '&' : '?';
$target = $destination . $separator . http_build_query(['message' => $message]);
if ($isCli) {
echo $target, PHP_EOL;
exit;
}
header('Location: ' . $target, true, 303);
exit;
对于这组模拟请求,处理程序会打印以下重定向目标:
/index.php?tab=profile&message=Saved.
在返回页面中,将消息插入 HTML 之前要先对其进行转义。首先确认查询参数的值是字符串,因为查询参数也可能以数组形式传入:htmlspecialchars(is_string($_GET['message'] ?? null) ? $_GET['message'] : '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')。处理程序中的 URL 编码可保护查询参数;显示时的 HTML 转义则可保护页面。对于任何将传入只接受字符串的转义函数的值,也应进行同样的字符串检查。
处理程序会根据获准的本地路径重新构造目标,而不是使用来源页信息中的主机名,因此外部 URL 不会成为重定向目标。此处的路径允许列表刻意保持精简:如果应用有多个表单页面,就应明确列出每个获准的本地路径,并为列表之外的值保留安全的本地回退目标。示例会保留获准来源页中的查询参数,再通过 http_build_query() 添加或替换 message 参数;这样无需手动拼接 URL 编码,也能将重定向路径与查询字符串分开处理。
header() 必须在任何 HTML、空白字符或其他响应内容输出之前运行。重定向之后调用 exit,可避免处理程序后续代码继续执行,让请求看起来像是正常完成了一样。303 状态码会告知浏览器:表单通过 POST 提交后,后续重定向请求应使用 GET。命令行分支仅用于演示;通过 Web 请求运行时,PHP 会发送响应标头,而不会把目标打印为页面内容。如果托管环境使用较早版本的 PHP,可以将 str_contains($destination, '?') 替换为兼容的检查,例如 strpos($destination, '?') !== false,并确认应用的其余部分也支持该版本。