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

PHP cURL 封裝類完整實戰:從基礎配置到多實例架構的兩種設計模式

     編輯:PHP 相關知識

cURL 是 PHP 處理 HTTP 請求的核心擴充,封裝為可復用類別能統一錯誤處理、超時控制、Cookie 管理、Header 構建。本文提供兩種成熟封裝架構:選項陣列注入模式與鏈式方法模式,涵蓋 GET/POST/PUT、SSL、代理、偽造 IP 等實戰場景。

前置環境檢查

# php.ini 啟用
extension=curl

# 依賴庫(Windows 需放入 System32)
libeay32.dll, ssleay32.dll, php_curl.dll

架構一:選項陣列注入模式(彈性最大)

<?php
class CurlClient {
    public string $cookieFile;
    public int $timeout = 160;

    public function __construct(string $cookieDir = '') {
        $this->cookieFile = $cookieDir 
            ? sys_get_temp_dir() . '/curl_cookie_' . md5($cookieDir) . '.txt'
            : tempnam(sys_get_temp_dir(), 'curl_cookie_');
    }

    /**
     * 發送請求並回傳回應內容
     * @param array $options CURLOPT_* 常數鍵值陣列
     * @return string|false 成功回傳字串,失敗回傳 false
     */
    public function request(array $options): string|false {
        // 1. 強制啟用回傳字串
        $options[CURLOPT_RETURNTRANSFER] = true;

        // 2. 自動處理 Cookie 持久化
        if (!isset($options[CURLOPT_COOKIEFILE])) {
            $options[CURLOPT_COOKIEFILE] = $this->cookieFile;
            $options[CURLOPT_COOKIEJAR]  = $this->cookieFile;
        }

        $ch = curl_init();
        curl_setopt_array($ch, $options);

        try {
            $response = curl_exec($ch);
            if ($response === false) {
                throw new \Exception(curl_error($ch), curl_errno($ch));
            }
            return $response;
        } catch (\Exception $e) {
            error_log('[CurlClient] ' . $e->getMessage());
            return false;
        } finally {
            curl_close($ch);
        }
    }

    // Unicode 轉 UTF-8 工具方法
    public static function unicodeToUtf8(string $str): string {
        $str = str_replace('\\u', '', strtolower($str));
        $out = '';
        for ($i = 0, $len = strlen($str); $i < $len; $i += 4) {
            $hex = substr($str, $i, 4);
            $code = hexdec($hex);
            if ($code < 128) $out .= chr($code);
            elseif ($code < 2048) $out .= chr(192 | ($code >> 6)) . chr(128 | ($code & 63));
            else $out .= chr(224 | ($code >> 12)) . chr(128 | (($code >> 6) & 63)) . chr(128 | ($code & 63));
        }
        return $out;
    }
}

// === 使用範例:POST 請求偽造 Header 與 IP ===
$client = new CurlClient();
$options = [
    CURLOPT_URL            => 'https://api.example.com/ticket',
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => 'ids=897&Submit=%E6%8A%95%E7%A5%A8',
    CURLOPT_HTTPHEADER     => [
        'X-FORWARDED-FOR: 139.197.14.19',
        'CLIENT-IP: 127.0.0.1',
        'Proxy-Client-IP: 139.197.14.19',
        'WL-Proxy-Client-IP: 139.197.14.19',
    ],
    CURLOPT_REFERER        => 'https://www.example.com/referer',
    CURLOPT_HEADER         => true,      // 回傳包含 Header
    CURLOPT_TIMEOUT        => $client->timeout,
    CURLOPT_SSL_VERIFYPEER => false,     // 僅測試環境關閉驗證
];
$response = $client->request($options);
if ($response !== false) {
    echo $response;
}
?>

架構二:鏈式方法模式(語意清晰、適合簡單場景)

<?php
class SimpleCurl {
    private $ch;
    private array $headers = [];
    private array $postFields = [];
    private string $method = 'GET';
    private int $timeout = 10;

