| 場景 | Apache (mod_rewrite) | IIS (ISAPI_Rewrite) |
|---|---|---|
| 重寫後的原始 URL | $_SERVER['REDIRECT_URL'] | $_SERVER['HTTP_X_REWRITE_URL'] |
| 重寫後的查詢字串 | $_SERVER['REDIRECT_QUERY_STRING'] | 無(包含在 HTTP_X_REWRITE_URL) |
| 原始請求 URI | $_SERVER['REQUEST_URI'] | $_SERVER['REQUEST_URI'](可能未重寫) |
<?php
/**
* 獲取用戶瀏覽器地址欄顯示的 URL(含查詢字串)
* 兼容 Apache mod_rewrite、IIS ISAPI_Rewrite、Nginx、無重寫
*/
function getDisplayUrl(): string {
// 1. ISAPI_Rewrite (IIS)
if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
return $_SERVER['HTTP_X_REWRITE_URL'];
}
// 2. Apache mod_rewrite
if (isset($_SERVER['REDIRECT_URL'])) {
$url = $_SERVER['REDIRECT_URL'];
if (isset($_SERVER['REDIRECT_QUERY_STRING'])) {
$url .= '?' . $_SERVER['REDIRECT_QUERY_STRING'];
}
return $url;
}
// 3. Nginx + PHP-FPM (通常無 REDIRECT_* 變量)
// 4. 普通請求
return $_SERVER['REQUEST_URI'] ?? '/';
}
需求:/article.php?id=123 → /article/123.html
<?php
// 入口文件最頂部執行
$displayUrl = getDisplayUrl();
// 判斷是否為舊式動態參數 URL
if (preg_match('#^/article\.php\?id=(\d+)$#', $displayUrl, $matches)) {
$id = (int)$matches[1];
if ($id > 0) {
$newUrl = "/article/{$id}.html";
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $newUrl);
exit;
}
}
// 正常路由分發...
關鍵在於只在「舊格式」時重定向,新格式直接進入路由:
<?php
// 檢測是否已經是靜態化 URL
if (preg_match('#^/article/\d+\.html$#', $displayUrl)) {
// 已是新格式,正常處理
return;
}
// 否則嘗試從舊格式轉換...
Nginx 不會產生 REDIRECT_* 變量,REQUEST_URI 即為重寫後的 URL。若需獲取原始未重寫 URL,需在 Nginx 配置中額外傳遞:
# nginx.conf
location / {
try_files $uri $uri/ /index.php?$query_string;
# 額外傳遞原始 URI
fastcgi_param ORIGINAL_URI $request_uri;
}
<?php
// PHP 端讀取
$originalUri = $_SERVER['ORIGINAL_URI'] ?? $_SERVER['REQUEST_URI'];
<?php
function detectRewriteEnv(): array {
return [
'is_apache_rewrite' => isset($_SERVER['REDIRECT_URL']),
'is_iis_isapi' => isset($_SERVER['HTTP_X_REWRITE_URL']),
'is_nginx' => strpos($_SERVER['SERVER_SOFTWARE'] ?? '', 'nginx') !== false,
'display_url' => getDisplayUrl(),
'request_uri' => $_SERVER['REQUEST_URI'] ?? '',
'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown',
];
}
print_r(detectRewriteEnv());