三種 POST 數據獲取方式對比
| 方式 | 適用場景 | 特點 | 獲取變量 |
| 表單提交 | 瀏覽器普通表單 | 自動解析、urldecode、編碼轉換 | $_POST、php://input |
| fsockopen 模擬 | 服務端之間通訊、爬蟲 | 手動構造 HTTP 報文、完全可控 | $_POST、php://input |
| 非標準 Content-Type | API、JSON、XML、文件上傳 | PHP 不自動解析 | php://input、$HTTP_RAW_POST_DATA |
核心變量詳解
1. $_POST —— 最常用
- 僅當
Content-Type: application/x-www-form-urlencoded 或 multipart/form-data 時自動填充。
- 鍵值對結構,自動
urldecode。
- 文件上傳時文件信息在
$_FILES,不在 $_POST。
2. php://input —— 原始流(推薦)
- 讀取未經處理的 HTTP 實體體(Raw Body)。
- 內存佔用小,無需
php.ini 配置。
- 不可用於
multipart/form-data(文件上傳)。
- 典型用途:接收 JSON API 數據
json_decode(file_get_contents('php://input'), true)。
3. $HTTP_RAW_POST_DATA —— 棄用(PHP 7.0 移除)
- 僅當
Content-Type 為 PHP 無法識別類型時才填充。
- 需
php.ini 開啟 always_populate_raw_post_data = On(PHP 5.6+ 棄用)。
- 內存佔用大,新代碼請勿使用。
實戰代碼對比
場景 A:普通表單提交
<?php
// 瀏覽器 POST:name=foo&email=bar@example.com
var_dump($_POST); // ['name'=>'foo', 'email'=>'bar@example.com']
var_dump(file_get_contents('php://input')); // "name=foo&email=bar@example.com"
?>
場景 B:JSON API 請求
<?php
// Client: Content-Type: application/json
// Body: {"id":1,"action":"buy"}
$data = json_decode(file_get_contents('php://input'), true);
var_dump($data); // ['id'=>1, 'action'=>'buy']
var_dump($_POST); // [] 空!PHP 不解析 application/json
?>
場景 C:fsockopen 模擬 POST
<?php
$sock = fsockopen('localhost', 80, $errno, $errstr, 30);
if (!$sock) die("$errstr ($errno)");
$postData = http_build_query(['txt' => '中文', 'bar' => 'Value']);
$req = "POST /posttest/response.php HTTP/1.1\r\n"
. "Host: localhost\r\n"
. "Content-Type: application/x-www-form-urlencoded\r\n"
. "Content-Length: " . strlen($postData) . "\r\n"
. "Connection: close\r\n\r\n"
. $postData;
fwrite($sock, $req);
$resp = '';
while (!feof($sock)) $resp .= fgets($sock, 4096);
fclose($sock);
// $resp 包含響應頭 + 體,需自行分離
echo $resp;
?>
關鍵結論
- 優先用
php://input 獲取原始數據,再按業務反序列化(JSON、XML、Protobuf 等)。
$_POST 只處理標準表單編碼,不可靠用於 API。
$HTTP_RAW_POST_DATA 已被移除,舊項目遷移至 php://input。
- 文件上傳(
multipart/form-data)只能用 $_POST/$_FILES,無法用 php://input。
- 手動構造請求時,務必正確設置
Content-Length 與 Content-Type。
最佳實踐封裝
<?php
function getInputData(): array {
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
$raw = file_get_contents('php://input');
if (str_starts_with($contentType, 'application/json')) {
return json_decode($raw, true) ?? [];
}
if (str_starts_with($contentType, 'application/x-www-form-urlencoded')) {
parse_str($raw, $parsed);
return $parsed;
}
// 其他類型(XML、自定義)按需擴展
return [];
}
?>