上傳大檔案失敗通常是「多層限制疊加」:PHP 設定、Nginx 設定、表單屬性、瀏覽器行為。本文提供從 php.ini 到 Nginx、再到前端表單的完整檢查清單與設定範例,一次解決所有瓶頸。
| 指令 | 預設 | 建議值(>100MB) | 說明 |
|---|---|---|---|
file_uploads | On | On | 總開關 |
upload_max_filesize | 2M | 200M | 單一檔案上限 |
post_max_size | 8M | 210M | 必須 > upload_max_filesize,含所有表單欄位 |
max_execution_time | 30 | 600 | 腳本最長執行秒數(上傳+處理) |
max_input_time | 60 | 600 | 接收 POST 資料最長秒數 |
memory_limit | 128M | 256M | 若在記憶體處理圖片壓縮需調大 |
upload_tmp_dir | 系統預設 | /tmp/upload | 需可寫、空間足夠、獨立分區更佳 |
修改後必須重啟 php-fpm:systemctl reload php8.2-fpm。
# nginx.conf / http {} 或 server {} 或 location {}
client_max_body_size 200m; # 預設 1m,超過回 413 Request Entity Too Large
client_body_buffer_size 10m; # 緩衝區,太小會頻繁落磁碟拖慢速度
client_body_temp_path /var/lib/nginx/body 1 2; # 臨時檔目錄需可寫
修改後 nginx -t && systemctl reload nginx。
<form action="upload.php" method="post" enctype="multipart/form-data">
<!-- 僅為瀏覽器端提示,不可信,後端仍需驗證 -->
<input type="hidden" name="MAX_FILE_SIZE" value="209715200">
<input type="file" name="file" id="file">
<button type="submit">上傳</button>
</form>
<?php
// upload.php
$targetDir = '/var/www/uploads/';
$maxSize = 200 * 1024 * 1024; // 200MB
$allowed = ['image/jpeg','image/png','application/pdf'];
if ($_SERVER['REQUEST_METHOD'] !== 'POST') exit('Method not allowed');
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
exit('上傳錯誤代碼: ' . ($_FILES['file']['error'] ?? '未知'));
}
if ($_FILES['file']['size'] > $maxSize) exit('檔案過大');
if (!in_array($_FILES['file']['type'], $allowed)) exit('類型不允許');
// 安全檔名:UUID + 原始副檔名
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$newName = bin2hex(random_bytes(16)) . '.' . $ext;
$dest = $targetDir . $newName;
if (!move_uploaded_file($_FILES['file']['tmp_name'], $dest)) {
exit('移動檔案失敗,請檢查權限');
}
// 後續:記錄資料庫、觸發佇列處理、回傳 JSON
echo json_encode(['ok'=>true, 'path'=>'/uploads/'.$newName]);
| 代碼 | 常數 | 原因與對策 |
|---|---|---|
| 1 | UPLOAD_ERR_INI_SIZE | 超過 upload_max_filesize → 改 php.ini |
| 2 | UPLOAD_ERR_FORM_SIZE | 超過 MAX_FILE_SIZE 隱藏欄位 → 前端調大或移除 |
| 3 | UPLOAD_ERR_PARTIAL | 網路中斷 → 檢查 max_input_time、Nginx client_body_timeout |
| 4 | UPLOAD_ERR_NO_FILE | 未選檔案 → 前端驗證 |
| 6 | UPLOAD_ERR_NO_TMP_DIR | 缺 upload_tmp_dir → 設定並 chmod 777 |
| 7 | UPLOAD_ERR_CANT_WRITE | 磁碟滿/權限不足 → df -h、ls -ld |
| 8 | UPLOAD_ERR_EXTENSION | 擴充模組攔截 → 檢查 suhosin、mod_security |
post_max_size = 0(無限制)。proxy_request_buffering off; 避免代理緩衝大檔案導致記憶體暴增。照著清單逐項核對,99% 的「上傳大檔失敗」都能在 10 分鐘內解決。