【JavaScript 】获取真实的文件类型

在系统上传文件时,有用户会直接修改文件名后缀,使其与系统要求一致后再上传,而html+javascript常用的上传文件方法难以判断文件的真实类型(此处也易恶意上传脚本文件的情况)

为此我们可以通过读取文件的二进制数据的前几个字节(通常称为“魔法数字”或文件签名)来尝试识别文件的类型。这些字节通常包含特定的ASCII字符或十六进制值,可以用来区分不同类型的文件格式。

一、代码示例

使用FileReader API读取文件的前几个字节,根据这些字节来确定文件类型:


/**
 * 提取文件类型
 * 文件名后缀可以随意修改,只有在读取的时候才能获取真实的文件类型,以防有人恶意上传不符合的文件
 * 如果返回数据为null则没有匹配到符合的文件名,可能是漏了,也可能是不存在的文件类型,使用时需核查
 *
 * 微软和WPS生成的的word excel ppt等文件码不一致,且没有区分具体文件后缀,所以在判断相应的码后再解析文件名后缀
 * */
export const getFileType = function(row) {
  return new Promise((reslove, reject) => {
    const file = row.file ? row.file : row.raw ? row.raw : row
    const name = row.name || file.name
    // console.log(file)
    const reader = new FileReader()
    reader.onload = evt => {
      let realMimeType = ''
      const arr = new Uint8Array(reader.result).subarray(0, 4)
      // 将截取的result和magic number比较
      let header = ''
      for (let i = 0; i < arr.length; i++) {
        header += arr[i].toString(16)
      }
      // 在这里可以得到上传图片的真实mintype类型
      // 在这里执行你的逻辑,该方法是异步执行
      if (header.indexOf('89504e47') === 0) {
        realMimeType = 'png'
      } else if (header.indexOf('424d') === 0) {
        realMimeType = 'bmp'
      } else if (header.indexOf('ffd8ffe0') === 0 || header.indexOf('ffd8ffe1') === 0 || header.indexOf('ffd8ffe2') === 0 || header.indexOf('ffd8ffe3') === 0) {
        realMimeType = 'jpeg' // JPG/JPEG
      } else if (header.indexOf('25504446') === 0) {
        realMimeType = 'pdf'
      } else if (header.indexOf('504b34') === 0) {
        realMimeType = name.substr(name.lastIndexOf('.')).substr(1).toLowerCase()
      } else if (header.indexOf('d0cf11e0') === 0 || header.indexOf('3c3f786d') === 0) {
        realMimeType = name.substr(name.lastIndexOf('.')).substr(1).toLowerCase()
      } else if (header.indexOf('47494638') === 0) {
        realMimeType = 'gif'
      } else if (header.indexOf('52617221') === 0) {
        realMimeType = 'rar'
      } else if (header.indexOf('57617665') === 0 || header.indexOf('52696666') === 0) {
        realMimeType = 'wav'
      } else if (header.indexOf('41564920') === 0) {
        realMimeType = 'avi'
      } else if (header.indexOf('504b0304') === 0) {
        realMimeType = 'zip'
      } else if (header.indexOf('50415220') === 0) {
        realMimeType = 'par2'
      } else if (header.indexOf('7b5c727466') === 0) {
        realMimeType = 'rtf'
      } else {
        realMimeType = null
      }
      console.log(header, realMimeType)

      reslove(realMimeType)
      // console.log(header, realMimeType)
    }
    reader.readAsArrayBuffer(file)
  })
}

1、使用 new FileReader(),读取将传入的文件转成二进制数据,如果是base64或其他格式可依对应方法转换成二进制数据。

2、使用Uint8Array方法将文件流转化成文件流。

3、依据第0位开始的前几位编码来判断文件类型。

二、几种常见的文件类型编码:

89504e47:png
424d:bmp
ffd8ffe0:jpeg、jpg
ffd8ffe1:jpeg、jpg
ffd8ffe2:jpeg、jpg
ffd8ffe3:jpeg、jpg
25504446:pdf
47494638:gif
52617221:rar
57617665:wav
52696666:wav
41564920:avi
504b0304:zip
50415220:par2
7b5c727466:rtf
504b34:无法判断真实文件名,可依据文件名后缀判断
d0cf11e0:无法判断真实文件名,可依据文件名后缀判断
3c3f786d:无法判断真实文件名,可依据文件名后缀判断

备注:这种方法并不完美,只能检测一些常见的文件类型。某些文件类型可能具有相同的或类似的头部,而且有些文件可能不遵循标准的文件签名,因此这种方法可能无法准确识别所有类型的文件。此外,文件可能被修改或封装在其他格式中,这也会影响检测的准确性。

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值