首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實現 301 永久重導向:域名遷移、HTTPS 強制、SEO 保留權重完整指南

     編輯:PHP 相關知識

301 重導向是網站遷移、域名變更、HTTPS 強制的關鍵 SEO 技術,正確實作能保留搜尋引擎權重。本文提供 PHP 多種場景的 301 實作、測試方法與常見錯誤避坑指南。

基本 301 重導向語法

<?php
// 必須在任何輸出之前呼叫
header('HTTP/1.1 301 Moved Permanently');
header('Location: https://www.new-domain.com' . $_SERVER['REQUEST_URI']);
exit; // 關鍵:防止後續代碼執行
?>

常見場景實作

1. 域名遷移(舊域名導向新域名)

<?php
// 301_redirect.php - 放在舊網站入口檔案最頂端
$oldDomains = [
    'old-domain.com',
    'www.old-domain.com',
    'legacy.example.com'
];

$newDomain = 'www.new-domain.com';
$currentHost = $_SERVER['HTTP_HOST'] ?? '';

if (in_array($currentHost, $oldDomains, true)) {
    $requestUri = $_SERVER['REQUEST_URI'] ?? '/';
    $targetUrl = "https://{$newDomain}{$requestUri}";
    
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: {$targetUrl}");
    exit;
}
?>

2. 強制 HTTPS

<?php
// 強制 HTTPS(建議在 Web 伺服器層面設定,PHP 作為備援)
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') {
    $host = $_SERVER['HTTP_HOST'] ?? '';
    $requestUri = $_SERVER['REQUEST_URI'] ?? '/';
    $targetUrl = "https://{$host}{$requestUri}";
    
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: {$targetUrl}");
    exit;
}

// HSTS 標頭(建議在伺服器設定)
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
?>

3. 強制 WWW 或非 WWW

<?php
// 統一為 www
$host = $_SERVER['HTTP_HOST'] ?? '';
if (!str_starts_with($host, 'www.')) {
    $targetUrl = "https://www.{$host}" . ($_SERVER['REQUEST_URI'] ?? '/');
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: {$targetUrl}");
    exit;
}

// 或統一為非 www(二選一)
if (str_starts_with($host, 'www.')) {
    $targetUrl = "https://" . substr($host, 4) . ($_SERVER['REQUEST_URI'] ?? '/');
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: {$targetUrl}");
    exit;
}
?>

4. URL 結構變更(含查詢參數保留)

<?php
// 舊結構:/product.php?id=123 -> 新結構:/product/123
$redirectMap = [
    '/product.php' => '/product/',
    '/category.php' => '/category/',
    '/article.php' => '/article/'
];

$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
$path = parse_url($requestUri, PHP_URL_PATH);
$query = parse_url($requestUri, PHP_URL_QUERY);

foreach ($redirectMap as $oldPath => $newPath) {
    if ($path === $oldPath) {
        $id = $_GET['id'] ?? '';
        if ($id !== '') {
            $targetUrl = "https://{$_SERVER['HTTP_HOST']}{$newPath}{$id}";
            if ($query) {
                // 保留其他參數(排除 id)
                parse_str($query, $params);
                unset($params['id']);
                if ($params) {
                    $targetUrl .= '?' . http_build_query($params);
                }
            }
            header('HTTP/1.1 301 Moved Permanently');
            header("Location: {$targetUrl}");
            exit;
        }
    }
}
?>

5. 內容遷移對照表(大量頁面)

<?php
// 使用資料庫或快取儲存對照表
$redirects = [
    '/old-page-1' => '/new-category/page-1',
    '/old-page-2' => '/new-category/page-2',
    // ... 數千筆
];

$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
$path = parse_url($requestUri, PHP_URL_PATH);

if (isset($redirects[$path])) {
    $targetUrl = "https://{$_SERVER['HTTP_HOST']}{$redirects[$path]}";
    // 保留查詢字串
    $query = parse_url($requestUri, PHP_URL_QUERY);
    if ($query) {
        $targetUrl .= '?' . $query;
    }
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: {$targetUrl}");
    exit;
}

// 效能優化:大量對照表用 Redis 或 APCu
// $targetPath = apcu_fetch("redirect:{$path}");
// if ($targetPath) { ... }
?>

進階:中介層架構(適用框架)

<?php
// Middleware/Redirect301.php
class Redirect301Middleware {
    private array $rules = [];
    private array $domainRules = [];

    public function addDomainRule(string $fromHost, string $toHost): self {
        $this->domainRules[strtolower($fromHost)] = $toHost;
        return $this;
    }

    public function addPathRule(string $fromPath, string $toPath, bool $keepQuery = true): self {
        $this->rules[$fromPath] = ['to' => $toPath, 'keepQuery' => $keepQuery];
        return $this;
    }

