图片上传校验图片格式

375 阅读1分钟

问题点: 上传图片时,校验图片格式,通常校验图片后缀,如果是把 其他类型的文件,手动改成图片类型后缀,通过拿文件后缀的方式进行校验,将不会生效

    解决方法,前端通过解析文件格式的方式,拿到文件的 魔术(每个图片文件都有自己单独的魔术),例如 png 
 格式,对应的文件魔术为 '89 50 4E 47',通过校验文件魔术的方式,避免用户手动改后缀上传的情况出现,且
 上传的如果是一个脚本,也会有安全问题

代码

async function isImage (file) {
  let gif = await isGif(file)
  let png = await isPng(file)
  let jpg = await isJpg(file)
  return gif || png || jpg
}
// 判断是否为 jpg | 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'
}
// 将文件转为十六进制字符串
async function 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) // 将文件读取为二进制字符串
  })
}

export default isImage