PHP文件类型白名单的核心是只允许特定扩展名上传,拒绝其他所有类型;必须用pathinfo()提取扩展名并转小写后严格比对白名单,结合finfo_file()校验真实MIME类型,重命名文件并禁用上传目录脚本执行权限。

PHP文件类型白名单的核心是**只允许特定扩展名上传,拒绝其他所有类型**。不能只靠前端判断或简单检查后缀,必须在服务端用可靠方式验证。
1. 用 pathinfo() 提取扩展名并严格比对
避免用 substr(strrchr($filename, '.'), 1) 等易被绕过的写法。推荐使用 pathinfo() 获取扩展名,并转为小写统一处理:
- 获取扩展名:
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); - 定义白名单数组:
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'txt']; - 严格校验:
if (!in_array($ext, $allowed, true)) { die('不支持的文件类型'); }
2. 结合 MIME 类型二次验证(可选但更安全)
仅靠扩展名不够,攻击者可能上传伪装文件(如把 PHP 文件改成 shell.jpg)。可用 finfo_file() 检查真实类型:
- 初始化检测器:
$finfo = finfo_open(FILEINFO_MIME_TYPE); - 获取真实 MIME:
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']); - 按扩展名映射允许的 MIME(例如
jpg→image/jpeg),再比对 - 注意:不要只信任
$_FILES['file']['type'],它由浏览器提供,完全不可信
3. 重命名文件,彻底剥离原始扩展名
上传后不要直接使用用户提交的文件名。生成唯一随机名,再拼上白名单中已确认合法的扩展名:
立即学习“PHP免费学习笔记(深入)”;
- 生成新名:
$newName = uniqid() . '.' . $ext; - 确保目标目录无执行权限(如 Apache 中禁用
php解析) - 保存时用
move_uploaded_file(),而非copy()或file_put_contents()
4. 额外防护建议
白名单只是基础,还需配合其他措施防绕过:
- 上传目录禁止解析 PHP(如 Nginx 中配置
location ~ \.(php|html|js|css)$ { deny all; }) - 检查文件头(如图片是否以
FF D8 FF开头),适合高安全场景 - 限制文件大小、设置超时、记录异常上传行为
- 不依赖 JavaScript 前端校验,它只能提升体验,不能替代服务端检查
白名单本身不复杂,但关键在于每一步都做严实——从提取扩展名、比对、重命名到环境配置,缺一不可。



















