PHP上传文件类型限制必须用finfo_file()校验真实MIME类型并比对白名单,再结合小写扩展名白名单双重验证,禁用$_FILES['type'],强制重命名且上传目录禁PHP执行。

PHP 上传文件类型限制不是靠前端或简单判断后缀就能保障安全的,必须结合 $_FILES 的 type(不靠谱)、tmp_name(需校验)和服务器端 MIME 检测 + 后缀白名单双重控制。核心修复点是:禁用信任客户端传来的 type,改用 finfo_file() 读取真实文件头信息,并与配置的允许类型严格比对。
1. 配置可上传的 MIME 类型白名单
在 PHP 文件顶部或配置文件中定义明确、最小化的允许类型列表,避免使用模糊通配符(如 image/*):
$allowed_mimes = [
'image/jpeg',
'image/png',
'image/gif',
'application/pdf',
'text/plain',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
];2. 使用 finfo 读取真实 MIME 类型(关键步骤)
$_FILES['file']['type'] 可被客户端伪造,必须丢弃。用 finfo_open() 基于文件内容检测真实类型:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$real_mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
<p>if (!in_array($real_mime, $allowed_mimes)) {
die('不支持的文件类型:' . htmlspecialchars($real_mime));
}</p>3. 补充后缀白名单 + 安全重命名
即使 MIME 正确,也要检查扩展名是否匹配,并强制生成安全文件名:
$uploaded_ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt', 'doc', 'docx'];
<p>if (!in_array($uploaded_ext, $allowed_extensions)) {
die('不支持的文件扩展名');
}</p><p>$safe_filename = uniqid() . '.' . $uploaded_ext;
$upload_path = '/var/www/uploads/' . $safe_filename;</p>4. 完整上传处理示例(含错误处理)
整合以上逻辑,加上基础校验(大小、错误码、目录权限):
<?php $upload_dir = '/var/www/uploads/';
$allowed_mimes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
<p>if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];<pre class="brush:php;toolbar:false;">if ($file['error'] !== UPLOAD_ERR_OK) {
die('上传失败:' . $file['error']);
}
if ($file['size'] > 5 * 1024 * 1024) { // 5MB 限制
die('文件不能超过 5MB');
}
// 检查扩展名
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_exts)) {
die('不支持的扩展名:' . htmlspecialchars($ext));
}
// 检查真实 MIME
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, $allowed_mimes)) {
die('不支持的文件类型(MIME 不匹配):' . htmlspecialchars($mime));
}
// 安全保存
$safe_name = uniqid() . '.' . $ext;
$target = $upload_dir . $safe_name;
if (move_uploaded_file($file['tmp_name'], $target)) {
echo '上传成功:' . htmlspecialchars($safe_name);
} else {
die('保存文件失败,请检查目录权限');
}} ?>
注意:确保 /var/www/uploads/ 目录存在、可写,且 Web 服务器(如 Nginx/Apache)**禁止直接执行 PHP 文件**(可通过配置拒绝对 uploads 目录下 .php 文件的解析)。不复杂但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











