首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 無法上傳大文件完美解決方案:php.ini、Nginx、表單三維配置詳解

     編輯:PHP 相關知識

大文件上傳失敗是 PHP 開發中高頻痛點,往往涉及 PHP 核心配置、Web 伺服器限制、客戶端表單設置三個層面。本文系統梳理完整排查鏈路,提供可直接套用的配置模板與原理解析。

一、PHP 核心配置(php.ini)

編輯 php.ini,重點調整以下指令(生效需重啟 PHP-FPM/Apache):

指令預設值建議值說明
file_uploadsOnOn總開關,必須開啟
upload_tmp_dir系統臨時目錄/tmp/php_upload需確保目錄存在且 PHP 進程用戶可寫
upload_max_filesize2M100M單個文件上限
post_max_size8M120M必須 ≥ upload_max_filesize,含所有 POST 數據
max_execution_time30300腳本最大執行秒數,大文件需更久
max_input_time60300解析 POST 數據最大秒數
memory_limit128M256M腳本記憶體上限,流式處理可不調高
; 關鍵配置示例
file_uploads = On
upload_tmp_dir = /var/www/tmp_upload
upload_max_filesize = 100M
post_max_size = 120M
max_execution_time = 300
max_input_time = 300
memory_limit = 256M

二、Nginx 配置(client_max_body_size)

Nginx 預設限制請求體大小為 1M,超過直接返回 413 Request Entity Too Large。

1. 定位正確配置文件

主配置 nginx.conf 的 http、server、location 三層均可設定,就近原則生效。若使用 include domains/* 分離虛擬主機,請修改對應站點配置。

2. 關鍵指令

server {
    listen 80;
    server_name example.com;
    
    client_max_body_size 100M;      # 請求體上限
    client_body_buffer_size 128k;   # 緩衝區,超過寫入臨時文件
    client_body_temp_path /var/www/nginx_body_temp; # 臨時目錄需可寫
    
    location / {
        proxy_pass https://backend;
        # 反向代理場景下,此處也需設定,否則由 server 繼承
        client_max_body_size 100M;
    }
}

修改後執行 nginx -t && nginx -s reload 熱重載。

三、前端表單設置

<form action="upload.php" method="post" enctype="multipart/form-data">
  <!-- 必須設置 enctype -->
  <input type="hidden" name="MAX_FILE_SIZE" value="104857600"> <!-- 100M,瀏覽器端建議值 -->
  <input type="file" name="userfile">
  <input type="submit" value="上傳">
</form>

注意:MAX_FILE_SIZE 僅是瀏覽器建議,惡意用戶可繞過,**服務端驗證才是最後防線**。

四、PHP 處理腳本安全實踐

<?php
// upload.php
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
$maxSize = 100 * 1024 * 1024; // 100M
$uploadDir = __DIR__ . '/uploads/';

if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userfile'])) {
    $file = $_FILES['userfile'];
    
    // 1. 錯誤碼檢查
    if ($file['error'] !== UPLOAD_ERR_OK) {
        $msg = [
            UPLOAD_ERR_INI_SIZE   => '超過 php.ini upload_max_filesize',
            UPLOAD_ERR_FORM_SIZE  => '超過表單 MAX_FILE_SIZE',
            UPLOAD_ERR_PARTIAL    => '文件部分上傳',
            UPLOAD_ERR_NO_FILE    => '未選擇文件',
            UPLOAD_ERR_NO_TMP_DIR => '缺少臨時目錄',
            UPLOAD_ERR_CANT_WRITE => '寫入失敗',
        ];
        die($msg[$file['error']] ?? '未知錯誤');
    }
    
    // 2. 類型與大小二次驗證
    if (!in_array($file['type'], $allowedTypes)) die('類型不允許');
    if ($file['size'] > $maxSize) die('文件過大');
    
    // 3. 防止同名覆蓋:日期 + 隨機字串 + 原始副檔名
    $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
    $newName = date('YmdHis') . '_' . bin2hex(random_bytes(8)) . '.' . $ext;
    $dest = $uploadDir . $newName;
    
    // 4. 移動文件(驗證是否真為 HTTP 上傳)
    if (!move_uploaded_file($file['tmp_name'], $dest)) {
        die('移動失敗,請檢查目錄權限');
    }
    
    chmod($dest, 0644);
    echo "上傳成功:$newName";
}
?>

五、進階優化:分片上傳與流式處理

超大文件(>500M)建議採用前端分片(如 WebUploader、Plupload)、後端合併策略,避免單次請求超時、記憶體飆升。PHP 端可使用 fopen('php://input') 流式寫入臨時文件,而非依賴 $_FILES 全量緩衝。

六、常見排查清單

  1. ✅ php.ini 三大尺寸參數已調大並重啟 PHP
  2. ✅ Nginx client_max_body_size 已配置在正確 server/location 並 reload
  3. ✅ 表單 enctype="multipart/form-data" 未遺漏
  4. ✅ 上傳目錄與臨時目錄權限正確(PHP-FPM 用戶可寫)
  5. ✅ 磁碟空間充足(df -h 確認)
  6. ✅ 錯誤日誌(php-fpm.log、nginx/error.log)無 413/500/權限報錯

按層級逐項排查,99% 的大文件上傳問題均可解決。若仍失敗,請檢查是否有 CDN/WAF/負載均衡器額外限制請求體大小。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved