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

PHP 大文件上傳失敗完整排查:配置參數、代碼邏輯與服務器限制

     編輯:PHP 相關知識

PHP 文件上傳「大文件失敗/無響應」徹底解決方案

上傳大文件 (>2M) 失敗、頁面白屏、無錯誤信息,90% 是 **PHP/服務器多層限制疊加** 導致。本文提供從 `php.ini` 到 Nginx/Apache、前端、代碼邏輯的全鏈路配置清單。

核心限制參數對照表 (必改項)

層級參數默認值建議大文件值 (如 100MB)說明
PHP (php.ini)upload_max_filesize2M100M單個上傳文件最大體積
post_max_size8M110M**POST 總數據上限,必須 > upload_max_filesize** (含表單其他字段)
max_execution_time30s0 (無限制) 或 300腳本最大執行時間,上傳+處理需足夠時間。CLI 模式無效
PHP (運行時)max_input_time60s300解析 POST/GET 數據最大時間,含文件上傳接收
memory_limit128M256M+腳本內存上限,處理大圖/解析大 CSV 時需調大
Nginxclient_max_body_size1M110M**Nginx 層面攔截大包**,配置在 `http`/`server`/`location` 塊
proxy_read_timeout60s300s反向代理模式下後端處理超時
fastcgi_read_timeout60s300sPHP-FPM 處理超時
ApacheLimitRequestBody0 (無限)115343360 (110M)目錄/虛擬主機級別限制
TimeOut300s300請求接收/發送總超時

php.ini 修改示例 (生效需重啟 PHP-FPM/Apache)

; 文件上傳
file_uploads = On
upload_max_filesize = 100M
post_max_size = 110M

; 執行時間 (0 表示無限制,生產建議具體值如 300)
max_execution_time = 300
max_input_time = 300

; 內存
memory_limit = 256M

; 臨時目錄權限確保可寫
; upload_tmp_dir = /tmp/php_uploads

Nginx + PHP-FPM 關鍵配置

# nginx.conf http 塊或 server 塊
client_max_body_size 110M;

# PHP-FPM 站點配置 location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;

# 超時設置 (防大文件處理中斷)
fastcgi_read_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_connect_timeout 300s;

# 緩衝區優化 (大文件上傳)
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 32k;
}

代碼邏輯健壯化 (關鍵點)

<?php
function handleLargeUpload(array $file, string $saveDir, array $allowedMimes = []): array {
    // 1. 錯誤碼檢查 (UPLOAD_ERR_INI_SIZE=1, UPLOAD_ERR_FORM_SIZE=2, UPLOAD_ERR_PARTIAL=3, UPLOAD_ERR_NO_FILE=4)
    if ($file['error'] !== UPLOAD_ERR_OK) {
        $msg = match($file['error']) {
            UPLOAD_ERR_INI_SIZE   => "超過 php.ini upload_max_filesize ({$file['size']} bytes)",
            UPLOAD_ERR_FORM_SIZE  => "超過 HTML 表單 MAX_FILE_SIZE",
            UPLOAD_ERR_PARTIAL    => "文件僅部分上傳 (網絡中斷/超時)",
            UPLOAD_ERR_NO_FILE    => "未選擇文件",
            UPLOAD_ERR_NO_TMP_DIR => "缺少臨時目錄",
            UPLOAD_ERR_CANT_WRITE => "寫入磁盤失敗",
            UPLOAD_ERR_EXTENSION  => "被 PHP 擴展攔截",
            default => "未知上傳錯誤: {$file['error']}",
        };
        throw new Exception($msg);
    }

    // 2. MIME 類型驗證 (防偽裝) - 使用 finfo 而非 $_FILES['type']
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    if ($allowedMimes && !in_array($mime, $allowedMimes)) {
        @unlink($file['tmp_name']);
        throw new Exception("禁止的文件類型: $mime");
    }

    // 3. 生成唯一文件名 (防覆蓋、防遍歷)
    $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
    $newName = bin2hex(random_bytes(16)) . '.' . strtolower($ext);
    $destPath = rtrim($saveDir, '/') . '/' . $newName;

    // 4. 移動文件 (move_uploaded_file 自帶安全檢查)
    if (!move_uploaded_file($file['tmp_name'], $destPath)) {
        throw new Exception("文件保存失敗: 目錄不可寫或磁盤滿");
    }
    @chmod($destPath, 0644);

    return ['path' => $destPath, 'name' => $newName, 'mime' => $mime, 'size' => $file['size']];
}

// 表單端必須設置 enctype 和 MAX_FILE_SIZE (隱藏字段,客戶端可繞過,服務端以 php.ini 為準)
/*
*/ ?>

超大文件 (>500MB) 進階方案:分片上傳

單次 HTTP 上傳受限於瀏覽器/代理/超時,不可靠。採用 **前端分片 + 後端合併**:

  1. 前端 (Plupload / Uppy / WebUploader) 將文件切片 (如 5MB/片),並發上傳,帶 `chunk_index`、`total_chunks`、`file_hash` (MD5/SHA1)。
  2. 後端接收分片保存至臨時目錄 `tmp/{file_hash}/part_{index}`。
  3. 所有分片上傳完成 → 前端發送 `merge` 請求。
  4. 後端驗證分片完整性 → 二進制拼接 (`fopen('ab')` 追加寫入) → 校驗最終文件 Hash → 移動至正式目錄 → 清理臨時分片。
  5. 支持**斷點續傳**:上傳前查詢已存在分片,跳過已上傳部分。

快速排查清單 (上傳失敗按順序查)

  1. `phpinfo()` 確認 `upload_max_filesize`、`post_max_size` 生效值?
  2. Nginx `client_max_body_size` 是否配置並 `reload`?
  3. `$_FILES['file']['error']` 具體錯誤碼是多少?(關鍵線索)
  4. 臨時目錄 (`upload_tmp_dir` 或 `sys_get_temp_dir()`) 磁盤空間/權限?
  5. 腳本 `max_execution_time`/`memory_limit` 是否足夠?
  6. 前端 `FormData` 是否正確 `append`、請求頭 `Content-Type: multipart/form-data`?
  7. 是否開啟了 `mod_security` / WAF 攔截大包?

總結

**大文件上傳 = PHP.ini + Nginx/Apache + 代碼邏輯 三層同時放開**。常規文件 (<100MB) 調大上述參數即可;超大文件**必須分片上傳**,配合斷點續傳、秒傳 (Hash 校驗) 才是生產級方案。

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