PHP上传图片校验MIME类型防止伪装文件 PHP

前言

只靠前端扩展名判断上传文件,攻击者可以把 PHP 改成 .jpg 上传并执行。安全做法是校验真实 MIME 和文件头:getimagesize 判断是否真图片,finfo 识别真实类型。本文讲解两层校验、白名单扩展名、重命名存储、拒绝伪装文件的完整代码。

操作步骤

1. 用 getimagesize 判断是否真图片

$img = @getimagesize($_FILES['file']['tmp_name']);
if (!$img) {
    exit('不是有效图片');
}

2. 用 finfo 校验真实 MIME

$finfo = new Finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['file']['tmp_name']);
$allow = ['image/jpeg','image/png','image/gif','image/webp'];
if (!in_array($mime, $allow)) {
    exit('文件类型不允许');
}

3. 同时校验扩展名白名单

$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
$allowExt = ['jpg','jpeg','png','gif','webp'];
if (!in_array($ext, $allowExt)) exit('扩展名不允许');

4. 重命名存储,避免文件名攻击

$newName = uniqid().'.'.$ext;
move_uploaded_file($_FILES['file']['tmp_name'], '/upload/'.$newName);

5. 限制大小

if ($_FILES['file']['size'] > 2*1024*1024) exit('图片过大');

常见坑

  1. 只校验前端传来的扩展名和 MIME,伪造极易绕过。
  2. getimagesize 对 SVG 可能误判,需单独处理。
  3. finfo 扩展未安装导致函数不存在,检查 php.ini。
  4. 上传目录设置可执行权限,伪装脚本被执行,目录关闭执行。
  5. 保留原始文件名,可能含路径穿越或特殊字符。
  6. 不同浏览器上报的 MIME 略有差异,以文件头为准。
  7. 大图未压缩直接存,占用空间过大。

总结

图片上传安全三层:getimagesize 验证真图片、finfo 验证文件头 MIME、扩展名白名单,再重命名存储。前端信息不可信,一切以临时文件的真实内容为准。上传目录禁止执行脚本,大小单独限制。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-11-14 07:19 
'); })();