在 API 串接、支付回調、服務間通訊等場景,PHP 後端常需主動向其他 URL 發送 POST 請求,而非透過瀏覽器表單。本文整理兩種最經典、無需表單的實作方式。
純 PHP 內建函數,無需額外擴展,適合不支援 cURL 的環境。
<?php
/**
* 使用 fsockopen 發送 POST 請求
* @param string $url 目標完整 URL(含 scheme、host、path、query)
* @param array $data 要發送的鍵值對陣列
* @return string|false 回應內容或失敗訊息
*/
function postToHost($url, $data) {
$parsed = parse_url($url);
if (!$parsed) return "無法解析 URL";
$host = $parsed['host'];
$port = $parsed['port'] ?? 80;
$path = $parsed['path'] ?? '/';
$query = $parsed['query'] ?? '';
$requestPath = $path . ($query ? "?$query" : '');
// 組裝 application/x-www-form-urlencoded 資料
$encoded = '';
foreach ($data as $k => $v) {
$encoded .= ($encoded ? '&' : '') . rawurlencode($k) . '=' . rawurlencode($v);
}
// 建立 Socket 連線
$fp = fsockopen($host, $port, $errno, $errstr, 10);
if (!$fp) return "無法連線至 $host: $errstr ($errno)";
// 發送 HTTP 請求頭
$request = "POST $requestPath HTTP/1.1\r\n";
$request .= "Host: $host\r\n";
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: " . strlen($encoded) . "\r\n";
$request .= "Connection: close\r\n\r\n";
$request .= $encoded;
fwrite($fp, $request);
// 讀取回應
$response = '';
$inHeader = true;
while (!feof($fp)) {
$line = fgets($fp, 1024);
if ($inHeader && ($line === "\n" || $line === "\r\n")) {
$inHeader = false;
continue;
}
if (!$inHeader) $response .= $line;
}
fclose($fp);
return $response;
}
// 使用範例
$result = postToHost('https://api.example.com/notify', [
'order_id' => '20240101001',
'amount' => '123.45',
'status' => 'paid'
]);
echo $result;
?>
cURL 功能更完整、支援 HTTPS、自動處理重導向、超時控制、憑證驗證等,是現代 PHP 專案的首選。
<?php
$url = 'https://api.example.com/notify';
$data = [
'order_id' => '20240101001',
'amount' => '123.45',
'status' => 'paid'
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data), // 自動編碼
CURLOPT_RETURNTRANSFER => true, // 回傳字串而非直接輸出
CURLOPT_TIMEOUT => 10, // 秒數超時
CURLOPT_SSL_VERIFYPEER => true, // 驗證 SSL 憑證(生產環境建議開啟)
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HTTPHEADER => [
'User-Agent: MyApp/1.0',
'Accept: application/json',
],
]);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
echo "cURL 錯誤: $error";
} else {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo "HTTP 狀態碼: $httpCode\n";
echo "回應內容: $response";
}
curl_close($ch);
?>
| 特性 | fsockopen | cURL |
|---|---|---|
| HTTPS 支援 | 需自行實作 SSL/TLS | 原生支援 |
| 重導向處理 | 手動解析 Location 標頭 | CURLOPT_FOLLOWLOCATION 自動 |
| 超時控制 | 僅連線階段 fsockopen 參數 | 完整 CURLOPT_TIMEOUT/CONNECTTIMEOUT |
| 錯誤處理 | 需自行檢查回應碼 | curl_errno()/curl_error() |
| 效能 | 較低(同步阻塞) | 較高,支援多執行緒 curl_multi |
| 依賴性 | 無(核心函數) | 需安裝 php-curl 擴展 |
CURLOPT_SSL_VERIFYPEER,否則易遭中間人攻擊http_build_query():自動處理陣列巢狀編碼、特殊字元跳脫,比手動拼裝更安全fsockopen 適合理解 HTTP 協議細節與極度受限環境;現代專案請優先使用 cURL 或 Guzzle、Http\Client 等 PSR-18 相容函式庫。