PHP文件上传如何限制大小

wen PHP项目 3

本文目录导读:

PHP文件上传如何限制大小

  1. PHP配置层面(最核心)
  2. 代码层面验证(前端+后端)
  3. 前端实时验证(JavaScript)
  4. Nginx配置限制(如果使用Nginx)
  5. 服务端汇总检查Code
  6. ⚠️ 注意事项

在PHP中限制文件上传大小,需要在多个层面进行配置,以下是完整的解决方案:

PHP配置层面(最核心)

php.ini 配置

; 单个上传文件的最大大小
upload_max_filesize = 10M
; POST数据最大大小(通常要比upload_max_filesize大)
post_max_size = 12M
; 允许的最大上传文件数量
max_file_uploads = 20
; 脚本执行时间(秒)
max_execution_time = 300
; 内存限制
memory_limit = 128M

通过 .htaccess 配置(Apache)

# 限制文件上传大小为10MB
php_value upload_max_filesize 10M
php_value post_max_size 12M
php_value max_execution_time 300
php_value memory_limit 128M

通过代码动态设置

// 在脚本开头设置
ini_set('upload_max_filesize', '10M');
ini_set('post_max_size', '12M');
ini_set('max_execution_time', 300);
ini_set('memory_limit', '128M');

代码层面验证(前端+后端)

HTML表单限制

<form action="upload.php" method="post" enctype="multipart/form-data">
    <!-- PHP预定义隐藏字段,必须在其他表单字段之前 -->
    <input type="hidden" name="MAX_FILE_SIZE" value="10485760" />
    <input type="file" name="file" />
    <input type="submit" value="上传" />
</form>

后端PHP验证

