最安全的php文件扩展名校验是严格拒绝非法后缀:用pathinfo()提取扩展名并转小写,检查空值与非法字符后,硬编码白名单+in_array(true)精确匹配;再通过finfo_file()校验真实mime类型,重命名时弃用原文件名。

校验PHP文件扩展名类型,核心不是“识别”,而是“拒绝非法后缀”——因为合法扩展名必须由你明确指定,不能依赖用户输入或自动推断。最安全的做法是提取后缀后,严格比对硬编码白名单。
用 pathinfo() 提取并统一转小写
直接从完整文件名中取最后一段点号后的部分,不拼接、不截断、不信任原始字符串:
- 调用 pathinfo($filename, PATHINFO_EXTENSION) 获取扩展名,它能正确处理
.env、archive.tar.gz(返回gz)等边界情况 - 立即用 strtolower() 转为小写,避免
JPG和jpg被当成两个不同值 - 检查结果是否为空或含非法字符(如
\0、/、..),空或异常则直接拒绝
白名单必须硬编码且精确匹配
允许哪些扩展名,必须写死在代码里或从可信配置加载,不能来自数据库、URL参数或表单字段:
- 例如:$allowed = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt']
- 用 in_array($ext, $allowed, true) 严格全等判断,第三个参数
true防止数字类型混淆 - 不要用
substr、strpos或正则模糊匹配,比如strpos($ext, 'jpg')会误放行jpgx
不能只靠扩展名,必须配合真实内容校验
扩展名只是第一道过滤,攻击者可上传 shell.php.jpg 绕过——此时 pathinfo 返回 jpg,但文件真实内容是 PHP。所以:
- 扩展名校验通过后,必须用 finfo_file() 读取临时文件头,获取真实 MIME 类型
- 再查 MIME 白名单,例如
image/jpeg→ 允许,application/x-php→ 拒绝 - 最终保存时,**丢弃原始文件名全部内容**,用
uniqid() . '.' . $safe_ext重命名,其中$safe_ext来自 MIME 映射表(如'image/png' => 'png')
特别注意隐藏文件和双后缀陷阱
.env、.htaccess 这类以点开头的文件,pathinfo() 仍能正确返回 env 或 htaccess;但它们常被用于配置泄露或解析绕过,建议:
- 若业务不需要上传隐藏文件,可在提取扩展名后加一层判断:str_starts_with($filename, '.'),命中即拦截
- 对
shell.php.jpg这类双后缀,pathinfo()只取最右一段,这是优点而非缺陷——你要的就是它不被干扰 - 绝对不要用
substr(strrchr($filename, '.'), 1)替代pathinfo,前者易被shell.php\0.jpg等空字节绕过
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











