php文件类型校验需分层组合:先用pathinfo()安全提取小写扩展名并白名单校验,再用finfo_file()基于魔数严格比对真实mime,高敏场景可追加手动魔数校验;禁用$_files['type']等不可信字段。

PHP文件类型校验不能只靠一个函数,必须分层组合使用。核心思路是:先提取扩展名做初步过滤,再读取文件内容(魔数或MIME)验证真实类型,两者缺一不可。
pathinfo() —— 安全提取扩展名
这是获取用户上传文件后缀最可靠的方式,它按标准路径规则解析,避免被shell.php.jpg这类双后缀绕过:
- 用
pathinfo($filename, PATHINFO_EXTENSION)拿到最后一段点后的部分(如.tar.gz返回gz) - 务必转小写:
strtolower(),防止JPG和jpg被当成不同类型 - 配合硬编码白名单校验:
in_array($ext, ['jpg', 'png', 'pdf'], true) - 不依赖
$_FILES['file']['name']原始值,因为它完全由客户端控制,可能含空字节、零宽字符等干扰项
finfo_file() —— 基于魔数的真实MIME检测
这是目前最推荐的内容校验方式,通过读取文件头(magic bytes)识别真实类型,无法被后缀或请求头伪造:
- 需先启用
fileinfo扩展(运行php -m | grep fileinfo确认) - 必须作用于临时文件路径:
$_FILES['file']['tmp_name'],不是移动后的路径 - 示例:
$finfo = finfo_open(FILEINFO_MIME_TYPE); $realType = finfo_file($finfo, $tmpPath); finfo_close($finfo); - 比对必须严格:
in_array($realType, ['image/jpeg', 'image/png'], true),禁用strpos($realType, 'image/') === 0等宽松匹配(防image/x-php绕过)
手动读取魔数(fread + 十六进制比对)—— 补充增强校验
对高敏感场景(如配置文件、可执行文件上传),可在finfo基础上加一层文件头字节校验:
- 用
fopen($path, 'rb')打开临时文件,fread($handle, 16)读前16字节 - 转换为十六进制:
bin2hex($bin),再与标准魔数比对 - 例如JPEG必须以
ffd8ff开头,PNG必须以89504e47开头,PDF以25504446(%PDF)开头 - 该方式不依赖扩展,但需维护魔数映射表,适合关键业务兜底
其他函数的注意事项
以下函数不建议单独用于安全校验:
-
$_FILES['file']['type']:来自客户端请求头,可任意篡改,完全不可信 -
mime_content_type():PHP 8.0+ 已废弃,且部分环境行为不稳定 -
getimagesize():仅适用于图像,对视频、PDF等返回false,无法通用分类 -
rename():只是重命名操作,不校验也不转换内容,不能当作类型判断手段
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











