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

PHP 後端發送 POST 請求的兩種經典做法:fsockopen 與 cURL

     編輯:PHP 綜合知識

應用場景

在 API 串接、支付回調、服務間通訊等場景,PHP 後端常需主動向其他 URL 發送 POST 請求,而非透過瀏覽器表單。本文整理兩種最經典、無需表單的實作方式。

方法一:原生 fsockopen 實作 HTTP 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 發送 POST(推薦生產環境)

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);
?>

兩者比較與選擇建議

特性fsockopencURL
HTTPS 支援需自行實作 SSL/TLS原生支援
重導向處理手動解析 Location 標頭CURLOPT_FOLLOWLOCATION 自動
超時控制僅連線階段 fsockopen 參數完整 CURLOPT_TIMEOUT/CONNECTTIMEOUT
錯誤處理需自行檢查回應碼curl_errno()/curl_error()
效能較低(同步阻塞)較高,支援多執行緒 curl_multi
依賴性無(核心函數)需安裝 php-curl 擴展

最佳實踐提醒

  • 永遠驗證 SSL 憑證:生產環境勿關閉 CURLOPT_SSL_VERIFYPEER,否則易遭中間人攻擊
  • 使用 http_build_query():自動處理陣列巢狀編碼、特殊字元跳脫,比手動拼裝更安全
  • 設定合理超時:避免對方服務無回應導致本機進程卡死
  • 記錄日誌:請求參數、回應碼、耗時、錯誤訊息完整記錄,便於除錯
  • 考慮非同步:高併發場景可搭配 Swoole、Workerman 或訊息佇列(RabbitMQ、Redis Stream)異步發送

fsockopen 適合理解 HTTP 協議細節與極度受限環境;現代專案請優先使用 cURL 或 Guzzle、Http\Client 等 PSR-18 相容函式庫。

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