長時間運行的 PHP CLI 腳本(如爬蟲、資料同步)使用 cURL 透過 HTTP Proxy 存取 HTTPS 網站時,記憶體使用量持續增長,top 觀察到 RSS 不斷上升,但 memory_get_usage() 回報正常。重啟腳本後記憶體釋放,確認為 cURL 底層洩漏。
cURL 在處理 HTTPS over HTTP Proxy 時,若未啟用 CURLOPT_HTTPPROXYTUNNEL,預設使用 HTTP CONNECT 建立隧道,但某些版本的 libcurl/OpenSSL 在重複建立 TLS 連線時,未正確釋放 SSL_CTX 或連線緩衝區,導致底層 C 堆疊記憶體洩漏。PHP 的記憶體管理器無法追蹤此類洩漏。
$ch = curl_init();
$options = [
CURLOPT_URL => 'https://www.google.com/search?q=test',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 30,
// === 關鍵三項 ===
CURLOPT_HTTPPROXYTUNNEL => true, // 1. 強制使用 HTTP CONNECT 隧道
CURLOPT_SSL_VERIFYPEER => false, // 2. 跳過憑證驗證(測試環境;生產請配合 CA Bundle)
CURLOPT_SSL_VERIFYHOST => false, // 3. 跳過主機名驗證(同上)
// Proxy 設定(視環境調整)
CURLOPT_PROXY => 'https://127.0.0.1:8118', // Privoxy 預設
CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
];
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
curl_close($ch);
| 選項 | 值 | 作用 |
|---|---|---|
CURLOPT_HTTPPROXYTUNNEL | true | 強制 cURL 向 Proxy 發送 CONNECT 指令建立 TCP 隧道,Proxy 僅轉發加密資料流,不解析 HTTP 標頭。避免 Proxy 層級的緩衝/重寫導致的洩漏。 |
CURLOPT_SSL_VERIFYPEER | false | 跳過伺服器憑證鏈驗證。生產環境請設為 true 並指定 CURLOPT_CAINFO。 |
CURLOPT_SSL_VERIFYHOST | false (或 0) | 跳過憑證 CN/SAN 與主機名比對。生產環境請設為 2。 |
// 生產環境:嚴格驗證 + 指定 CA Bundle
curl_setopt_array($ch, [
CURLOPT_HTTPPROXYTUNNEL => true,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CAINFO => '/etc/ssl/certs/ca-certificates.crt', // Debian/Ubuntu
// CURLOPT_CAPATH => '/etc/ssl/certs', // 或指定目錄
CURLOPT_PROXY => 'https://proxy.example.com:3128',
CURLOPT_PROXYUSERPWD => 'user:pass', // 若 Proxy 需認證
]);
# 1. 撰寫測試腳本 loop_curl.php,迴圈 1000 次請求 # 2. 監控記憶體 watch -n 1 'ps -o pid,rss,cmd -p $(pgrep -f loop_curl.php)' # 3. 對比修正前後 RSS 增長趨勢 # 修正前:RSS 持續線性增長 # 修正後:RSS 穩定在固定區間(±幾 MB)
curl_multi_* 非阻塞介面時,同樣需在每個 handle 設定上述三項選項。CURLSHOPT_SSL_SESSION_CACHE 可重用 SSL Session,減少握手開銷與洩漏風險:$sh = curl_share_init(); curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); curl_setopt($ch, CURLOPT_SHARE, $sh);
CURLOPT_HTTPPROXYTUNNEL,建議升級系統套件:yum update curl libcurl 或 apt upgrade libcurl4。正確配置 cURL Proxy 與 SSL 選項,能徹底解決長期運行 HTTPS 請求的記憶體洩漏問題,確保爬蟲、同步任務穩定執行。