在開發鏈接驗證、圖片熱鏈保護、資源可用性巡檢等功能時,常需判斷遠程 URL 是否可訪問(HTTP 200)。本文對比兩種主流方案,給出生產環境可用的封裝函數。
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 影響)僅發送 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;
}
需檢測大量 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 |
| 適用場景 | 少量、簡單檢測 | 高併發、需定制、生產環境 |
CURLOPT_SSL_VERIFYPEER,改為部署 CA 憑證包(cacert.pem)。簡單場景用 get_headers() 一行搞定;生產級、高併發、需定制請求的場景,請毫不猶豫選擇 cURL(含 Multi 介面)。封裝成可複用的 Service 類,統一異常處理、日誌記錄、指標監控,才是成熟工程化的做法。