上传至服务器前如何验证文件是否为归档文件?
验证上传归档文件的可行方案
为什么$my_image['type']不靠谱
浏览器返回的type字段是根据文件名后缀推断的,并非读取文件真实内容,所以RAR这类格式经常会被识别为application/octet-stream,完全不能作为可靠验证依据。
具体验证步骤
1. 文件名后缀初步过滤(第一道防线)
先通过后缀筛选常见归档格式,虽然可以被篡改,但能快速拦截大部分误传:
$allowed_extensions = ['rar', 'zip', '7z', 'tar', 'gz']; $file_ext = strtolower(pathinfo($_FILES['archive']['name'], PATHINFO_EXTENSION)); if (!in_array($file_ext, $allowed_extensions)) { exit('请上传RAR/ZIP/7Z等格式的归档文件'); }
2. 读取文件魔术数字验证真实格式(核心验证)
每种归档格式都有固定的文件头魔术数字,读取临时文件的前几个字节就能判断真实类型,这是最可靠的方式:
$temp_file_path = $_FILES['archive']['tmp_name']; // 读取文件前8字节(足够覆盖主流归档格式的魔术数字) $file_header = file_get_contents($temp_file_path, false, null, 0, 8); $hex_header = bin2hex($file_header); // 主流归档格式的魔术数字(十六进制) $valid_magic_numbers = [ '526172211a0700', // RAR '504b0304', // ZIP '377abcaf271c', // 7Z '7573746172', // TAR '1f8b08' // GZIP ]; $is_valid = false; foreach ($valid_magic_numbers as $magic) { if (str_starts_with($hex_header, $magic)) { $is_valid = true; break; } } if (!$is_valid) { // 删除非法临时文件 unlink($temp_file_path); exit('上传的文件不是合法的归档文件'); }
3. 进阶验证:尝试打开归档文件(高安全要求场景)
如果需要确保归档文件可正常读取,可以用PHP扩展尝试打开,能成功打开则说明是有效归档:
- ZIP格式验证(依赖PHP内置
ZipArchive扩展):
$zip = new ZipArchive(); if ($zip->open($temp_file_path) !== ZipArchive::OK) { unlink($temp_file_path); exit('无效的ZIP归档文件'); } $zip->close();
- RAR格式验证(需安装
rar扩展):
if (!extension_loaded('rar')) { exit('服务器未启用RAR文件支持'); } $rar = RarArchive::open($temp_file_path); if (!$rar) { unlink($temp_file_path); exit('无效的RAR归档文件'); } $rar->close();
注意:所有验证都必须在文件上传到服务器临时目录后执行,前端无法在上传前读取文件内容做真实验证,前端的后缀检查只能作为辅助,不能替代后端验证。
内容的提问来源于stack exchange,提问作者B23
相关产品推荐
相关产品推荐

