preface
This article is short, about 5 minutes, and tends to be practical rather than analytical.
background
There is an upload function in a small project. Because it is small, there is no verification on the back end this time. Check all to the front end, test a case is: change the suffix of the file can bypass upload. Out of confidence in Antd, I gave QA a pat on the chest to say yes. Results found that in fact not, in order not to be disS, tried to complete this function.
why
After the file type is changed, the browser changes the corresponding file.type as well. File. type in the following code can be determined by the suffix at the end of the file.
/ / the official demo
function beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if(! isJpgOrPng) { message.error('You can only upload JPG/PNG file! ');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if(! isLt2M) { message.error('Image must smaller than 2MB! ');
}
return isJpgOrPng && isLt2M;
}
Copy the code
The solution
The core implementation is to read the file through binary and verify the first 4 bits of the real file content in hexadecimal. The files that are allowed to be uploaded in this code are of XLSX type. The binary headers of other files can be found by themselves, such as the file type corresponding to the binary header bytes.
getFileMimeType: (file) = > {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
return new Promise((resolve, reject) = > {
reader.onload = (event) = > {
try {
let buffer = [...Buffer.from(event.target.result)];
// Just the first four digits of the file are enough
buffer = buffer.splice(0.4);
buffer.forEach((num, i, arr) = > {
arr[i] = num.toString(16).padStart(2.'0');
});
// 504b0304 is the XLSX header
resolve(buffer.join(' ') = = ='504b0304');
} catch (e) {
// Error reading file header Default is not a valid file typereject(); }}; }); }Copy the code
Next up is the beforeUpload of the Antd Upload component, with minor modifications to the official demo
beforeUpload: (file) = > {
return new Promise(async (resolve, reject) => {
const isExcel = await getFileMimeType(file); // Call the above code
if(! isExcel) { message.error('Upload failed! Only files of type XLSX are supported.);
reject();
}
const isLt10M = file.size / 1024 / 1024 < 10;
if(! isLt10M) { message.error('Upload file cannot exceed 10MB! ');
reject();
}
resolve();
});
}
Copy the code
Pay attention to the point
- ReadAsArrayBuffer is asynchronous, so individuals are converted into promises for synchronous writing
- In the beginning beforeUpload is written directly like this:
beforeUpload: async (file) => {
const isExcel = await getFileMimeType(file); // Call the above code
if(! isExcel) { message.error('Upload failed! Only files of type XLSX are supported.);
return false;
}
const isLt10M = file.size / 1024 / 1024 < 10;
if(! isLt10M) { message.error('Upload file cannot exceed 10MB! ');
return false;
}
return true;
}
Copy the code
Files will always upload successfully with this writing, so modify the beforeUpload to return a Promise.