php校验上传文件扩展名时,必须用pathinfo($filename, pathinfo_extension)提取后立即strtolower()转换为小写再比对白名单,避免大小写不一致导致绕过;禁用explode或substr等错误方法,因其无法正确解析多点文件名或隐藏文件;还需前置校验空文件名、路径遍历及点开头文件,并用^和$锚定正则确保全匹配。

PHP在处理用户上传文件时,常因扩展名大小写不一致导致白名单校验失败——比如上传IMG.JPG却被判定为非法,只因$pathinfo返回的是原始大写JPG而白名单是小写的['jpg']。
必须对pathinfo返回的扩展名做小写转换
第一步:用pathinfo($filename, PATHINFO_EXTENSION)提取扩展名;
第二步:立即用【strtolower()包裹该结果】,再与白名单比对。
不这样做,'PNG'、'PDF'、'PHP'等大写或混合大小写扩展名会直接被in_array()拒绝。pathinfo本身不标准化大小写,它忠实地返回原始字符串,而你的白名单几乎总是小写数组。
这一步操作起来很简单,直接把pathinfo结果喂给strtolower就行。
别用explode + end截扩展名
方法一:$ext = end(explode('.', $filename)) —— 错误。遇到evil.PHP返回'PHP',大小写未统一;遇到archive.tar.gz返回'gz',漏掉真实类型;遇到README返回'README',根本不是扩展名。
方法二:$ext = substr(strrchr($filename, '.'), 1) —— 更危险。对.gitignore返回'gitignore'(错误),对noext触发PHP警告,对隐藏文件如.htaccess返回'htaccess'(绕过校验)。
【pathinfo是唯一能按标准路径规则解析、天然隔离多点干扰的方式】,且性能开销可忽略。
前置校验防止空扩展名和路径遍历
检查文件名是否为空或含非法字符:
if (empty($filename) || preg_match('/[\/]/', $filename)) { throw new InvalidArgumentException('非法文件名'); }
文件名无点号(如README)→ pathinfo返回空字符串 → in_array('', $allowed)可能意外通过(若白名单里误含空值);
文件名以点开头(如.htaccess)→ pathinfo返回'htaccess' → 完全绕过隐藏文件拦截。
这一步必须放在strtolower之前执行,否则空字符串经strtolower后仍是空,无法区分“真空”和“转小写后的空”。
正则匹配扩展名时加^和$锚定
正确写法:preg_match('/^(jpg|jpeg|png|gif|webp)$/i', $ext)
错误写法:preg_match('/.jpg|png|gif$/i', $filename) —— 它实际等价于/.jpg/或/png/或/gif$/i,logo.png会被中间的'png'子串匹配成功,script.php.bak也可能命中'php'。
扩展名本身不含点,正则里不要带.;【必须用^和$强制全字符串匹配】,否则大小写不敏感也救不了你。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











