當客戶端以 Content-Type: application/octet-stream 或非表單編碼方式發送二進制數據(如圖片上傳、設備上報)時,$_POST 無法解析。需通過 php://input 或 $GLOBALS['HTTP_RAW_POST_DATA'] 讀取原始流。本文封裝通用函數並說明適用場景與避坑指南。
binary_to_file()<?php
/**
* 將請求體原始二進制流保存為文件
*
* @param string $file 目標文件路徑(含文件名)
* @return bool|int 寫入字節數,失敗返回 false
*/
function binary_to_file($file) {
// 1. 優先嘗試 $GLOBALS['HTTP_RAW_POST_DATA'](需 php.ini: always_populate_raw_post_data = On,PHP 5.6+ 棄用)
$content = $GLOBALS['HTTP_RAW_POST_DATA'] ?? '';
// 2. 回退到 php://input(不依賴 ini 配置,內存壓力較小,推薦)
if (empty($content)) {
$content = file_get_contents('php://input');
}
// 3. 寫入文件(FILE_APPEND 防止多次調用覆蓋,通常用 LOCK_EX 獨佔鎖)
$bytes = @file_put_contents($file, $content, LOCK_EX);
return $bytes !== false ? $bytes : false;
}
// 使用示例:接收客戶端 POST 的圖片二進制流
binary_to_file('uploads/photo_' . time() . '.png');
| 特性 | $GLOBALS['HTTP_RAW_POST_DATA'] | php://input |
|---|---|---|
| PHP 版本要求 | 所有版本(PHP 5.6+ 棄用,7.0+ 移除) | PHP 4.3+ |
需配置 php.ini | 是(always_populate_raw_post_data = On) | 否 |
| 內存佔用 | 始終佔用內存緩存整個請求體 | 流式讀取,可配合 fopen('php://input', 'r') 分塊處理大文件 |
multipart/form-data 支援 | 不支援 | 不支援 |
enctype="multipart/form-data" 的表單上傳。該場景請使用 $_FILES 超全局變量。always_populate_raw_post_data 並嘗試讀取 php://input,PHP 5.6+ 會報 Deprecated 警告。$fp = fopen('php://input', 'r'); while(!feof($fp)) { fwrite($dst, fread($fp, 8192)); }。Content-Type、Content-Length、來源 IP 白名單、簽名/Token 驗證。ini_set('memory_limit', '64M'); 或 Nginx client_max_body_size 10M;。