应使用pathinfo($filename, PATHINFO_EXTENSION)提取小写扩展名并校验白名单:先basename()清洗文件名,再转小写,最后用array_key_exists()在键值白名单中快速校验,空扩展名或非法字符一律拒绝。

需要在PHP中快速验证上传文件或本地文件的扩展名是否符合预设的安全白名单,避免因后缀校验不严导致任意文件上传漏洞。
获取文件后缀名
使用 pathinfo() 提取扩展名,这是最可靠的方式——它基于路径解析,不依赖文件内容或系统配置。
调用 pathinfo($filename, PATHINFO_EXTENSION) 返回小写扩展名字符串,例如 'jpg'、'pdf';若无后缀则返回空字符串。
注意:不要用 substr(strrchr($filename, '.'), 1),该方式在文件名含多个点(如 archive.tar.gz)时会错误截取 'tar.gz' 而非 'gz'。
立即学习“PHP免费学习笔记(深入)”;
定义并校验白名单
方法一:用 in_array() 直接比对
先将白名单声明为索引数组,如 $whitelist = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];再用 in_array(strtolower(pathinfo($filename, PATHINFO_EXTENSION)), $whitelist) 判断。
方法二:用 array_key_exists() 提升性能
把白名单转为键值数组:$whitelist = ['jpg' => true, 'jpeg' => true, 'png' => true, 'gif' => true, 'pdf' => true];然后检查 array_key_exists(strtolower(pathinfo($filename, PATHINFO_EXTENSION)), $whitelist)。
这一步更快,尤其当白名单较大时,避免了遍历搜索。
处理边界情况
第一步:过滤空后缀和非法字符
如果 pathinfo() 返回空字符串,说明文件无扩展名,应直接拒绝——【空后缀默认不在白名单内,不可跳过校验】。
第二步:剥离可能存在的 URL 查询参数或路径干扰
若 $filename 来自 $_FILES['file']['name'] 或用户输入,需先用 basename() 清洗:$cleanName = basename($filename);否则攻击者可能传入 'shell.php?xxx.jpg',pathinfo() 会误判为 'jpg'。
第三步:统一转小写再比对
Windows 文件系统不区分大小写,但 PHP 的 in_array() 默认区分,所以必须对提取的扩展名调用 strtolower(),否则 'JPG' 会被判为非法。



















