PHP 專案中頁面跳轉(重導向)是高頻需求,需考慮:輸出緩衝狀態、延遲秒數、JS/HTML 相容、AJAX 回應等細節。
<?php
/**
* 通用頁面跳轉函數
* @param string $url 目標網址
* @param int $delay 延遲秒數(0 為立即)
* @param bool $js 是否輸出 JS 代碼而非 Header
* @param bool $jsWrapped JS 是否用 script 標籤包裹
* @param bool $return 是否返回字串而非直接輸出
*/
function redirect(string $url, int $delay = 0, bool $js = false, bool $jsWrapped = true, bool $return = false): ?string {
$url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
if (!$js) {
// 純 Header 跳轉(最快、SEO 友善)
if (!headers_sent() && $delay === 0) {
header("Location: {$url}");
exit;
}
// 已有輸出或需延遲 → HTML meta refresh
$html = <<
頁面跳轉中...
正在跳轉,請稍候...
HTML;
if ($return) return $html;
echo $html;
exit;
}
// JS 跳轉模式(AJAX、iframe、需執行邏輯再跳轉)
$jsCode = $delay > 0
? "setTimeout(() => { location.href = '{$url}'; }, {$delay}000);"
: "location.href = '{$url}';";
$out = $jsWrapped ? "" : $jsCode;
if ($return) return $out;
echo $out;
exit;
}
?>
<?php
// 1. 立即跳轉(表單提交成功後)
redirect('/dashboard');
// 2. 3 秒後跳轉(顯示成功訊息)
redirect('/login', 3);
// 3. AJAX 回傳 JS 跳轉(不刷新父頁)
echo redirect('/pay/callback', 0, true, true, true); // 返回 JS 字串
// 4. 已有輸出內容時(無法用 header)
echo '處理完成...';
redirect('/home', 2); // 自動改用 meta refresh
?>
<?php
/**
* 統一操作回應格式:成功/失敗、訊息、資料、跳轉
*/
class ActionResult {
public int $code = 200; // 200 成功,其他為錯誤碼
public string $msg = '';
public mixed $data = null;
public ?string $redirectUrl = null;
public int $redirectDelay = 0;
public static function success(string $msg = '操作成功', mixed $data = null): self {
$r = new self();
$r->msg = $msg;
$r->data = $data;
return $r;
}
public static function error(int $code, string $msg): self {
$r = new self();
$r->code = $code;
$r->msg = $msg;
return $r;
}
public function withRedirect(string $url, int $delay = 1): self {
$this->redirectUrl = $url;
$this->redirectDelay = $delay;
return $this;
}
// 輸出 JSON(API 專用)
public function toJson(): string {
return json_encode($this, JSON_UNESCAPED_UNICODE);
}
// 輸出 HTML 提示頁(傳統頁面)
public function toHtml(): string {
$html = <<
{$this->msg}
{$this->msg}
HTML;
if ($this->redirectUrl) {
$html .= "{$this->redirectDelay} 秒後自動跳轉... 立即跳轉
";
$html .= "";
}
$html .= "";
return $html;
}
}
?>
<?php
// API 端點
public function store(Request $request) {
try {
$order = $this->orderService->create($request->validated());
return ActionResult::success('訂單建立成功', $order)->toJson();
} catch (ValidationException $e) {
return ActionResult::error(422, $e->getMessage())->toJson();
}
}
// 傳統表單提交
public function update(Request $request, $id) {
$this->service->update($id, $request->all());
return ActionResult::success('更新成功')
->withRedirect('/admin/items', 2)
->toHtml();
}
?>
ActionResult。redirect() 內部判斷 headers_sent() 決定 Header 或 Meta/JS。htmlspecialchars 防 XSS,延遲參數強制 int。$return=true 取得字串供單元測試斷言。封裝良好的跳轉與提示機制,能大幅減少控制器樣板代碼,統一用戶體驗。