Recently, I made a requirement, which was just a simple picture uploading, but the test showed that the picture uploading was successful, but the picture was put into the product, and there were only two pictures. The original plan was not to solve the problem temporarily, because I could not find the problem. Then the product said it would be better to investigate why.

Later, the test said that the two pictures were directly modified suffixes, so it was not solved. Check the Internet myself, the original file byte stream will have a file type mark at the beginning of the content, in fact, the file stream is the file, change the suffix, the file type mark of the file stream will not be changed.

Generally, front-end uploads are restricted by the accept side of the input and then blocked by the suffix of the file name. I have never used the byte stream to determine the file type. NPM install file-type NPM install file-type NPM install file-type NPM install file-type NPM install file-type NPM install file-type

Detect the file type of a Buffer/Uint8Array/ArrayBuffer

The file type is detected by checking the magic number of the buffer.

This package is for detecting binary-based file formats, not text-based formats like .txt, .csv, .svg, etc.

It also introduces the can detect file, can yourself to look at: www.npmjs.com/package/fil…

Here we try this package with vue:

<input type="file" id="inputFile" @change="handleChange" />

import FileType from 'file-type/browser';
export default defineComponent({
  setup(){
    const handleChange = (e) => {
      const file = e.target.files[0];
      FileType.fromBlob(file).then((res) => {
        console.log(res)
      }, (err) => {
        console.log(err)
      })
    }
    return {
      handleChange
    }
  }
})
Copy the code

The _fromTokenizer in core.js provides all the file types to be detected, so I wrote a demo of PNG and JPG images by referring to the code in it:

<input type="file" onchange="handleChange(event)" /> function handleChange(event) { const file = event.target.files[0]; const reader = new FileReader(); reader.onload = () => { let fileType = typeResult(reader.result); console.log(fileType); }; reader.readAsArrayBuffer(file); } function _check(buffer, headers) { options = { offset: 0 }; for (const [index, header] of headers.entries()) { if (header ! == buffer[index + options.offset]) { return false; } } return true; } function typeResult(arryBUffer) { const buffer = new Uint8Array(arryBUffer); const check = (header, options) => _check(buffer, header); if (check([0xFF, 0xD8, 0xFF])) { return { ext: 'jpg', mime: 'image/jpeg' }; } if (check([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) { return { ext: 'png', mime: 'image/png' }; } return undefined }Copy the code

Testing is possible, because there are many different kinds of detection in PNG, because there is no further understanding of the meaning of byte stream.

case 'IDAT':
  return {
    ext: 'png',
    mime: 'image/png'
  };
case 'acTL':
  return {
    ext: 'apng',
    mime: 'image/apng'
  };
Copy the code

Inside the code also intercept byte stream, and judge two parameters, and determine the beginning of the number, looks very complicated.

Accept (input) : accept (input) : accept (input) : accept (input)

Welcome to the public number coding personal notes