在無法安裝 cURL 或 pecl_http 擴展的受限環境,可使用 PHP 內建 fsockopen() 手工組裝 HTTP 封包,實作完整的 GET/POST 請求,支援 Header 自訂、Cookie、逾時、阻塞/非阻塞模式。
<?php
/**
* 純 Socket HTTP 請求
* @param string $url 完整 URL
* @param array|string $post POST 資料
* @param string $method GET|POST
* @param int $limit 讀取長度限制 (0=無限制)
* @param bool $returnHeader 是否回傳 Header
* @param string $cookie Cookie 字串
* @param bool $bySocket 強制使用 Socket (保留相容)
* @param string $ip 指定解析 IP
* @param int $timeout 逾時秒數
* @param bool $block 阻塞模式
* @return string|array|false 內容/含Header/失敗false
*/
function httpRequest(
string $url,
$post = '',
string $method = 'GET',
int $limit = 0,
bool $returnHeader = false,
string $cookie = '',
bool $bySocket = false,
string $ip = '',
int $timeout = 15,
bool $block = true
) {
$parsed = parse_url($url);
$host = $parsed['host'] ?? '';
$path = ($parsed['path'] ?? '/') . (isset($parsed['query']) ? '?' . $parsed['query'] : '');
$port = $parsed['port'] ?? ($parsed['scheme'] === 'https' ? 443 : 80);
// HTTPS 需使用 ssl:// 前綴
$fpHost = ($parsed['scheme'] === 'https' ? 'ssl://' : '') . ($ip ?: $host);
$out = "$method $path HTTP/1.0\r\n";
$out .= "Host: $host\r\n";
$out .= "User-Agent: {$_SERVER['HTTP_USER_AGENT'] ?? 'PHP Socket Client'}\r\n";
$out .= "Accept: */*\r\n";
$out .= "Connection: Close\r\n";
if ($cookie) $out .= "Cookie: $cookie\r\n";
if (strtoupper($method) === 'POST') {
$postData = is_array($post) ? http_build_query($post) : $post;
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
$out .= "Content-Length: " . strlen($postData) . "\r\n";
$out .= "\r\n$postData";
} else {
$out .= "\r\n";
}
$fp = fsockopen($fpHost, $port, $errno, $errstr, $timeout);
if (!$fp) {
error_log("Socket 連線失敗 [$errno]: $errstr");
return false;
}
stream_set_blocking($fp, $block);
stream_set_timeout($fp, $timeout);
fwrite($fp, $out);
$header = $content = '';
$meta = stream_get_meta_data($fp);
if (!$meta['timed_out']) {
// 讀取 Header
while (!feof($fp)) {
$line = fgets($fp);
$header .= $line;
if ($line === "\r\n" || $line === "\n") break;
}
// 讀取 Body
while (!feof($fp) && (!$limit || $limit > 0)) {
$chunk = fread($fp, $limit ? min(8192, $limit) : 8192);
$content .= $chunk;
if ($limit) $limit -= strlen($chunk);
}
} else {
error_log("Socket 讀取逾時");
}
fclose($fp);
return $returnHeader ? ['header' => $header, 'content' => $content] : $content;
}
// 使用範例
echo httpRequest('https://www.baidu.com');
?>
fsockopen('ssl://host', 443) 需 OpenSSL 擴展(PHP 核心內建)。\r\n\r\n 或 \n\n。雖然功能較 cURL 簡略,但在「零依賴」約束下是可靠的備選方案。