PHP 中發送 HTTP POST 請求主要有三種原生方式:cURL 擴展、stream_context + file_get_contents、fsockopen 底層 Socket。本文將逐一解析原理、程式碼範例、優缺點與適用場景,助你選擇最適合的方案。
cURL 功能最完整、效能最好、支援 HTTPS/HTTP2/代理/憑證驗證等進階特性,是生產環境首選。
function postCurl(string $url, array $data, int $timeout = 10): string {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data), // 自動 application/x-www-form-urlencoded
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => true, // 生產環境請保持 true
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HTTPHEADER => ['Expect:'], // 避免大資料觸發 100-continue
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException('cURL error: ' . curl_error($ch));
}
curl_close($ch);
return $response;
}
優點:功能豐富、效能高、錯誤處理完善、支援並發(curl_multi)。
缺點:需安裝擴展(現代 PHP 環境通常內建)。
利用 PHP 內建 HTTP stream wrapper,無需額外擴展,適合簡單 GET/POST、受限環境。
function postStream(string $url, array $data, int $timeout = 10): string {
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded\r\n' .
'Connection: close\r\n',
'content' => http_build_query($data),
'timeout' => $timeout,
'ignore_errors' => true, // 取得非 2xx 回應內容
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
],
]);
$response = @file_get_contents($url, false, $context);
if ($response === false) {
$error = error_get_last();
throw new RuntimeException('Stream POST failed: ' . ($error['message'] ?? 'Unknown'));
}
return $response;
}
優點:零依賴、程式碼簡潔、記憶體效率佳(流式讀取)。
缺點:不支援並發、重導向處理較弱、大檔上傳不便、錯誤訊息較不明確。
手動組裝 HTTP 協定封包,適合學習 HTTP 協定、極度受限環境、或需精確控制原始封包(如測試伺服器行為)。
function postSocket(string $host, string $path, array $data, int $port = 80, int $timeout = 10): string {
$query = http_build_query($data);
$request = "POST $path HTTP/1.1\r\n"
. "Host: $host\r\n"
. "Content-Type: application/x-www-form-urlencoded\r\n"
. "Content-Length: " . strlen($query) . "\r\n"
. "Connection: close\r\n\r\n"
. $query;
$fp = @fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$fp) {
throw new RuntimeException("Socket connect failed: $errstr ($errno)");
}
stream_set_timeout($fp, $timeout);
fwrite($fp, $request);
$response = '';
while (!feof($fp)) {
$response .= fread($fp, 8192);
}
fclose($fp);
// 簡易移除 HTTP 標頭
list($header, $body) = explode("\r\n\r\n", $response, 2);
return $body ?? '';
}
優點:完全控制封包、無任何擴展依賴、可實作自訂協定。
缺點:需手動處理 HTTPS(需 ssl:// 協定 + 憑證驗證)、Chunked 編碼、重導向、Keep-Alive 等複雜細節,極易出錯,不建議生產環境直接使用。
| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 一般 API 串接、生產環境 | cURL | 功能完整、效能佳、錯誤處理完善 |
| 簡單請求、無法安裝擴展、共享主機 | stream_context | 零依賴、語法簡潔 |
| HTTP 協定教學、除錯原始封包、特殊協定 | fsockopen | 完全控制、學習價值高 |
| 高併發、大量並行請求 | cURL (curl_multi) | 原生非阻塞多工 |
| 大檔案上傳/下載、串流處理 | cURL / stream | 支援串流、記憶體友善 |
CURLOPT_SSL_VERIFYPEER => true 並提供 CA 憑證(CURLOPT_CAINFO),stream_context 同理設定 ssl.verify_peer。Content-Type 改為 application/json,資料用 json_encode($data)。guzzlehttp/guzzle 內建),提升穩定性。理解三種底層方式的原理與取捨,能讓你在受限環境、效能調優、協定除錯等場景遊刃有餘。日常開發請優先選用成熟 HTTP Client 套件,專注於業務邏輯而非輪子細節。