在開發網頁採集器專案時,我深刻體會到 file_get_contents 的局限性。雖然它語法簡潔、調用便捷,但面對複雜的網絡請求場景時顯得力不從心。相比之下,cURL 雖然參數較多、學習曲線稍陡,但功能強大得多,幾乎是 PHP 進行網絡通訊的「瑞士軍刀」。
| 特性 | file_get_contents | cURL |
|---|---|---|
| 支持協議 | HTTP/HTTPS/FTP (受限於 allow_url_fopen) | HTTP/HTTPS/FTP/FTPS/GOPHER/TELNET/DICT/FILE/LDAP 等 |
| 請求控制 | 極難精細控制 Header、Cookie、Referer 等 | 完整支持自定義 Header、Cookie 管理、Referer 偽裝 |
| 認證機制 | 基礎 HTTP 認證 | Basic/Digest/NTLM/OAuth 等多種認證 |
| 代理支持 | 不支持 | HTTP/SOCKS4/SOCKS5 代理,含認證 |
| 斷點續傳 | 不支持 | 原生支持 Range 請求與斷點續傳 |
| 並發請求 | 串行阻塞 | 支持 curl_multi 並發非阻塞 |
| SSL/TLS 控制 | 極其有限 | 證書驗證、客戶端證書、密鑰對、Cipher 套件全可控 |
| 重定向策略 | 自動跟隨,不可控 | 可自定義最大重定向次數、是否跟隨、Header 轉發策略 |
| 超時控制 | 受 default_socket_timeout 影響 | 連接超時、執行超時、DNS 緩存超時獨立可控 |
| 錯誤處理 | 僅返回 false,錯誤資訊獲取困難 | curl_errno/curl_error 提供詳細錯誤碼與描述 |
PHP 預設未啟用 cURL 擴展,需修改 php.ini:
; 去掉前面的分號 extension=php_curl.dll ; Windows 下可能還需將 libeay32.dll、ssleay32.dll 複製到系統路徑
修改後重啟 Apache/IIS 或 php-fpm 使其生效。
<?php
// 1. 初始化 cURL 句柄
$ch = curl_init();
// 2. 設定目標 URL
curl_setopt($ch, CURLOPT_URL, 'https://api.example.com/data');
// 3. 核心選項:將回傳內容作為字串返回,而非直接輸出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 4. 常用選項:設定 User-Agent、超時、SSL 驗證
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MyBot/1.0)');
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 執行超時 10 秒
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 連接超時 5 秒
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 開發環境暫時關閉 SSL 驗證
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
// 5. 執行請求
$response = curl_exec($ch);
// 6. 錯誤檢查
if ($response === false) {
$errno = curl_errno($ch);
$error = curl_error($ch);
error_log("cURL Error [$errno]: $error");
} else {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 處理 $response...
}
// 7. 關閉句柄,釋放資源
curl_close($ch);
?>
// 啟用 Cookie 檔案持久化 $cookieFile = sys_get_temp_dir() . '/cookie_' . md5($url) . '.txt'; curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile); // 寫入 Cookie curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); // 讀取 Cookie curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 自動跟隨重定向
$postData = ['username' => 'user', 'password' => 'pass'];
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
// 或發送 JSON
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
// 或上傳檔案 (PHP 5.5+ 使用 CURLFile)
curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => new CURLFile('/path/to/file')]);
$fp = fopen('large_file.zip', 'ab'); // 追加模式
$fileSize = filesize('large_file.zip');
curl_setopt($ch, CURLOPT_RANGE, $fileSize . '-'); // 從斷點續傳
curl_setopt($ch, CURLOPT_FILE, $fp); // 直接寫入檔案句柄
curl_exec($ch);
fclose($fp);
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_multi_add_handle($mh, $ch);
$handles[$i] = $ch;
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh); // 等待活動
} while ($running > 0);
foreach ($handles as $i => $ch) {
$results[$i] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
cURL 以擴展形式運行,底層使用 libcurl 庫,相比用戶態流封裝的 file_get_contents,在長連接復用、DNS 緩存、SSL 會話復用等方面效能優勢明顯。對於高併發採集場景,建議搭配 curl_multi 或 Swoole 協程化 cURL 使用。
file_get_contents 足矣,代碼更乾淨。