File upload is a very common function in daily work. In some cases, we want to limit the type of file that can be uploaded, such as limiting the upload to PNG images. To solve this problem, we would consider using the Accept attribute of the input element to restrict the type of file that can be uploaded:

<input type="file" id="inputFile" accept="image/png" />
Copy the code

This works for most scenarios, but users can overcome this limitation if they change the JPEG image suffix to.png. So how do you solve this problem? In fact, we can identify the correct file type by reading the binary data of the file. Before introducing the specific implementation scheme, a baoge first to picture type file as an example, to introduce the relevant knowledge.

How to view the binary data of the picture

To view the binary data for an image, there are ready-made editors like WinHex for Windows or Synalyze It! For macOS. Pro hexadecimal editor. Here we use Synalyze It! Pro this editor, in the form of hexadecimal to view a brother’s image corresponding binary data.

Pay attention to “the road to immortal in full stack” to read four free e-books and more than 50 TS series tutorials.

Two, how to distinguish the types of pictures

Computers do not distinguish between different types of images by their suffix names, but by their “Magic Number.” For certain types of files, the first few bytes are fixed, and the type of file can be determined by the contents of these bytes.

The magic numbers for common image types are shown in the following table:

The file type The file suffix The magic number
JPEG jpg/jpeg 0xFF D8 FF
PNG png 0x89 50 4E 47 0D 0A 1A 0A
GIF gif 0x47 49 46 38 (GIF8)
BMP bmp 0x42 4D

Also use Synalyze It! Pro to verify that the type of abao.png is correct:

From the figure above, the first 8 bytes of a PNG image are 0x89 50 4E 47 0D 0A 1A 0A. PNG file to abao.jpeg, and then open the editor to view the binary content of the image, you will find that the first 8 bytes of the file remain the same. If you use the input[type=”file”] input box to read the file information, it will output the following:

Obviously the correct file type cannot be identified by the file name extension or the MIME type of the file. Next, I’ll show you how to read the binary information of an image to ensure the correct image type when uploading it.

Three, how to detect the type of picture

3.1 Defining the readBuffer function

After obtaining the file object, we can use the FileReader API to read the contents of the file. Since we don’t need to read the entire file, Apog encapsulates a readBuffer function that reads a specified range of binary data in the file.

function readBuffer(file, start = 0, end = 2) {
  return new Promise((resolve, reject) = > {
    const reader = new FileReader();
    reader.onload = () = > {
      resolve(reader.result);
    };
    reader.onerror = reject;
    reader.readAsArrayBuffer(file.slice(start, end));
  });
}
Copy the code

For PNG type images, the first 8 bytes of the file are 0x89 50 4E 47 0D 0A 1A 0A. Therefore, when detecting whether the selected file is a PNG image, we only need to read the first 8 bytes of data and determine whether the content of each byte is consistent one by one.

3.2 Defining the check function

In order to achieve byte by byte alignment and enable better reuse, Apog defines a check function:

function check(headers) {
  return (buffers, options = { offset: 0 }) = >
    headers.every(
      (header, index) = > header === buffers[options.offset + index]
    );
}
Copy the code

3.3 Detecting the PNG image type

Based on the readBuffer and check functions defined earlier, we can implement the function of PNG image detection:

3.3.1 HTML code
<div>Select file:<input type="file" id="inputFile" accept="image/*"
              onchange="handleChange(event)" />
   <p id="realFileType"></p>
</div>
Copy the code
3.3.2 rainfall distribution on 10-12 JS code
const isPNG = check([0x89.0x50.0x4e.0x47.0x0d.0x0a.0x1a.0x0a]); // The magic number of the PNG image
const realFileElement = document.querySelector("#realFileType");

async function handleChange(event) {
  const file = event.target.files[0];
  const buffers = await readBuffer(file, 0.8);
  const uint8Array = new Uint8Array(buffers);
  realFileElement.innerText = `${file.name}The file type is:${
    isPNG(uint8Array) ? "image/png" : file.type
  }`;
}
Copy the code

After the above example is successfully run, the corresponding detection result is as shown in the figure below:

As you can see from the figure above, we have successfully detected the correct image format. If you want to detect JPEG files, you only need to define an isJPEG function:

const isJPEG = check([0xff.0xd8.0xff])
Copy the code

However, what if you want to test other types of files, such as PDF files? Here we start with Synalyze It! Pro editor to view the binary content of the PDF file:

Looking at the figure above, we can see that the first four bytes of the PDF file are 0x25 50 44 46, and the corresponding string is %PDF. To make it more intuitive for the user to identify the type being detected, Apogo defines a stringToBytes function:

function stringToBytes(string) {
  return [...string].map((character) = > character.charCodeAt(0));
}
Copy the code

Based on the stringToBytes function, we can easily define an isPDF function as follows:

const isPDF = check(stringToBytes("%PDF"));
Copy the code

With the isPDF function, you will be able to detect PDF files. However, in the actual work, encountered a variety of file types, for this case, you can use a ready-made third library to implement the function of file detection, such as file-type library.

In fact, based on the binary data of the file, in addition to the type of the file can be detected, we can also read the file related meta information, such as the size of the image, bit depth, color type and compression algorithm, etc., we continue to take abao.png as an example, to see the actual situation:

Ok, so much for detecting file types on the front end. In actual projects, for file upload scenarios, for security reasons, it is recommended that partners limit the type of file upload during the development process. For more stringent scenarios, consider using the method described in Apo to verify file types. In addition, if you are interested in how the front-end handles binary data you can read play with front-end binary.

Pay attention to the “full stack of the road to repair the immortal” to read a baoge original 4 free e-books (accumulated downloads of 30 thousand +) and 11 Vue 3 advanced series tutorial. If you want to learn TS/Vue 3.0 together, you can add Semlinker on wechat.

Iv. Reference Resources

  • Play with front-end binaries
  • MDN – FileReader