這個函數利用 PHP 內建的 stream_context_create() 與 fopen() 實現 HTTP POST 請求,無需依賴 cURL 擴展,適合簡單場景或受限環境。
/**
* 發送 HTTP POST 請求
*
* @param string $url 目標 URL
* @param string $data 已編碼的 POST 資料(application/x-www-form-urlencoded 格式)
* @param string|null $optional_headers 額外 HTTP 標頭,如 "Content-Type: application/json\r\nAuthorization: Bearer xxx"
* @return string|false 回應內容,失敗拋出 Exception
* @throws Exception 連線或讀取失敗時拋出
*/
function do_post_request($url, $data, $optional_headers = null) {
// 建立 stream context 選項
$params = [
'http' => [
'method' => 'POST',
'content' => $data,
]
];
// 註入自訂標頭
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
// 建立 context 並開啟串流
$ctx = stream_context_create($params);
$fp = @fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("無法連線至 $url: " . $php_errormsg);
}
// 讀取回應
$response = @stream_get_contents($fp);
fclose($fp);
if ($response === false) {
throw new Exception("從 $url 讀取資料失敗: " . $php_errormsg);
}
return $response;
}
注意:預設 Content-Type 為 application/x-www-form-urlencoded。若需發送 JSON,必須手動設定標頭並編碼資料。
// 1. 準備 JSON 字串
$json_payload = json_encode([
'user_id' => 12345,
'action' => 'update_profile',
'data' => ['nickname' => '新用戶', 'email' => 'user@example.com']
]);
// 2. 設定標頭:指定 Content-Type 為 JSON
$headers = "Content-Type: application/json\r\n";
$headers .= "Content-Length: " . strlen($json_payload) . "\r\n";
// 3. 發送請求
try {
$response = do_post_request('https://api.example.com/endpoint', $json_payload, $headers);
$result = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('回應非合法 JSON: ' . $response);
}
echo "API 回應: "; print_r($result);
} catch (Exception $e) {
error_log("POST 請求失敗: " . $e->getMessage());
echo "請求處理異常,請稍後再試。";
}
傳統表單提交格式(application/x-www-form-urlencoded)可直接使用 http_build_query() 編碼陣列:
$form_data = [
'username' => 'user123',
'password' => 'secret',
'remember' => 1
];
$post_data = http_build_query($form_data); // 自動 URL 編碼
$response = do_post_request('https://example.com/login', $post_data);
| 維度 | Stream Context (本函數) | cURL (curl_* 函數) | Guzzle / HTTP Client 套件 |
|---|---|---|---|
| 依賴需求 | 無(PHP 核心功能) | 需啟用 php_curl.dll/so | 需 Composer 安裝 |
| 功能豐富度 | 基礎(支援 POST、標頭、基本 SSL) | 完整(多協定、並發、代理、認證、進階 SSL) | 極豐富(中介軟體、重試、異步、PSR-7/18 相容) |
| 錯誤處理 | 需自行 try/catch | 需檢查 curl_errno/error | 拋出具體異常類別 |
| 適用場景 | 簡單請求、無 cURL 環境、輕量腳本 | 生產環境標準選擇、複雜互動 | 現代框架專案、微服務呼叫、長期維護專案 |
php.ini 已啟用 openssl 擴展,且 CA 憑證路徑正確(curl.cainfo 或 openssl.cafile)。'timeout' => 10(秒)於 $params['http'] 中。'follow_location' => 1(PHP 5.3.4+)並設定 'max_redirects' => 5。CURLOPT_INFILE 或分塊上傳。