<?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;
}
?>
%20 (而非 +),符合 HTTP 標準。POST /path?query HTTP/1.0,HTTP/1.0 不支援持久連線,配合 Connection: close 確保對方關閉連線。\r\n\r\n 分隔標頭與主體。200,再逐行讀取;遇空行 (\n 或 \r\n) 視為標頭結束,之後內容累加為主體。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 等成熟客戶端,獲得完整的協定支援與錯誤處理能力。