在監控網站可用性、檢查連結有效性、實作爬蟲預檢等場景,我們往往只需要知道目標 URL 回應的 HTTP 狀態碼(如 200、301、404、500),而不需要下載完整 HTML 內容,以節省頻寬與時間。本文介紹使用 PHP cURL 發送 HEAD 請求(或設定 CURLOPT_NOBODY)僅取得回應標頭並解析狀態碼的標準做法。
<?php
/**
* 僅取得 HTTP 狀態碼,不下載 Body
* @param string $url 目標網址
* @return int|false 狀態碼,失敗回傳 false
*/
function GetHttpStatusCode($url) {
$curl = curl_init();
// 1. 設定目標 URL
curl_setopt($curl, CURLOPT_URL, $url);
// 2. 只取標頭,不取 Body(關鍵)
curl_setopt($curl, CURLOPT_NOBODY, true); // 相當於發送 HEAD 請求
curl_setopt($curl, CURLOPT_HEADER, true); // 將回應標頭包含在輸出中(配合 RETURNTRANSFER)
// 3. 回傳字串而非直接輸出
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// 4. 設定超時(秒),避免卡住
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
// 5. 自動追蹤重導向(可選,視需求決定是否開啟)
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_MAXREDIRS, 5);
// 6. 執行請求
$response = curl_exec($curl);
// 7. 取得 HTTP 狀態碼
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// 8. 錯誤處理
if ($response === false) {
$errNo = curl_errno($curl);
$errMsg = curl_error($curl);
error_log("cURL error ($errNo): $errMsg for URL: $url");
curl_close($curl);
return false;
}
curl_close($curl);
return (int)$httpCode;
}
// 使用範例
$url = "https://www.example.com";
$code = GetHttpStatusCode($url);
if ($code !== false) {
echo "HTTP Status: $code"; // 正常輸出 200
} else {
echo "請求失敗";
}
?>
| 選項 | 值 | 作用 |
|---|---|---|
| CURLOPT_NOBODY | true | 不下載 Body,發送 HEAD 請求(某些伺服器對 HEAD 支援不佳,若狀態碼異常可改用 CURLOPT_CUSTOMREQUEST => 'GET' 搭配 CURLOPT_NOBODY => true) |
| CURLOPT_HEADER | true | 將回應標頭包含在輸出字串中(配合 RETURNTRANSFER),方便除錯 |
| CURLOPT_RETURNTRANSFER | true | 回傳字串而非直接輸出 |
| CURLOPT_TIMEOUT | 10 | 連線+傳輸總超時秒數,防止卡死 |
| CURLOPT_FOLLOWLOCATION | true | 自動追蹤 3xx 重導向,最終取得終點狀態碼 |
| CURLOPT_MAXREDIRS | 5 | 最大重導向次數,防無限循環 |
| CURLOPT_SSL_VERIFYPEER | false | (開發環境)跳過 SSL 憑證驗證;生產環境請設 true 並配置 CA 憑證 |
| CURLOPT_USERAGENT | 'Mozilla/5.0...' | 模擬瀏覽器 UA,避免被簡單反爬攔截 |
部分伺服器不支援或禁止 HEAD。解法:改用 GET 但丟棄 Body:
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($curl, CURLOPT_NOBODY, true); // 仍不下載 Body
設定 CURLOPT_MAXREDIRS 並記錄 CURLINFO_REDIRECT_URL 追蹤路徑。
生產環境請下載 cacert.pem 並設定:
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_CAINFO, '/path/to/cacert.pem');
$info = curl_getinfo($curl);
// 可用鍵值:
// CURLINFO_HTTP_CODE // 回應碼
// CURLINFO_TOTAL_TIME // 總耗時(秒)
// CURLINFO_CONNECT_TIME // 連線耗時
// CURLINFO_NAMELOOKUP_TIME // DNS 解析耗時
// CURLINFO_REDIRECT_COUNT // 重導向次數
// CURLINFO_CONTENT_TYPE // Content-Type
class HttpStatusChecker {
private $timeout = 10;
private $followRedirects = true;
private $maxRedirects = 5;
private $userAgent = 'Mozilla/5.0 (compatible; HttpStatusChecker/1.0)';
public function __construct(array $options = []) {
foreach ($options as $k => $v) if (property_exists($this, $k)) $this->$k = $v;
}
public function getStatusCode(string $url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_NOBODY => true,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER=> true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_FOLLOWLOCATION=> $this->followRedirects,
CURLOPT_MAXREDIRS => $this->maxRedirects,
CURLOPT_USERAGENT => $this->userAgent,
CURLOPT_SSL_VERIFYPEER=> true, // 生產環境建議開啟
]);
$resp = curl_exec($ch);
$code = ($resp !== false) ? (int)curl_getinfo($ch, CURLINFO_HTTP_CODE) : false;
curl_close($ch);
return $code;
}
public function checkBatch(array $urls, callable $callback = null) {
$results = [];
foreach ($urls as $url) {
$code = $this->getStatusCode($url);
$results[$url] = $code;
if ($callback) $callback($url, $code);
}
return $results;
}
}
// 使用
$checker = new HttpStatusChecker(['timeout' => 5]);
echo $checker->getStatusCode('https://www.google.com'); // 200
實測對同一目標(首頁約 200 KB HTML):
大量連結檢查時,HEAD 模式可節省 70%+ 時間與頻寬。
使用 CURLOPT_NOBODY => true 搭配 curl_getinfo($ch, CURLINFO_HTTP_CODE) 是 PHP 中最高效、最標準的「只取狀態碼」做法。配合合理的超時、重導向控制、SSL 驗證與 User-Agent 設定,即可構建穩健的連結監控、死連結檢測、爬蟲預檢等系統。記住:生產環境務必開啟 SSL 驗證並妥善處理錯誤日誌。