php 8.3 文件类型校验须以 finfo_open(fileinfo_mime_type) 获取真实 mime 类型并比对白名单,辅以文件头魔数(如 jpeg 的 ffd8ff)二次验证,禁用客户端扩展名与 $_files['type'],上传目录需隔离且禁用脚本执行。

PHP 8.3 中做文件类型校验,不能只看扩展名或客户端传来的 $_FILES['file']['type'],这些全可被伪造。真正可靠的方式是读取文件二进制头(magic bytes),用 finfo 函数提取真实 MIME 类型,并与白名单比对。
用 finfo 做内容级 MIME 校验
这是最核心的一环。必须在服务端调用 finfo_open(FILEINFO_MIME_TYPE),传入临时文件路径获取实际类型,而非信任任何用户输入字段。
- 确保
fileinfo扩展已启用(PHP 8.3 默认开启,但需确认) - 白名单只列明确允许的类型,例如:
['image/jpeg', 'image/png', 'application/pdf'] - 显式拒绝危险类型:
text/html、application/x-php、application/x-sh等必须拦截 - 校验失败立即
die()或抛出异常,不继续后续逻辑
扩展名不来自用户,而由 MIME 映射生成
原始文件名中的扩展名不可信,也不能简单用 pathinfo($name, PATHINFO_EXTENSION) 提取后拼接。应根据上一步确认的安全 MIME 类型,映射为固定、安全的扩展名。
- 例如:
image/jpeg → '.jpg',application/pdf → '.pdf' - 避免使用用户提供的后缀,哪怕它看起来“像”jpg —— 攻击者常上传
shell.php.jpg或malicious.png.php - 新文件名中不含任何路径字符(
/、\)、空格或控制符
配合文件头签名(Magic Number)二次验证
MIME 类型校验虽强,但极少数情况下仍可能被特殊构造的文件绕过(如嵌套格式)。对关键类型可追加魔数检查,提升鲁棒性。
- 用
file_get_contents($tmp_name, false, null, 0, 4)读前 4 字节 - JPEG 应以
\xFF\xD8\xFF开头,PNG 是\x89PNG,PDF 是%PDF - 仅对图像、PDF 等有明确魔数的类型启用,不作为通用替代,而是补充层
上传目录与执行权限隔离
即使类型校验全部通过,也必须防止文件被 Web 服务器直接解析执行。
- 上传目录不要放在 Web 根目录下(如
/var/www/html/uploads/),推荐放至根外(如/var/data/uploads/) - 若必须放 Web 可达路径,需在 Web 服务器配置中禁用脚本执行(Nginx 加
location ~ \.(php|sh|pl|py)$ { deny all; };Apache 用php_flag engine off) - Linux 下设置目录权限为
755,文件为644,禁止写+执行组合
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