<?php
// 定义上传限制
define('MAX_FILE_SIZE', 10 * 1024 * 1024); // 10MB
define('ALLOWED_TYPES', ['jpg', 'jpeg', 'png', 'gif', 'pdf']);
define('UPLOAD_PATH', './uploads/');
// 检查是否有文件上传
if (!isset($_FILES['file'])) {
    die('没有文件被上传');
}
$file = $_FILES['file'];
// 错误检查
if ($file['error'] !== UPLOAD_ERR_OK) {
    $errorMessages = [
        UPLOAD_ERR_INI_SIZE => '文件大小超过PHP配置限制',
        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 => '文件上传被扩展阻止'
    ];
    $errorCode = $file['error'];
    if (isset($errorMessages[$errorCode])) {
        die($errorMessages[$errorCode]);
    } else {
        die('未知错误');
    }
}
// 文件大小验证(双保险)
if ($file['size'] > MAX_FILE_SIZE) {
    die('文件大小超过10MB限制');
}
// 检查文件类型
$fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($fileExtension, ALLOWED_TYPES)) {
    die('文件类型不允许');
}
// 检查文件MIME类型
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
$allowedMimes = [
    'image/jpeg' => 'jpg',
    'image/png' => 'png',
    'image/gif' => 'gif',
    'application/pdf' => 'pdf'
];
if (!array_key_exists($mimeType, $allowedMimes)) {
    die('文件MIME类型不允许');
}
// 安全检查 - 避免文件类型伪造
if ($allowedMimes[$mimeType] !== $fileExtension) {
    die('文件扩展名与实际类型不匹配');
}
// 生成唯一文件名
$newFileName = uniqid('upload_', true) . '.' . $fileExtension;
// 确保上传目录存在
if (!is_dir(UPLOAD_PATH)) {
    mkdir(UPLOAD_PATH, 0755, true);
}
// 移动上传文件
$uploadPath = UPLOAD_PATH . $newFileName;
if (move_uploaded_file($file['tmp_name'], $uploadPath)) {
    echo "文件上传成功!保存为:{$newFileName}";
    echo "文件大小:" . formatFileSize($file['size']) . "<br>";
    echo "文件类型:" . $mimeType . "<br>";
} else {
    die('文件移动失败');
}
// 辅助函数
function formatFileSize($bytes) {
    if ($bytes >= 1073741824) {
        return number_format($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return number_format($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return number_format($bytes / 1024, 2) . ' KB';
    } else {
        return $bytes . ' 字节';
    }
}
?>

前端实时验证(JavaScript)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">文件上传</title>
    <style>
        .error { color: red; }
        .success { color: green; }
    </style>
</head>
<body>
    <form id="uploadForm" action="upload.php" method="post" enctype="multipart/form-data">
        <h3>文件上传(最大10MB)</h3>
        <div>
            <label>选择文件:</label>
            <input type="file" name="file" id="fileInput" accept=".jpg,.jpeg,.png,.gif,.pdf">
        </div>
        <div>
            <span id="fileInfo"></span>
        </div>
        <button type="submit">上传</button>
    </form>
    <script>
        const MAX_SIZE = 10 * 1024 * 1024; // 10MB
        const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
        document.getElementById('fileInput').addEventListener('change', function(e) {
            const file = this.files[0];
            const fileInfo = document.getElementById('fileInfo');
            if (!file) {
                fileInfo.textContent = '';
                return;
            }
            // 检查大小
            if (file.size > MAX_SIZE) {
                fileInfo.textContent = `错误:文件大小 ${formatBytes(file.size)} 超过10MB限制`;
                fileInfo.className = 'error';
                this.value = ''; // 清空选择
                return;
            }
            // 检查类型
            if (!ALLOWED_TYPES.includes(file.type)) {
                fileInfo.textContent = '错误:不支持的文件类型';
                fileInfo.className = 'error';
                this.value = '';
                return;
            }
            // 显示文件信息
            fileInfo.textContent = `文件名:${file.name},大小:${formatBytes(file.size)},类型:${file.type}`;
            fileInfo.className = 'success';
        });
        function formatBytes(bytes) {
            if (bytes >= 1048576) {
                return (bytes / 1048576).toFixed(2) + ' MB';
            } else if (bytes >= 1024) {
                return (bytes / 1024).toFixed(2) + ' KB';
            } else {
                return bytes + ' 字节';
            }
        }
        // 表单提交验证
        document.getElementById('uploadForm').addEventListener('submit', function(e) {
            const fileInput = document.getElementById('fileInput');
            const file = fileInput.files[0];
            if (!file) {
                e.preventDefault();
                alert('请选择文件');
                return;
            }
            if (file.size > MAX_SIZE) {
                e.preventDefault();
                alert('文件大小超过10MB限制');
                return;
            }
        });
    </script>
</body>
</html>

Nginx配置限制(如果使用Nginx)

# 在server或location块中设置
location /upload/ {
    # 限制请求体大小
    client_max_body_size 10m;
    # 限制上传超时时间
    client_body_timeout 60s;
}

服务端汇总检查Code

<?php
class FileUploadValidator {
    private $maxSize;
    private $allowedExtensions;
    private $allowedMimeTypes;
    public function __construct($maxSize = 10485760, $allowedExtensions = [], $allowedMimeTypes = []) {
        $this->maxSize = $maxSize;
        $this->allowedExtensions = $allowedExtensions;
        $this->allowedMimeTypes = $allowedMimeTypes;
    }
    public function validate($file) {
        $errors = [];
        // 检查是否有错误
        if ($file['error'] !== UPLOAD_ERR_OK) {
            $errors[] = $this->getUploadErrorMessage($file['error']);
            return $errors;
        }
        // 检查大小
        if ($file['size'] > $this->maxSize) {
            $errors[] = '文件大小超过限制';
        }
        // 检查扩展名
        $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!empty($this->allowedExtensions) && !in_array($ext, $this->allowedExtensions)) {
            $errors[] = '不允许的文件扩展名:' . $ext;
        }
        // 检查MIME类型
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mimeType = $finfo->file($file['tmp_name']);
        if (!empty($this->allowedMimeTypes) && !in_array($mimeType, $this->allowedMimeTypes)) {
            $errors[] = '不允许的MIME类型:' . $mimeType;
        }
        return $errors;
    }
    private function getUploadErrorMessage($errorCode) {
        $messages = [
            UPLOAD_ERR_INI_SIZE => '文件大小超过PHP配置限制',
            UPLOAD_ERR_FORM_SIZE => '文件大小超过表单限制',
            UPLOAD_ERR_PARTIAL => '文件只上传了一部分',
            UPLOAD_ERR_NO_FILE => '没有文件被上传',
            UPLOAD_ERR_NO_TMP_DIR => '找不到临时文件夹',
            UPLOAD_ERR_CANT_WRITE => '文件写入失败',
            UPLOAD_ERR_EXTENSION => '文件上传被扩展阻止'
        ];
        return isset($messages[$errorCode]) ? $messages[$errorCode] : '未知错误';
    }
}
?>

⚠️ 注意事项

  1. 多层限制的重要性:不要只依赖单层限制,前端限制是用户体验,后端限制是安全保证。

  2. 配置调整

    • post_max_size 必须大于 upload_max_filesize
    • 如果上传多个文件,要考虑总大小
    • 内存限制不能小于上传文件大小
  3. 安全建议

    • 不要信任前端限制
    • 始终在服务端进行二次验证
    • 检查文件内容的MIME类型,不要只检查扩展名
    • 将文件存储在Web根目录之外
    • 生成随机文件名,避免路径注入
  4. 查看当前配置

    <?php
    // 查看当前PHP上传配置
    echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . "<br>";
    echo 'post_max_size: ' . ini_get('post_max_size') . "<br>";
    echo 'max_file_uploads: ' . ini_get('max_file_uploads') . "<br>";
    echo 'max_execution_time: ' . ini_get('max_execution_time') . "秒<br>";
    echo 'memory_limit: ' . ini_get('memory_limit') . "<br>";
    ?>

是多层文件上传大小限制的完整解决方案,应该能覆盖大部分场景需求。

抱歉,评论功能暂时关闭!