多步驟表單(如:列表 → 新增 → 確認 → 完成)需在最後一步「返回列表」時跳轉回原始列表頁。由於 HTTP 無狀態、HTTP_REFERER 不可靠(可能被代理/防火牆剝離、用戶直接訪問),最穩健方案是**在首個表單頁將原始 URL 寫入隱藏字段,層層透傳**。
<?php
// list.php
$returnUrl = urlencode('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
// 或手動構建:$returnUrl = urlencode('/admin/users?page=3&status=active');
?>
新增用戶
<?php
// create.php
$return = $_GET['return'] ?? '/admin/users'; // 默認回退
$return = urldecode($return); // 還原
?>
<?php
// confirm.php
$return = $_POST['return_url'] ?? '/admin/users';
?>
<?php
// store.php
$return = $_POST['return_url'] ?? '/admin/users';
// 業務邏輯:驗證、入庫...
$success = User::create($_POST);
if ($success) {
// 成功:跳轉回原始列表頁
header("Location: $return");
exit;
} else {
// 失敗:返回確認頁並保留 return_url
header("Location: confirm.php?return_url=" . urlencode($return));
exit;
}
?>
<?php
/** 生成帶返回 URL 的表單隱藏字段 HTML */
function return_url_field(string $name = 'return_url', ?string $default = null): string {
$url = $_POST[$name] ?? $_GET[$name] ?? $default ?? '/';
return '';
}
/** 獲取返回 URL,優先 POST > GET > 默認 */
function get_return_url(string $name = 'return_url', string $default = '/'): string {
return $_POST[$name] ?? $_GET[$name] ?? $default;
}
/** 安全跳轉:驗證 URL 同域、非危險協議 */
function safe_redirect(string $url, string $fallback = '/'): void {
$parsed = parse_url($url);
if (!$parsed || !isset($parsed['host'])) {
$url = $fallback;
} elseif ($parsed['host'] !== $_SERVER['HTTP_HOST']) {
$url = $fallback; // 防開放重定向攻擊
}
header("Location: $url");
exit;
}
// 使用示例
$return = get_return_url();
safe_redirect($return);
| 場景 | HTTP_REFERER 表現 | 隱藏字段方案 |
|---|---|---|
| 用戶從收藏夾/地址欄直接進入 | 空 | 有默認回退 |
| HTTPS → HTTP 跨協議 | 瀏覽器不發送 | 正常透傳 |
| 企業代理/殺毒軟體剝離 | 丟失 | 正常透傳 |
| 中間頁面刷新/F5 | 變為中間頁 URL | 保持原始 URL |
| 開放重定向攻擊風險 | 高(直接信任) | 可在 safe_redirect 中驗證同域 |
<a href="= $return ?>>取消</a>。 FormData 中,成功回調 window.location = returnUrl。 return_url,登錄成功跳回原受保護頁面。