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

PHP $_FILES['error'] 完整錯誤碼對照表與異常處理最佳實踐

     編輯:PHP 相關知識

文件上傳失敗時,$_FILES['file']['error'] 是排查的第一現場。本文提供完整錯誤碼常量對照、中文說明、觸發場景、處理建議,並封裝統一異常處理類。

官方錯誤碼常量對照表

常量值含義典型觸發場景處理建議
UPLOAD_ERR_OK0上傳成功—正常處理
UPLOAD_ERR_INI_SIZE1超過 php.ini upload_max_filesize上傳大文件、配置過小提示用戶壓縮/分片;調大配置並重啟 PHP-FPM
UPLOAD_ERR_FORM_SIZE2超過表單 MAX_FILE_SIZE 隱藏域前端限制小於實際文件移除或調大隱藏域;注意此限制極易繞過,不可信任
UPLOAD_ERR_PARTIAL3文件只被部分上傳網絡中斷、客戶端取消、PHP 超時提示重試;檢查 max_execution_time、Nginx client_body_timeout
UPLOAD_ERR_NO_FILE4沒有文件被上傳用戶未選文件直接提交、input name 不匹配前端校驗必填;後端兜底判斷
UPLOAD_ERR_NO_TMP_DIR6缺少臨時目錄upload_tmp_dir 未配置或目錄不可寫配置有效可寫目錄;檢查 open_basedir 限制
UPLOAD_ERR_CANT_WRITE7寫入臨時文件失敗磁盤滿、權限不足、inode 耗盡、SELinux 限制磁盤清理、權限修復、df -i 檢查 inode
UPLOAD_ERR_EXTENSION8PHP 擴展阻止上傳安裝了類似 suhosin、mod_security 的擴展並攔截檢查擴展配置白名單;必要時禁用擴展

統一異常處理類

<?php
class UploadException extends Exception {
    public function __construct(public int $code, string $message = '') {
        parent::__construct($message ?: self::getMessageByCode($code), $code);
    }
    public static function getMessageByCode(int $code): string {
        return match($code) {
            UPLOAD_ERR_INI_SIZE     => '文件大小超過服務器限制 (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   => '服務器寫入臨時文件失敗',
            UPLOAD_ERR_EXTENSION    => '上傳被服務器擴展攔截',
            default                 => '未知上傳錯誤',
        };
    }
}

function handleUpload(array $file, array $allowedTypes = [], int $maxSize = 10485760): string {
    // 1. 錯誤碼檢查
    if ($file['error'] !== UPLOAD_ERR_OK) {
        throw new UploadException($file['error']);
    }
    // 2. 文件大小二次檢查(防繞過 MAX_FILE_SIZE)
    if ($file['size'] > $maxSize) {
        throw new UploadException(UPLOAD_ERR_INI_SIZE, "文件大小 {$file['size']} 超過限制 $maxSize");
    }
    // 3. MIME 類型檢查(不要信任瀏覽器傳來的 type,用 finfo 驗證真實類型)
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime = $finfo->file($file['tmp_name']);
    if ($allowedTypes && !in_array($mime, $allowedTypes, true)) {
        throw new UploadException(0, "文件類型 $mime 不在允許列表中");
    }
    // 4. 構建安全存儲路徑
    $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
    $safeName = bin2hex(random_bytes(16)) . ($ext ? ".$ext" : '');
    $dateDir = date('Y/m/d');
    $destDir = "/var/www/uploads/$dateDir";
    if (!is_dir($destDir)) mkdir($destDir, 0755, true);
    $destPath = "$destDir/$safeName";
    // 5. 移動文件(移動比複製+刪除原子、快)
    if (!move_uploaded_file($file['tmp_name'], $destPath)) {
        throw new UploadException(0, '移動上傳文件失敗');
    }
    return $destPath; // 返回相對或絕對路徑供業務入庫
}

// 使用
try {
    $path = handleUpload($_FILES['avatar'], ['image/jpeg', 'image/png', 'image/webp'], 5*1024*1024);
    // 入庫 $path ...
    echo json_encode(['code' => 0, 'path' => $path]);
} catch (UploadException $e) {
    echo json_encode(['code' => $e->getCode(), 'msg' => $e->getMessage()]);
}

關鍵避坑指南

  1. 不要信任 $_FILES['type']: 瀏覽器根據擴展名猜測,極易偽造。必須用 finfo 或 getimagesize() 驗證真實內容。
  2. MAX_FILE_SIZE 隱藏域無安全性: 客戶端可篡改,僅作用戶體驗提示,服務端必須以 upload_max_filesize 和代碼邏輯為準。
  3. 臨時文件自動清理: 腳本結束時 PHP 自動刪除 tmp_name 文件,必須用 move_uploaded_file 移動,否則文件丟失。
  4. 大文件上傳: 需調整 post_max_size > upload_max_filesize、max_execution_time、max_input_time、Nginx client_max_body_size、client_body_timeout、proxy_read_timeout。
  5. 分片/斷點續傳: 前端切片(如 Uppy、WebUploader),後端合併,避免單次請求超時/超大。

上傳看似簡單,實則涉及客戶端、Web Server、PHP、文件系統、安全策略多層交互。建立標準化異常處理流程,能覆蓋 99% 線上上傳故障排查場景。

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