傳統 cURL 處理 Cookie 需指定 CURLOPT_COOKIEJAR 和 CURLOPT_COOKIEFILE 指向實體檔案,涉及兩次磁碟 I/O(寫入讀取),效能較差且不利於無狀態部署環境(如 Serverless、容器化)。
啟用 CURLOPT_HEADER 獲取原始回應,手動分離 Header 與 Body,用正則提取 Set-Cookie 欄位,後續請求直接帶入 CURLOPT_COOKIE 參數。
// 1. 初始化 cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
// 2. 關鍵設定:獲取完整 Header、回傳原始字串
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 3. 執行請求
$content = curl_exec($ch);
curl_close($ch);
// 4. 解析 HTTP 回應:分離 Header 與 Body
list($header, $body) = explode("\r\n\r\n", $content, 2);
// 5. 正則提取 Set-Cookie(支援多組 Cookie)
preg_match_all("/set\-cookie:\s*([^\r\n]*)/i", $header, $matches);
// 6. 組裝 Cookie 字串供下次請求使用
$cookies = array();
foreach ($matches[1] as $cookie) {
// 僅取 name=value 部分,捨棄 path、domain、expires 等屬性
$pair = explode(';', $cookie)[0];
$cookies[] = trim($pair);
}
$cookieString = implode('; ', $cookies);
// 7. 後續請求直接帶入
// curl_setopt($ch, CURLOPT_COOKIE, $cookieString);
class CurlCookieJar {
private $cookies = array();
public function extractFromHeader($header) {
preg_match_all("/set\-cookie:\s*([^\r\n]*)/i", $header, $matches);
foreach ($matches[1] as $raw) {
$parts = explode(';', $raw);
$nameVal = trim($parts[0]);
if (strpos($nameVal, '=') !== false) {
list($name, $value) = explode('=', $nameVal, 2);
$this->cookies[$name] = $value;
}
}
}
public function getCookieString() {
$pairs = array();
foreach ($this->cookies as $name => $value) {
$pairs[] = "$name=$value";
}
return implode('; ', $pairs);
}
public function clear() { $this->cookies = array(); }
}
// 使用範例
$jar = new CurlCookieJar();
$ch = curl_init($loginUrl);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $loginData);
$resp = curl_exec($ch);
$jar->extractFromHeader($resp);
// 後續請求
$ch2 = curl_init($apiUrl);
curl_setopt($ch2, CURLOPT_COOKIE, $jar->getCookieString());
// ...
| 維度 | 檔案模式 | 記憶體模式 |
|---|---|---|
| I/O 操作 | 2 次磁碟讀寫 | 零磁碟 I/O |
| 效能 | 較慢 | 極快 |
| 持久化 | 自動跨程序 | 需自行序列化儲存 |
| 並發安全 | 需檔案鎖 | 天然隔離 |
| 適用場景 | 長期會話、CLI 常駐 | 短鏈路 API 串接、Serverless |
$jar->getCookieString() 存入 Redis/資料庫CURLOPT_SSL_VERIFYPEER 正確設定此技巧在 API 串接、第三方登入、爬蟲登入維持會話等場景極為實用,建議封裝為工具類複用。