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

PHP 獲取重定向後最終 URL 的完整實現方案

     編輯:PHP 相關知識

處理短網址、防盜鏈、CDN 跳轉等場景時,常需解析重定向鏈路獲取最終落地頁。本文提供基於 Socket 與 cURL 兩種方案的完整實現。

方案一:Socket 底層實現 (無依賴)

發送 HEAD 請求解析 Location 標頭,遞迴追蹤完整重定向鏈:

<?php
class RedirectUrl {
    private $url;

    public function __construct($url) {
        $this->url = $url;
    }

    /** 獲取單次重定向目標 */
    private function getRedirectUrl($url) {
        $parts = @parse_url($url);
        if (!$parts || !isset($parts['host'])) return false;
        $parts['path'] = $parts['path'] ?? '/';

        $sock = fsockopen($parts['host'], $parts['port'] ?? 80, $errno, $errstr, 30);
        if (!$sock) return false;

        $request = "HEAD {$parts['path']}" . (isset($parts['query']) ? '?' . $parts['query'] : '') . " HTTP/1.1\r\n";
        $request .= "Host: {$parts['host']}\r\n";
        $request .= "Connection: Close\r\n\r\n";
        fwrite($sock, $request);

        $response = '';
        while (!feof($sock)) $response .= fread($sock, 8192);
        fclose($sock);

        if (preg_match('/^Location: (.+?)$/m', $response, $matches)) {
            return trim($matches[1]);
        }
        return false;
    }

    /** 遞迴獲取所有重定向 */
    private function getAllRedirects($url) {
        $redirects = [];
        while ($newUrl = $this->getRedirectUrl($url)) {
            if (in_array($newUrl, $redirects)) break; // 防循環
            $redirects[] = $newUrl;
            $url = $newUrl;
        }
        return $redirects;
    }

    /** 獲取最終 URL */
    public function getFinalUrl() {
        $redirects = $this->getAllRedirects($this->url);
        return $redirects ? array_pop($redirects) : $this->url;
    }
}

// 使用範例
$obj = new RedirectUrl('https://short.url/abc');
echo $obj->getFinalUrl();

方案二:cURL 實現 (推薦生產環境)

更健壯、支援 HTTPS、自動處理壓縮、Cookie、並行請求:

function getFinalUrlCurl($url, $maxRedirects = 10) {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_HEADER => true,
        CURLOPT_NOBODY => true,        // HEAD 請求
        CURLOPT_FOLLOWLOCATION => false, // 手動處理遞迴
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP Redirect Resolver)',
    ]);

    $redirects = 0;
    $finalUrl = $url;

    while ($redirects < $maxRedirects) {
        $response = curl_exec($ch);
        if ($response === false) break;

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($httpCode < 300 || $httpCode >= 400) break; // 非重定向

        // 從回應標頭提取 Location
        $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $header = substr($response, 0, $headerSize);
        if (preg_match('/^Location:\s*(.+)$/mi', $header, $matches)) {
            $finalUrl = trim($matches[1]);
            // 處理相對 URL
            if (strpos($finalUrl, 'http') !== 0) {
                $parts = parse_url($url);
                $finalUrl = $parts['scheme'] . '://' . $parts['host'] . 
                    (strpos($finalUrl, '/') === 0 ? '' : dirname($parts['path']) . '/') . $finalUrl;
            }
            curl_setopt($ch, CURLOPT_URL, $finalUrl);
            $url = $finalUrl;
            $redirects++;
        } else {
            break;
        }
    }

    curl_close($ch);
    return $finalUrl;
}

進階應用:圖片防盜鏈備用圖

function getShowPic($url, $noImg = 'noimg.gif', $fallback = 'https://example.com/default.jpg') {
    $finalUrl = getFinalUrlCurl($url);
    // 若最終圖為預設佔位圖,回傳備用圖
    return strpos($finalUrl, $noImg) !== false ? $fallback : $url;
}

// 使用
echo "<img src='" . getShowPic('https://i2.ku6img.com/encode/picpath/.../5.jpg') . "'/>";

方案比較與選擇建議

特性Socket 方案cURL 方案
依賴無 (核心函式)需 php-curl 擴充
HTTPS 支援需自行實現 SSL原生支援
效能單請求較快連線複用、並行優勢
健壯性需自行處理編碼、壓縮完善錯誤處理
推薦場景簡單環境、無 cURL 限制生產環境、高併發

注意事項

  • 設定合理的 maxRedirects 防止無限循環
  • 處理相對路徑 Location 標頭
  • 某些 CDN 返回 302 但無 Location,需檢查 Refresh 標頭或 JS 跳轉
  • 大量解析時建議使用 curl_multi 並行處理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved