class HttpClient {
/** cURL 方式 - 功能最全、性能最好、推荐生产环境 */
public static function postCurl(string $url, array $data = [], int $timeout = 5): string {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_HEADER => false,
CURLOPT_SSL_VERIFYPEER => true, // 生产环境必须验证
CURLOPT_CAINFO => '/etc/ssl/certs/ca-certificates.crt', // CA 路径
]);
$result = curl_exec($ch);
if ($result === false) {
throw new RuntimeException('cURL Error: ' . curl_error($ch));
}
curl_close($ch);
return $result;
}
/** stream_context 方式 - 无扩展依赖、原生支持、适合简单场景 */
public static function postStream(string $url, array $data = []): string {
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($data),
'timeout' => 5,
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
'cafile' => '/etc/ssl/certs/ca-certificates.crt',
],
]);
$result = file_get_contents($url, false, $context);
if ($result === false) {
throw new RuntimeException('Stream POST failed');
}
return $result;
}
/** fsockopen 方式 - 底层 Socket、无 HTTPS 支持、仅教学/极简环境用 */
public static function postSocket(string $host, string $path, string $query): string {
$request = "POST $path HTTP/1.1\r\n";
$request .= "Host: $host\r\n";
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: " . strlen($query) . "\r\n";
$request .= "Connection: close\r\n\r\n";
$request .= $query;
$fp = fsockopen($host, 80, $errno, $errstr, 5);
if (!$fp) throw new RuntimeException("Socket connect failed: $errstr ($errno)");
fwrite($fp, $request);
$response = '';
while (!feof($fp)) {
$response .= fread($fp, 8192);
}
fclose($fp);
// 简易去除 HTTP 头
list(, $body) = explode("\r\n\r\n", $response, 2);
return $body;
}
}
$url = 'https://api.example.com/endpoint';
$data = ['action' => 'user_list', 'page' => 1];
try {
// 方式 1: cURL (推荐)
$result = HttpClient::postCurl($url, $data);
// 方式 2: Stream (无 cURL 扩展时)
// $result = HttpClient::postStream($url, $data);
// 方式 3: Socket (仅 HTTP、教学)
// $result = HttpClient::postSocket('api.example.com', '/endpoint', http_build_query($data));
echo $result;
} catch (Exception $e) {
error_log($e->getMessage());
echo '请求失败';
}
| 维度 | cURL | stream_context | fsockopen |
|---|---|---|---|
| HTTPS 支持 | 原生完美 | 需配置 ssl 上下文 | 不支持 (需手写 TLS) |
| 并发/多路复用 | curl_multi_* 强大 | stream_select 可实现 | 极难实现 |
| 协议支持 | HTTP/HTTPS/FTP/SMTP/... | HTTP/HTTPS/FTP/... | 仅 TCP 原始流 |
| 重定向跟随 | CURLOPT_FOLLOWLOCATION | 需手动处理 Location | 需手动解析 |
| Cookie 管理 | CURLOPT_COOKIEJAR/FILE | 手动处理 Set-Cookie | 手动处理 |
| 文件上传 | CURLFile 原生 | 手动构造 multipart | 手动构造 |
| 性能 | 最高 (C 底层) | 中等 (PHP 流封装) | 最低 (PHP 脚本循环) |
| 依赖 | 需 php-curl 扩展 | 核心内置 | 核心内置 |
| 代码复杂度 | 中等 (选项多) | 低 (配置数组) | 高 (手写协议) |
// 实际项目建议直接用成熟库:guzzlehttp/guzzle, symfony/http-client, php-http/client
// 示例:composer require guzzlehttp/guzzle
$client = new \GuzzleHttp\Client();
$response = $client->post('https://api.example.com/endpoint', [
'json' => ['action' => 'user_list'],
'timeout' => 5,
]);
$data = json_decode($response->getBody(), true);
手写封装仅适合学习或极度受限环境,生产项目请拥抱标准库。