方法比較表
| 方法 | 原理 | 優點 | 缺點 | 推薦度 |
| cURL HEAD | 發送 HEAD 請求,檢查 HTTP 狀態碼 | 不下載內文、支援 HTTPS、可檢查 Header | 需啟用 cURL、部分伺服器不支援 HEAD | ★★★★★ |
| cURL GET + NOBODY | GET 請求但不接收 Body | 相容性較 HEAD 好 | 仍下載 Header、稍慢 | ★★★★☆ |
| get_headers() | PHP 內建取得所有 Header | 程式碼極簡潔 | 無法控制超時、跟隨重導向、效能較差 | ★★★☆☆ |
| fopen() | 嘗試以讀模式開啟 URL | 原生函式、無需擴充套件 | 會下載內文、無法自訂 Header、受 allow_url_fopen 限制 | ★★☆☆☆ |
| fsockopen | 手工組裝 HTTP 請求 | 完全控制、無擴充套件依賴 | 程式碼複雜、需自行解析回應 | ★★☆☆☆ |
推薦實作:cURL HEAD 封裝函式
function urlExists($url, $timeout = 10) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_NOBODY => true, // HEAD 請求
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_FOLLOWLOCATION => true, // 跟隨重導向
CURLOPT_MAXREDIRS => 5,
CURLOPT_SSL_VERIFYPEER => false, // 生產請設 true 並配置 CA
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP Bot)',
]);
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 2xx、3xx 視為存在 (視業務需求)
return $result !== false && $httpCode >= 200 && $httpCode < 400;
}
// 使用
if (urlExists('https://example.com/image.jpg')) {
echo '圖片存在';
} else {
echo '圖片不存在或無法存取';
}
狀態碼判斷建議
- 200 OK:確定存在。
- 301/302/307/308:重導向,
CURLOPT_FOLLOWLOCATION 會自動追蹤最終狀態碼。
- 404 Not Found:不存在。
- 403 Forbidden:存在但無權存取,視業務決定是否視為「存在」。
- 5xx:伺服器錯誤,建議重試或視為暫時不可用。
效能優化
- 批次檢查時使用
curl_multi_* 並發請求。
- 結果快取 (Redis) 避免重複檢查同一 URL。
- 設定合理
CURLOPT_TIMEOUT 避免卡死。