You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

POST请求时捕获PHP文件上传过大警告并返回JSON错误

解决PHP大文件上传时的错误捕获与友好提示问题

问题背景

我有一台用于文件上传的Apache服务器,采用PHP 8.2编写脚本。创建了表单允许用户上传图片和视频,但文件过大时仅返回通用JSON 400错误“Failed to upload your file”。此时PHP会在Apache日志中记录警告:

PHP Warning: POST Content-Length of 8978294 bytes exceeds the limit of 8388608 bytes in Unknown on line 0

希望在运行时捕获该错误,简化为类似“文件过大,仅允许上传XXMB以内的文件”的提示,并返回合适的HTTP状态码。当前文件过大时$_FILES为空数组,常规try-catch无法捕获异常,脚本仍会继续运行。

原处理POST请求的代码:

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    header('Content-Type: application/json');

    $asset = $_FILES['file_data'];

    // 存储客户端上传时的文件名
    $assetName = $asset['name'];

    // 存储文件类型,例如image/jpeg
    $assetType = $asset['type'];

    // 存储上传过程中的错误码
    $assetError = $asset['error'];

    // 存储服务器生成的临时文件名
    $assetTemp = $asset['tmp_name'];

    $uploadPath = dirname(__DIR__, 1).'/uploads/';

    $extensionsAllowed = ['png','jpg','jpeg','tiff','tif','webp','mp4','mp3','acc'];

    $fileExtension =  pathinfo($assetName, PATHINFO_EXTENSION);

    if(array_search($fileExtension, $extensionsAllowed) === false) {
        echo json_encode(['status'=>415,'message'=>'Failed to upload your file']);
        exit;
    }

    if(is_uploaded_file($assetTemp)) {
        if(move_uploaded_file($assetTemp, $uploadPath . $assetName)) {
            echo json_encode(['status'=>200,'message'=>'Successfully uploaded '.$assetName);
            exit;
        }
        else {
            echo json_encode(['status'=>400,'message'=>'Failed to move your file']);
            exit;
        }
    }
    else {
        echo json_encode(['status'=>400,'message'=>'Failed to upload your file']);
        exit;
    }
}

解决方案

1. 核心问题分析

该警告发生在PHP脚本正式执行前(请求解析阶段),无法用常规try-catch捕获。需通过自定义错误处理器或直接检查请求头信息来判断。同时文件过大时$_FILES会为空,需在脚本开头增加空值判断。

2. 具体实现方案

方案一:检查请求内容长度与PHP配置限制

直接对比CONTENT_LENGTH请求头和php.ini中的上传限制,无需依赖错误日志:

// 辅助函数:将php.ini中的文件大小(如2M)转换为字节
function convertToBytes($size) {
    $unit = strtoupper(substr($size, -1));
    $size = (int)substr($size, 0, -1);
    switch($unit) {
        case 'G': $size *= 1024;
        case 'M': $size *= 1024;
        case 'K': $size *= 1024;
    }
    return $size;
}

// 获取服务器允许的最大上传字节数
$maxUploadBytes = convertToBytes(ini_get('upload_max_filesize'));

