首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP cURL 無檔案儲存 Cookie 實戰:記憶體中提取與攜帶 Session ID

     編輯:PHP 相關知識

傳統方式:COOKIEJAR/COOKIEFILE(磁碟 I/O)

$cookieFile = tempnam('/tmp', 'cookie');
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile);  // 寫入
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); // 讀取
// 缺點:兩次 I/O、雲平台(BAE/SAE)無本地寫入權限、併發需加鎖

無檔案方案:手動解析 Set-Cookie Header

步驟 1:登入請求,開啟 CURLOPT_HEADER 獲取原始回應

$ch = curl_init('https://example.com/login');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => 'user=admin&pass=123456',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HEADER         => true, // 關鍵:將 Header 包含在返回字串
    CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);

步驟 2:正則提取 Set-Cookie(支援多 Cookie、屬性)

// 匹配所有 Set-Cookie 行,取值部分(分號前)
preg_match_all('/^Set-Cookie:\s*([^;]+)/mi', $response, $matches);
$cookies = $matches[1] ?? []; // 陣列:['PHPSESSID=abc123', 'csrf_token=xyz', ...]

// 組合為 Cookie Header 字串
$cookieHeader = implode('; ', $cookies); // "PHPSESSID=abc123; csrf_token=xyz"
curl_close($ch);

步驟 3:後續請求攜帶 Cookie

$ch2 = curl_init('https://example.com/api/data');
curl_setopt_array($ch2, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIE         => $cookieHeader, // 直接送出 Cookie Header
    CURLOPT_SSL_VERIFYPEER => true,
]);
$data = curl_exec($ch2);
curl_close($ch2);

封裝為可重用類(支援自動更新 Cookie)

class CurlCookieHandler {
    private $cookieHeader = '';
    private $ch;

    public function __construct() {
        $this->ch = curl_init();
        curl_setopt_array($this->ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HEADER         => true, // 永遠開啟以捕獲新 Cookie
        ]);
    }

    public function exec(string $url, array $post = []): string {
        curl_setopt($this->ch, CURLOPT_URL, $url);
        if ($post) {
            curl_setopt($this->ch, CURLOPT_POST, true);
            curl_setopt($this->ch, CURLOPT_POSTFIELDS, http_build_query($post));
        } else {
            curl_setopt($this->ch, CURLOPT_POST, false);
        }
        // 攜帶現有 Cookie
        if ($this->cookieHeader) {
            curl_setopt($this->ch, CURLOPT_COOKIE, $this->cookieHeader);
        }

        $response = curl_exec($this->ch);
        if (curl_errno($this->ch)) {
            throw new \RuntimeException(curl_error($this->ch));
        }

        // 更新 Cookie(合併新舊,新的覆蓋同名)
        $this->updateCookies($response);
        return substr($response, curl_getinfo($this->ch, CURLINFO_HEADER_SIZE));
    }

    private function updateCookies(string $response): void {
        preg_match_all('/^Set-Cookie:\s*([^;]+)/mi', $response, $m);
        foreach ($m[1] as $cookie) {
            [$name] = explode('=', $cookie, 2);
            // 移除舊同名
            $this->cookieHeader = preg_replace(
                '/(^|;\s*)' . preg_quote($name, '/') . '=[^;]*(;\s*|$)/',
                '$1', $this->cookieHeader
            );
            // 附加新
            $this->cookieHeader .= ($this->cookieHeader ? '; ' : '') . $cookie;
        }
    }

    public function __destruct() {
        curl_close($this->ch);
    }
}

// 使用
$client = new CurlCookieHandler();
$html = $client->exec('https://example.com/login', ['user'=>'a','pass'=>'b']);
$json = $client->exec('https://example.com/api/user'); // 自動攜帶登入 Cookie

注意事項與限制

  • HttpOnly Cookie:JavaScript 無法讀取,但 cURL 可正常收發,無影響。
  • Secure / SameSite:僅影響瀏覽器行為,cURL 忽略。
  • 多域名:若跨域名需維護多組 Cookie,類中改用 `array $cookies[domain] => header`。
  • 效能:省去磁碟 I/O,適合高併發、Serverless、容器環境。
  • 完整性:此法僅處理 `Set-Cookie`,若需支援 `Cookie2`、RFC 2965 等舊標準,建議改用 `GuzzleHttp\Cookie\CookieJar`。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved