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

PHP Socket 發送 POST 請求完整實作與細節解析

     編輯:PHP 綜合知識

PostToHost 函式

<?php
function PostToHost($url, $data) {
    $url = parse_url($url);
    if (!$url) return "couldn't parse url";
    $url['port'] = $url['port'] ?? '';
    $url['query'] = $url['query'] ?? '';

    // 組裝主體
    $encoded = '';
    foreach ($data as $k => $v) {
        $encoded .= ($encoded ? '&' : '') . rawurlencode($k) . '=' . rawurlencode($v);
    }

    $port = $url['port'] ? $url['port'] : 80;
    $fp = fsockopen($url['host'], $port, $errno, $errstr, 10);
    if (!$fp) return "Failed to open socket to {$url['host']}:{$port} ERROR: $errno - $errstr";

    // 發送請求
    fputs($fp, sprintf("POST %s%s%s HTTP/1.0\r\n", $url['path'], $url['query'] ? '?' : '', $url['query']));
    fputs($fp, "Host: {$url['host']}\r\n");
    fputs($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
    fputs($fp, "Content-Length: " . strlen($encoded) . "\r\n");
    fputs($fp, "Connection: close\r\n\r\n");
    fputs($fp, $encoded . "\r\n");

    // 讀取狀態行
    $line = fgets($fp, 1024);
    if (!preg_match('/^HTTP\/\d\.\d\s+200/', $line)) return;

    // 讀取主體
    $results = '';
    $inHeader = true;
    while (!feof($fp)) {
        $line = fgets($fp, 1024);
        if ($inHeader && ($line === "\n" || $line === "\r\n")) {
            $inHeader = false;
        } elseif (!$inHeader) {
            $results .= $line;
        }
    }
    fclose($fp);
    return $results;
}
?>

細節解析

  • parse_url():解析 scheme、host、port、path、query 等元件;port 預設 80。
  • rawurlencode():依 RFC 3986 編碼,空格編為 %20 (而非 +),符合 HTTP 標準。
  • 請求行:POST /path?query HTTP/1.0,HTTP/1.0 不支援持久連線,配合 Connection: close 確保對方關閉連線。
  • 標頭結束:雙 \r\n\r\n 分隔標頭與主體。
  • 回應讀取:先讀狀態行檢查 200,再逐行讀取;遇空行 (\n 或 \r\n) 視為標頭結束,之後內容累加為主體。
  • 錯誤處理:連線失敗、非 2xx 狀態碼均回傳 false 或錯誤字串,呼叫端需檢查。

現代替代方案

// cURL 版本 (支援 HTTPS、重導向、超時、憑證驗證)
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($data),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
curl_close($ch);

結語

Socket 底層實作有助於理解 HTTP 協定細節,但生產環境請使用 cURL 或 Guzzle 等成熟客戶端,獲得完整的協定支援與錯誤處理能力。

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