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

PHP 檢測遠程 URL 是否存在的兩種高效方法(get_headers / cURL)

     編輯:PHP 綜合知識

應用場景

在開發鏈接驗證、圖片熱鏈保護、資源可用性巡檢等功能時,常需判斷遠程 URL 是否可訪問(HTTP 200)。本文對比兩種主流方案,給出生產環境可用的封裝函數。

方法一:get_headers() — 簡潔易用

get_headers() 內部封裝 HTTP HEAD 請求,預設跟隨重定向,返回響應頭陣列。

function urlExistsGetHeaders(string $url): bool {
    $headers = @get_headers($url, true); // true 返回關聯陣列
    if ($headers === false) {
        return false; // DNS 失敗、連線超時等
    }
    // 兼容數字索引與關聯索引
    $statusLine = is_array($headers) ? ($headers[0] ?? '') : '';
    return stripos($statusLine, '200') !== false;
}

// 使用示例
$url = 'https://example.com/image.jpg';
var_dump(urlExistsGetHeaders($url)); // bool(true/false)

優缺點

  • ✅ 代碼極簡,無需額外擴展
  • ✅ 自動處理重定向
  • ❌ 無法精確控制超時(受 default_socket_timeout 影響)
  • ❌ 無法自定義 User-Agent、Cookie 等請求頭
  • ❌ 部分舊版本 PHP 在 HTTPS 上可能失效

方法二:cURL — 功能全面、可控性強

僅發送 HEAD 請求(CURLOPT_NOBODY),不下載實體內容,極其輕量。

function urlExistsCurl(string $url, int $timeout = 5): bool {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_NOBODY        => true,      // 只取頭
        CURLOPT_RETURNTRANSFER=> true,
        CURLOPT_FOLLOWLOCATION=> true,      // 跟隨 301/302
        CURLOPT_CONNECTTIMEOUT=> $timeout,  // 連線超時
        CURLOPT_TIMEOUT       => $timeout,  // 總超時
        CURLOPT_SSL_VERIFYPEER=> false,     // 生產環境建議 true 並配置 CA
        CURLOPT_USERAGENT     => 'Mozilla/5.0 (LinkChecker)',
    ]);
    $result = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $errno = curl_errno($ch);
    curl_close($ch);

    if ($errno !== 0) {
        // 可記錄 curl_error($ch) 供排查
        return false;
    }
    return $httpCode === 200;
}

進階:批量並發檢測(cURL Multi)

需檢測大量 URL 時,使用 curl_multi_* 並發執行,耗時約為串行的 1/N。

function batchCheckUrls(array $urls, int $concurrency = 10, int $timeout = 5): array {
    $mh = curl_multi_init();
    $handles = [];
    $results = [];

    // 初始化 easy handles
    foreach ($urls as $i => $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_NOBODY => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => $timeout,
            CURLOPT_TIMEOUT => $timeout,
        ]);
        curl_multi_add_handle($mh, $ch);
        $handles[$i] = $ch;
    }

    // 並發執行循環
    $running = null;
    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh, 0.1);
    } while ($running > 0);

    // 收集結果
    foreach ($handles as $i => $ch) {
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $errno = curl_errno($ch);
        $results[$urls[$i]] = ($errno === 0 && $httpCode === 200);
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
    curl_multi_close($mh);
    return $results;
}

方案選型建議

維度get_headers()cURL
代碼複雜度極低中等
超時控制全局 ini 設定精確到毫秒
請求頭自定義不支援完全支援
並發批量不支援支援 curl_multi
適用場景少量、簡單檢測高併發、需定制、生產環境

常見坑點提示

  • 重定向陷阱: 301/302 導致最終狀態碼非 200,業務層需明確是否允許重定向。
  • CDN/WAF 拦截: 缺乏 User-Agent 或請求頻率過高會被封禁,必須模擬瀏覽器 UA、控制併發、加入隨機延遲。
  • HTTPS 證書驗證: 生產環境請勿關閉 CURLOPT_SSL_VERIFYPEER,改為部署 CA 憑證包(cacert.pem)。
  • 超時設置: 區分「連線超時」與「讀取超時」,防止慢速攻擊佔用執行緒。

總結

簡單場景用 get_headers() 一行搞定;生產級、高併發、需定制請求的場景,請毫不猶豫選擇 cURL(含 Multi 介面)。封裝成可複用的 Service 類,統一異常處理、日誌記錄、指標監控,才是成熟工程化的做法。

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