cURL 基礎流程
<?php
// 1. 初始化
$ch = curl_init();
// 2. 設定選項
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.example.com/endpoint',
CURLOPT_RETURNTRANSFER => true, // 回傳字串而非直接輸出
CURLOPT_POST => true, // POST 請求
CURLOPT_POSTFIELDS => http_build_query(['key' => 'value']), // 表單資料
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
'Authorization: Bearer ' . $token,
],
CURLOPT_TIMEOUT => 30, // 總超時秒數
CURLOPT_CONNECTTIMEOUT => 10, // 連線超時秒數
CURLOPT_SSL_VERIFYPEER => true, // 驗證 SSL 憑證
CURLOPT_FOLLOWLOCATION => true, // 支援重導向
CURLOPT_MAXREDIRS => 5, // 最大重導向次數
]);
// 3. 執行
$response = curl_exec($ch);
// 4. 錯誤檢查
if ($response === false) {
$errorNo = curl_errno($ch);
$errorMsg = curl_error($ch);
throw new Exception("cURL 錯誤 ($errorNo): $errorMsg");
}
// 5. 取得 HTTP 狀態碼
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 6. 關閉
curl_close($ch);
// 7. 處理回應
$data = json_decode($response, true);
常用選項分類速查
| 類別 | 選項 | 說明 |
| URL/請求 | CURLOPT_URL | 請求網址 |
CURLOPT_CUSTOMREQUEST | 自訂 HTTP 方法 (GET/POST/PUT/DELETE/PATCH) |
CURLOPT_POST | 是否 POST |
CURLOPT_POSTFIELDS | POST 資料 (陣列=multipart, 字串=urlencoded) |
| 標頭 | CURLOPT_HTTPHEADER | 請求標頭陣列 |
CURLOPT_USERAGENT | User-Agent 字串 |
CURLOPT_REFERER | Referer 標頭 |
CURLOPT_COOKIE | Cookie 字串 |
| 回應處理 | CURLOPT_RETURNTRANSFER | 回傳字串 (必設 true) |
CURLOPT_HEADER | 包含回應標頭在輸出中 |
CURLOPT_WRITEFUNCTION | 自訂寫入回呼 (流式處理大檔案) |
CURLOPT_FILE | 直接寫入檔案資源 |
| SSL/安全 | CURLOPT_SSL_VERIFYPEER | 驗證對方憑證 (生產必開 true) |
CURLOPT_SSL_VERIFYHOST | 驗證 CN (2=嚴格) |
CURLOPT_CAINFO | CA 憑證束路徑 |
CURLOPT_SSLCERT | 客戶端憑證 (.pem) |
| 超時/限制 | CURLOPT_TIMEOUT | 總超時 (秒) |
CURLOPT_CONNECTTIMEOUT | 連線超時 (秒) |
CURLOPT_LOW_SPEED_LIMIT | 低速門檻 (bytes/sec) |
CURLOPT_LOW_SPEED_TIME | 低速持續秒數才中斷 |
| 代理/連線 | CURLOPT_PROXY | 代理伺服器 |
CURLOPT_PROXYUSERPWD | 代理認證 |
CURLOPT_INTERFACE | 指定網卡 IP |
進階實戰場景
1. JSON API 請求
<?php
$payload = json_encode(['user_id' => 123, 'action' => 'purchase']);
$ch = curl_init('https://api.example.com/order');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: ' . strlen($payload),
'Authorization: Bearer ' . $accessToken,
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
2. 檔案上傳
<?php
$filePath = '/path/to/image.jpg';
$postFields = [
'file' => new CURLFile($filePath, 'image/jpeg', 'image.jpg'), // PHP 5.5+
'user_id' => 123,
];
$ch = curl_init('https://api.example.com/upload');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postFields,
CURLOPT_RETURNTRANSFER => true,
]);
3. 斷點續傳下載大檔案
<?php
$url = 'https://example.com/large-file.zip';
$savePath = '/data/large-file.zip';
$fp = fopen($savePath, 'ab'); // 追加模式
$downloaded = filesize($savePath) ?: 0;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RANGE => "$downloaded-", // 從已下載位置繼續
CURLOPT_FILE => $fp,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 0, // 不限制總時間
]);
curl_exec($ch);
fclose($fp);
4. 並發請求
<?php
$urls = [
'https://api1.example.com/data',
'https://api2.example.com/data',
'https://api3.example.com/data',
];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
curl_multi_add_handle($mh, $ch);
$handles[$i] = $ch;
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh, 0.5); // 等待活動
} while ($running > 0);
$results = [];
foreach ($handles as $i => $ch) {
$results[$i] = [
'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
'body' => curl_multi_getcontent($ch),
'error' => curl_error($ch),
];
curl_multi_remove_handle($mh, $ch);
}
curl_multi_close($mh);
5. 自動處理 Cookie(模擬登入)
<?php
$cookieJar = '/tmp/cookies.txt';
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_COOKIEJAR => $cookieJar, // 儲存回應 Cookie
CURLOPT_COOKIEFILE => $cookieJar, // 發送儲存的 Cookie
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
]);
// 1. 登入
curl_setopt($ch, CURLOPT_URL, 'https://example.com/login');
curl_setopt($ch, CURLOPT_POSTFIELDS, ['user' => 'xxx', 'pass' => 'yyy']);
curl_exec($ch);
// 2. 存取需登入頁面 (自動攜帶 Cookie)
curl_setopt($ch, CURLOPT_URL, 'https://example.com/dashboard');
$dashboard = curl_exec($ch);
錯誤碼對照表
| 代碼 | 常數 | 說明 |
| 6 | CURLE_COULDNT_RESOLVE_HOST | DNS 解析失敗 |
| 7 | CURLE_COULDNT_CONNECT | 無法連線到主機 |
| 28 | CURLE_OPERATION_TIMEDOUT | 操作逾時 |
| 35 | CURLE_SSL_CONNECT_ERROR | SSL 連線錯誤 |
| 51 | CURLE_SSL_PEER_CERTIFICATE | 對方憑證驗證失敗 |
| 60 | CURLE_SSL_CACERT | CA 憑證驗證失敗 |
| 22 | CURLE_HTTP_RETURNED_ERROR | HTTP 狀態碼 >= 400 (需配合 CURLOPT_FAILONERROR) |
最佳實踐檢查清單
- ✅ 生產環境 啟用 SSL 驗證 (CURLOPT_SSL_VERIFYPEER = true)
- ✅ 設定 合理超時 (連線 5-10s,總計 30-60s)
- ✅ 檢查 HTTP 狀態碼 而非只看回應內容
- ✅ 使用
http_build_query 編碼表單資料,避免手工拼接
- ✅ 大檔案使用
CURLOPT_FILE 或 CURLOPT_WRITEFUNCTION 避免記憶體暴增
- ✅ 重試機制:指數退避 + 最大重試次數 (針對 5xx、網路錯誤)
- ✅ 記錄請求/回應日誌 (含耗時、狀態碼、錯誤) 利於除錯
- ✅ 敏感資訊 (Token、密鑰) 不寫入日誌