严格判断文件上传类型
注意:前端判断只能是尽量覆盖所有类型,实际上最可靠的还是靠后端判断
前端胖头鱼:遇到一个小米手机文件上传读取不到后缀,当时也尝试用文中的方法,但是难以覆盖全,还是会判断不对。最后还是依赖后端解决的
# 常规类型校验
通常是通过input元素的accept属性来限制文件的类型:
<input id="file" type="file" accept="image/*" />
缺点:可通过浏览器控制台删除 accept 属性,绕过限制
或者通过截取文件名后缀的方式来判断:
const ext = file.name.substring(file.name.lastIndexOf('.') + 1);
缺点:可通过本地修改文件扩展名,绕过限制
但是其实同一种类型的文件,他们的十六进制头信息是完全相同的。可以根据头信息来判断文件类型了。
# 1. 将文件转为十六进制字符串
在获取文件对象后,可以通过FileReader API来读取文件的内容,然后将结果转为Unicode编码,再转为十六进制,以下是封装的将文件转为十六进制字符串的方法:
async blobToString(blob) {
return new Promise(resolve => {
const reader = new FileReader()
reader.onload = function() {
const res = reader.result
.split("") // 将读取结果分割为数组
.map(v => v.charCodeAt()) // 转为 Unicode 编码
.map(v => v.toString(16).toUpperCase()) // 转为十六进制,再转大写
.map(v => v.padStart(2, "0")) // 个位数补0
.join(" "); // 转为字符串
resolve(res)
}
reader.readAsBinaryString(blob) // 将文件读取为二进制字符串
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 2. 判断文件类型
没有必要将整个文件转为十六进制,我们只需要截取文件的前几个字节,然后将截取后的文件转为十六进制,再进行比对就可以了:
// 判断是否为 jpg 格式
async function isJpg(file) {
const res = await blobToString(file.slice(0, 3))
return res === 'FF D8 FF'
}
// 判断是否为 png 格式
async function isPng(file) {
const res = await blobToString(file.slice(0, 4))
return res === '89 50 4E 47'
}
// 判断是否为 gif 格式
async function isGif(file) {
const res = await blobToString(file.slice(0, 4))
return res === '47 49 46 38'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 常用文件的文件头(十六进制)
JPEG (jpg), 文件头:FFD8FF
PNG (png), 文件头:89504E47
GIF (gif), 文件头:47494638
TIFF (tif), 文件头:49492A00
Windows Bitmap ( bmp),文件头:424D
CAD (dwg), 文件头:41433130
Adobe Photoshop (psd), 文件头:38425053
Rich Text Format (rtf), 文件头:7B5C727466
XML (xml), 文件头:3C3F786D6C
HTML (html), 文件头:68746D6C3E
Email [thorough only] (eml), 文件头:44656C69766572792D646174653A
Outlook Express (dbx), 文件头:CFAD12FEC5FD746F
Outlook (pst), 文件头:2142444E
MS Word/Excel (xls.or.doc), 文件头:D0CF11E0
MS Access (mdb), 文件头:5374616E64617264204A
WordPerfect (wpd), 文件头:FF575043
Adobe Acrobat (pdf), 文件头:255044462D312E
Quicken (qdf), 文件头:AC9EBD8F
Windows Password (pwl), 文件头:E3828596
ZIP Archive (zip), 文件头:504B0304
RAR Archive (rar), 文件头:52617221
Wave (wav), 文件头:57415645
AVI (avi), 文件头:41564920
Real Audio (ram), 文件头:2E7261FD
Real Media (rm), 文件头:2E524D46
MPEG (mpg), 文件头:000001BA
MPEG (mpg), 文件头:000001B3
Quicktime (mov), 文件头:6D6F6F76
Windows Media (asf), 文件头:3026B2758E66CF11
MIDI (mid), 文件头:4D546864
- 01
- 2023/07/03 00:00:00
- 02
- 2023/04/22 00:00:00
- 03
- 2023/02/16 00:00:00