    public function addRegexRule(string $pattern, string $replacement): self {
        $this->rules[$pattern] = ['regex' => true, 'replacement' => $replacement];
        return $this;
    }

    public function handle(Request $request, callable $next): Response {
        $host = strtolower($request->getHost());
        $path = $request->getPathInfo();
        $query = $request->getQueryString();

        // 域名規則
        if (isset($this->domainRules[$host])) {
            $targetHost = $this->domainRules[$host];
            $targetUrl = "https://{$targetHost}{$path}" . ($query ? "?{$query}" : '');
            return new RedirectResponse($targetUrl, 301);
        }

        // 精確路徑匹配
        if (isset($this->rules[$path])) {
            $rule = $this->rules[$path];
            $targetPath = $rule['to'];
            $targetQuery = $rule['keepQuery'] ? $query : '';
            $targetUrl = "https://{$host}{$targetPath}" . ($targetQuery ? "?{$targetQuery}" : '');
            return new RedirectResponse($targetUrl, 301);
        }

        // 正則規則
        foreach ($this->rules as $pattern => $rule) {
            if (($rule['regex'] ?? false) && preg_match($pattern, $path, $matches)) {
                $targetPath = preg_replace($pattern, $rule['replacement'], $path);
                $targetUrl = "https://{$host}{$targetPath}" . ($query ? "?{$query}" : '');
                return new RedirectResponse($targetUrl, 301);
            }
        }

        return $next($request);
    }
}

// 註冊規則
$middleware = new Redirect301Middleware()
    ->addDomainRule('old.example.com', 'www.new-example.com')
    ->addPathRule('/product.php', '/product/', true)
    ->addRegexRule('#^/user/(\d+)$#', '/profile/$1');
?>

測試與驗證

命令列測試

# 檢查回應碼與 Location 標頭
curl -I "https://old-domain.com/product.php?id=123"

# 預期輸出:
# HTTP/1.1 301 Moved Permanently
# Location: https://www.new-domain.com/product/123
# Content-Type: text/html; charset=UTF-8

線上工具

自動化測試腳本

<?php
// test_redirects.php
$testCases = [
    ['url' => 'https://old.com/page1', 'expected' => 'https://www.new.com/page1', 'code' => 301],
    ['url' => 'https://old.com/page2?utm=src', 'expected' => 'https://www.new.com/page2?utm=src', 'code' => 301],
    ['url' => 'https://www.new.com/page3', 'expected' => null, 'code' => 200], // 不應重導向
];

foreach ($testCases as $case) {
    $ch = curl_init($case['url']);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => true,
        CURLOPT_NOBODY => true,
        CURLOPT_FOLLOWLOCATION => false, // 關鍵:不自動追蹤
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_TIMEOUT => 10
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $location = '';
    
    if (preg_match('/^Location:\s*(.+)$/im', $response, $m)) {
        $location = trim($m[1]);
    }
    curl_close($ch);
    
    $pass = $httpCode === $case['code'] 
        && ($case['expected'] === null || $location === $case['expected']);
    
    echo ($pass ? '✓' : '✗') . " {$case['url']} -> {$httpCode} {$location}\n";
}
?>

常見錯誤與避坑

錯誤後果正確做法
用 302 代替 301搜尋引擎不傳遞權重,舊頁面保留索引永久遷移必須用 301
重導向鏈過長(A→B→C)爬蟲放棄追蹤,權重流失,載入慢直接導向最終目標,最多 1 次跳轉
導向無關頁面(如首頁)軟 404、用戶體驗差、權重不傳遞一對一對應相關內容
查詢參數丟失UTM 追蹤失效、分頁/篩選狀態消失保留或合理轉換查詢字串
HTTP/HTTPS 混合導向安全性警告、SEO 損害統一 HTTPS,HSTS 預載
輸出內容前未 exit可能輸出雜訊、導向失效header 後立即 exit

Web 伺服器層面設定(效能更好)

Nginx

# 域名遷移
server {
    server_name old-domain.com www.old-domain.com;
    return 301 https://www.new-domain.com$request_uri;
}

# 強制 HTTPS
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

# 路徑對照
location /product.php {
    rewrite ^/product\.php$ /product/$arg_id? permanent;
}

Apache (.htaccess)

RewriteEngine On

# 域名遷移
RewriteCond %{HTTP_HOST} ^(www\.)?old-domain\.com$ [NC]
RewriteRule ^(.*)$ https://www.new-domain.com/$1 [R=301,L]

# 強制 HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# 強制 WWW
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

**最佳實踐**:優先在 Web 伺服器層面設定 301(效能最好、不經 PHP)、PHP 作為複雜邏輯備援、建立完整對照表與自動化測試、上線後持續監控 Search Console 索引狀態、保留舊域名至少 1 年並續約 SSL 憑證。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved