上傳 4.66MB 的 GIF 圖片,$_FILES['file']['size'] 為 0,$_FILES['file']['error'] 為 1(UPLOAD_ERR_INI_SIZE),小文件正常。
php.ini 中 upload_max_filesize = 2M 導致 PHP 直接拒絕接收超大文件,$_FILES 雖存在但內容為空/錯誤碼。
; 文件上傳核心配置 file_uploads = On upload_max_filesize = 50M ; 單文件上限 post_max_size = 60M ; 必須 > upload_max_filesize memory_limit = 128M ; 建議 ≥ post_max_size max_execution_time = 300 ; 大文件需更長執行時間 max_input_time = 300 ; 解析輸入數據時間 upload_tmp_dir = /var/www/tmp ; 確保目錄存在且 www-data 可寫
# systemd 系統 sudo systemctl restart php8.1-fpm # 或發送信號 sudo kill -USR2 $(cat /run/php/php8.1-fpm.pid)
# nginx.conf http 段或 server 段 client_max_body_size 60M; # 默認 1M,必須 ≥ post_max_size # 重載 nginx -s reload
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">上傳</button>
</form>
<?php
// test_upload.php
echo "upload_max_filesize: " . ini_get('upload_max_filesize') . "\n";
echo "post_max_size: " . ini_get('post_max_size') . "\n";
echo "memory_limit: " . ini_get('memory_limit') . "\n";
echo "file_uploads: " . (ini_get('file_uploads') ? 'On' : 'Off') . "\n";
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
var_dump($_FILES);
}
?>
| 項目 | 檢查點 |
|---|---|
| php.ini 路徑 | php --ini 確認載入的文件 |
| 多版本 PHP | CLI 和 FPM 可能用不同 ini |
| 單位後綴 | M/K/G 不區分大小寫,無單位視為字節 |
| post_max_size < upload_max_filesize | 導致 POST 數據被截斷,$_FILES 為空 |
| Nginx/Apache 限制 | client_max_body_size / LimitRequestBody |
| 臨時目錄權限 | chown www-data:www-data /var/www/tmp |
| 磁盤空間 | df -h 確認臨時分區有空間 |
| 安全模式/損壞檢查 | open_basedir 限制臨時目錄訪問 |
若業務需上傳 GB 級文件,單純調大配置不可行,需前端分片 + 後端合併:
<?php
// 後端合併分片示例
$chunkDir = '/var/www/uploads/chunks/' . $fileId;
$finalPath = '/var/www/uploads/' . $fileName;
$chunks = glob($chunkDir . '/part_*');
sort($chunks, SORT_NATURAL);
$fp = fopen($finalPath, 'wb');
foreach ($chunks as $chunk) {
fwrite($fp, file_get_contents($chunk));
unlink($chunk); // 刪除分片
}
fclose($fp);
rmdir($chunkDir);
?>
upload_max_filesize + post_max_size(php.ini)client_max_body_size (Nginx) / LimitRequestBody (Apache)ini_get() 確認生效配置鏈路中任一環節受限,都會導致上傳失敗,系統性排查是關鍵。