// 检查POST内容长度是否超限
if (!empty($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > $maxUploadBytes) {
    $maxSizeMB = round($maxUploadBytes / 1024 / 1024, 2);
    header('Content-Type: application/json');
    echo json_encode(['status'=>413,'message'=>"文件过大,仅允许上传{$maxSizeMB}MB以内的文件。"]);
    exit;
}

方案二:自定义错误处理器捕获警告

注册错误处理器,精准捕获POST内容长度超限的警告:

// 自定义错误处理器
function uploadErrorHandler($errno, $errstr) {
    if (strpos($errstr, 'POST Content-Length') !== false && strpos($errstr, 'exceeds the limit') !== false) {
        // 从警告信息中提取允许的最大字节数
        preg_match('/limit of (\d+) bytes/', $errstr, $matches);
        $maxBytes = $matches[1];
        $maxSizeMB = round($maxBytes / 1024 / 1024, 2);
        header('Content-Type: application/json');
        echo json_encode(['status'=>413,'message'=>"文件过大,仅允许上传{$maxSizeMB}MB以内的文件。"]);
        exit;
    }
    // 其他错误交给默认处理器处理
    return false;
}

// 注册错误处理器,仅捕获E_WARNING级别的错误
set_error_handler('uploadErrorHandler', E_WARNING);

3. 整合后的完整代码

将上述逻辑与原有上传代码结合,同时优化错误提示和状态码:

// 辅助函数:将文件大小单位转换为字节
function convertToBytes($size) {
    $unit = strtoupper(substr($size, -1));
    $size = (int)substr($size, 0, -1);
    switch($unit) {
        case 'G': $size *= 1024;
        case 'M': $size *= 1024;
        case 'K': $size *= 1024;
    }
    return $size;
}

// 自定义错误处理器捕获POST内容长度超限警告
function uploadErrorHandler($errno, $errstr) {
    if (strpos($errstr, 'POST Content-Length') !== false && strpos($errstr, 'exceeds the limit') !== false) {
        preg_match('/limit of (\d+) bytes/', $errstr, $matches);
        $maxBytes = $matches[1];
        $maxSizeMB = round($maxBytes / 1024 / 1024, 2);
        header('Content-Type: application/json');
        echo json_encode(['status'=>413,'message'=>"文件过大,仅允许上传{$maxSizeMB}MB以内的文件。"]);
        exit;
    }
    return false;
}
set_error_handler('uploadErrorHandler', E_WARNING);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    header('Content-Type: application/json');

    // 检查文件是否存在(处理文件过大导致$_FILES为空的情况)
    if (!isset($_FILES['file_data']) || empty($_FILES['file_data'])) {
        $maxSizeMB = round(convertToBytes(ini_get('upload_max_filesize')) / 1024 / 1024, 2);
        echo json_encode(['status'=>413,'message'=>"文件过大,仅允许上传{$maxSizeMB}MB以内的文件。"]);
        exit;
    }

    $asset = $_FILES['file_data'];
    $assetName = $asset['name'];
    $assetError = $asset['error'];
    $assetTemp = $asset['tmp_name'];

    $uploadPath = dirname(__DIR__, 1).'/uploads/';
    $extensionsAllowed = ['png','jpg','jpeg','tiff','tif','webp','mp4','mp3','acc'];
    $fileExtension = strtolower(pathinfo($assetName, PATHINFO_EXTENSION));

    // 检查文件扩展名
    if (!in_array($fileExtension, $extensionsAllowed)) {
        echo json_encode(['status'=>415,'message'=>'不支持该文件格式,请上传指定类型的文件。']);
        exit;
    }

    // 处理其他上传错误
    if ($assetError !== UPLOAD_ERR_OK) {
        $errorMsg = match($assetError) {
            UPLOAD_ERR_INI_SIZE => '文件超过服务器允许的最大大小',
            UPLOAD_ERR_FORM_SIZE => '文件超过表单允许的最大大小',
            UPLOAD_ERR_PARTIAL => '文件仅部分上传',
            UPLOAD_ERR_NO_FILE => '未选择文件',
            default => '文件上传失败'
        };
        echo json_encode(['status'=>400,'message'=>$errorMsg]);
        exit;
    }

    if(is_uploaded_file($assetTemp)) {
        if(move_uploaded_file($assetTemp, $uploadPath . $assetName)) {
            echo json_encode(['status'=>200,'message'=>'成功上传文件:'.$assetName]);
            exit;
        } else {
            echo json_encode(['status'=>500,'message'=>'无法保存文件到服务器']);
            exit;
        }
    } else {
        echo json_encode(['status'=>400,'message'=>'文件上传验证失败']);
        exit;
    }
}

关键说明

  • 使用HTTP状态码413(Payload Too Large)表示请求实体过大,比400状态码更精准。
  • 自定义错误处理器直接拦截PHP生成的警告,确保错误发生时立即返回友好提示。
  • 增加$_FILES空值判断,覆盖文件过大导致的空数组场景。
  • 补充对$_FILES['error']的枚举处理,覆盖更多上传错误场景。

内容的提问来源于stack exchange,提问作者dctech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:09:51