唯一可靠方式是用finfo_file()读取临时文件二进制头校验真实mime类型,必须使用fileinfo_mime_type模式、校验$_files'file'合法性、白名单精确匹配完整字符串(如'image/png'),并配合安全重命名与存储隔离。

PHP 7.4 文件类型检测不能只靠 $_FILES['file']['type'],它完全由客户端控制,极易被篡改。真正可靠的方式是用 finfo_file() 读取临时文件二进制头,结合白名单和路径安全策略,才能守住上传入口。
用 finfo_file() 做真实 MIME 校验
这是唯一可信的校验手段,绕过成本高、结果稳定:
- 必须调用
finfo_open(FILEINFO_MIME_TYPE)—— 不能用FILEINFO_MIME,否则返回带编码的字符串(如image/jpeg; charset=binary),比对会失败 - 校验目标必须是
$_FILES['file']['tmp_name'],且要先确认该路径存在、是合法上传临时文件,避免空值或路径遍历导致读取任意文件 - 白名单匹配必须是完整 MIME 字符串,例如
'image/png',不能只写'png'或模糊匹配子串 - 上线前务必检查
extension_loaded('fileinfo'),老旧环境可能未启用该扩展
别单独依赖 exif_imagetype()
它快但太浅,仅看文件头几个字节(如 JPEG 的 FF D8 FF),无法识别拼接型恶意文件:
- 攻击者用
cat good.jpg bad.php > evil.jpg就能绕过 - 对 SVG 完全无效 —— 不解析 XML 结构,必须回退到
finfo_file()或内容扫描 -
false不代表非法,可能是合法但不支持的格式(比如含扩展块的 GIF) - 建议仅作初筛:先快速排除明显非图文件,再交由
finfo_file()终审
重命名与存储必须彻底隔离
原始文件名一个字符都不能留,否则攻击者可构造 shell.php.jpg 欺骗后缀提取逻辑:
- 新文件名推荐生成方式:
uniqid('up_') . bin2hex(random_bytes(8)),再拼上由 MIME 映射来的固定后缀(如image/svg+xml → '.svg') - 映射表必须严格一一对应:
'image/gif' => '.gif',拒绝非标准 MIME(如'image/x-png') - 文件名中禁止出现
..、/、\0、控制字符;清洗不如彻底不用,若真需清洗可用preg_replace('/[^a-zA-Z0-9._-]/', '', $basename)
move_uploaded_file() 前必须验证目标路径
PHP 7.4 的 move_uploaded_file() 不自动建目录、不报错,静默返回 false 是常见故障根源:
- 必须用
is_dir($targetDir) && is_writable($targetDir)双重判断,缺一不可 - Linux 下上传目录(如
public/uploads)必须有执行位(x),否则 Web 服务器无法进入创建文件 ——chmod 0755是底线,0644会导致静默失败 - 确保 Web 进程用户(如
www-data或apache)拥有该目录所有权:chown -R www-data:www-data public/uploads -
$file->move($savePath)中的$savePath必须过滤路径穿越,禁用用户传入的原始名拼接路径
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











