PHP 內建的 file_get_contents 搭配 stream_context_create,無需安裝 cURL 擴展即可發送 HTTP 請求。本文詳細說明如何正確發送 POST 請求(含 JSON、表單資料),並處理常見陷阱。
<?php
$url = 'https://api.example.com/endpoint';
$options = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n" .
"Accept: application/json\r\n",
'content' => json_encode(['key' => 'value']),
'timeout' => 30,
]
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
if ($response === false) {
throw new Exception("請求失敗");
}
$data = json_decode($response, true);
| 類型 | Header | Content 格式 | 適用場景 |
|---|---|---|---|
| JSON | application/json | json_encode($array) | 現代 REST API、Webhook |
| 表單 | application/x-www-form-urlencoded | http_build_query($array) | 傳統 API、OAuth token 端點 |
<?php
function postJson(string $url, array $data, int $timeout = 30): array {
$options = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n" .
"User-Agent: PHP/" . PHP_VERSION . "\r\n",
'content' => json_encode($data, JSON_UNESCAPED_UNICODE),
'timeout' => $timeout,
'ignore_errors' => true, // 取得 4xx/5xx 回應內容
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
]
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
// 取得 HTTP 狀態碼
$meta = stream_get_meta_data($context);
$httpCode = 0;
if (isset($meta['wrapper_data'])) {
foreach ($meta['wrapper_data'] as $header) {
if (stripos($header, 'HTTP/') === 0) {
preg_match('/\d{3}/', $header, $matches);
$httpCode = (int)$matches[0];
break;
}
}
}
if ($response === false || $httpCode >= 400) {
throw new Exception("HTTP {$httpCode}: " . ($response ?: '請求失敗'));
}
return json_decode($response, true) ?? [];
}
// 使用範例
try {
$result = postJson('https://httpbin.org/post', [
'name' => 'Joe',
'website' => 'www.example.com'
]);
print_r($result);
} catch (Exception $e) {
error_log($e->getMessage());
}
<?php
function postForm(string $url, array $data, int $timeout = 30): string {
$options = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query($data),
'timeout' => $timeout,
]
];
$context = stream_context_create($options);
return file_get_contents($url, false, $context) ?: '';
}
'ssl' => [
'verify_peer' => false, // 僅開發測試使用
'verify_peer_name' => false, // 僅開發測試使用
]
警告:生產環境務必啟用驗證,否則有中間人攻擊風險。
需同時設定 default_socket_timeout (php.ini) 與 context 的 timeout 參數。
file_get_contents 會將整個回應載入記憶體,大檔案請改用 cURL 或 fopen 串流處理。
預設不跟隨重導向,需加入 'follow_location' => 1 (PHP 7.1+)。
| 特性 | file_get_contents | cURL |
|---|---|---|
| 依賴性 | 核心內建 | 需安裝擴展 |
| 記憶體效率 | 全載入記憶體 | 支援串流 |
| 功能豐富度 | 基本 HTTP | 完整 HTTP/2、多協定 |
| 效能 | 一般 | 較佳(連線復用等) |
| 適用場景 | 簡單請求、小回應 | 生產級、複雜需求 |
掌握 file_get_contents 的進階用法,能在無法安裝擴展的環境下快速完成 HTTP 整合;但生產系統建議優先使用成熟的 HTTP 客戶端庫(Guzzle、Symfony HttpClient 等)。