I have read this and this questions which seems to suggest that the file MIME type could be checked using javascript on client side. Now, I understand that the real validati
Here is a Typescript implementation that supports webp. This is based on the JavaScript answer by Vitim.us.
interface Mime {
mime: string;
pattern: (number | undefined)[];
}
// tslint:disable number-literal-format
// tslint:disable no-magic-numbers
const imageMimes: Mime[] = [
{
mime: 'image/png',
pattern: [0x89, 0x50, 0x4e, 0x47]
},
{
mime: 'image/jpeg',
pattern: [0xff, 0xd8, 0xff]
},
{
mime: 'image/gif',
pattern: [0x47, 0x49, 0x46, 0x38]
},
{
mime: 'image/webp',
pattern: [0x52, 0x49, 0x46, 0x46, undefined, undefined, undefined, undefined, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50],
}
// You can expand this list @see https://mimesniff.spec.whatwg.org/#matching-an-image-type-pattern
];
// tslint:enable no-magic-numbers
// tslint:enable number-literal-format
function isMime(bytes: Uint8Array, mime: Mime): boolean {
return mime.pattern.every((p, i) => !p || bytes[i] === p);
}
function validateImageMimeType(file: File, callback: (b: boolean) => void) {
const numBytesNeeded = Math.max(...imageMimes.map(m => m.pattern.length));
const blob = file.slice(0, numBytesNeeded); // Read the needed bytes of the file
const fileReader = new FileReader();
fileReader.onloadend = e => {
if (!e || !fileReader.result) return;
const bytes = new Uint8Array(fileReader.result as ArrayBuffer);
const valid = imageMimes.some(mime => isMime(bytes, mime));
callback(valid);
};
fileReader.readAsArrayBuffer(blob);
}
// When selecting a file on the input
fileInput.onchange = () => {
const file = fileInput.files && fileInput.files[0];
if (!file) return;
validateImageMimeType(file, valid => {
if (!valid) {
alert('Not a valid image file.');
}
});
};