    public function __construct() {
        $this->ch = curl_init();
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->ch, CURLOPT_HEADER, false);
        curl_setopt($this->ch, CURLOPT_TIMEOUT, $this->timeout);
    }

    public function url(string $url): self {
        curl_setopt($this->ch, CURLOPT_URL, $url);
        return $this;
    }

    public function method(string $method): self {
        $this->method = strtoupper($method);
        return $this;
    }

    public function header(string $key, string $value): self {
        $this->headers[] = "$key: $value";
        return $this;
    }

    public function headers(array $headers): self {
        foreach ($headers as $k => $v) $this->header($k, $v);
        return $this;
    }

    public function data(array|string $data): self {
        if (is_array($data)) {
            $data = http_build_query($data);
        }
        $this->postFields = $data;
        if ($this->method === 'POST') {
            curl_setopt($this->ch, CURLOPT_POST, true);
            curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
        }
        return $this;
    }

    public function timeout(int $seconds): self {
        curl_setopt($this->ch, CURLOPT_TIMEOUT, $seconds);
        return $this;
    }

    public function exec(): string|false {
        if ($this->headers) {
            curl_setopt($this->ch, CURLOPT_HTTPHEADER, $this->headers);
        }
        $response = curl_exec($this->ch);
        if ($response === false) {
            error_log('[SimpleCurl] ' . curl_error($this->ch));
            return false;
        }
        return $response;
    }

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

// === 使用範例 ===
$curl = new SimpleCurl();
$response = $curl->url('https://api.example.com/users')
    ->method('POST')
    ->header('Authorization', 'Bearer token123')
    ->header('Content-Type', 'application/json')
    ->data(['name' => 'John', 'email' => 'john@example.com'])
    ->timeout(15)
    ->exec();

if ($response) {
    $data = json_decode($response, true);
    print_r($data);
}
?>

核心 CURLOPT 選項速查表

常數用途典型值
CURLOPT_URL請求網址字串
CURLOPT_RETURNTRANSFER回傳字串而非直接輸出true
CURLOPT_POST啟用 POSTtrue
CURLOPT_POSTFIELDSPOST 資料字串或陣列(自動 multipart/form-data)
CURLOPT_HTTPHEADER自訂 Header['Key: Value', ...]
CURLOPT_COOKIEFILE/JARCookie 讀寫檔案檔案路徑
CURLOPT_SSL_VERIFYPEER驗證 SSL 憑證false (測試) / true (生產)
CURLOPT_TIMEOUT最大執行秒數整數
CURLOPT_PROXY代理伺服器'ip:port'
CURLOPT_USERAGENT偽造 UA字串

常見問題排查

  • SSL 憑證驗證失敗:生產環境必須 CURLOPT_SSL_VERIFYPEER => true 並配合 CURLOPT_CAINFO 指定 CA 憑證包。
  • 中文亂碼:確保請求 Header 含 Content-Type: application/x-www-form-urlencoded; charset=utf-8,回應以 mb_convert_encoding() 處理。
  • 大檔案上傳:使用 CURLOPT_INFILE + CURLOPT_UPLOAD 流式傳輸,避免記憶體爆炸。
  • 並發請求:使用 curl_multi_* 系列函式或 GuzzleHttp 等成熟庫。

架構選型建議

  • 選項陣列模式:需精細控制每個 CURLOPT、整合既有陣列配置、遷移舊代碼。
  • 鏈式方法模式:新專案、團隊偏好流暢介面、常用參數固定化。
  • 企業級專案:建議直接採用 GuzzleHttp,支援 PSR-18、中介軟體、非同步、測試雙工等現代化特性。

封裝 cURL 類別能將 HTTP 通訊細節內聚,業務代碼專注於參數組裝與回應解析,是 PHP 後端開發的基礎設施建設核心環節。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved