J'avais besoin de vérifier d'autres types de fichiers.
Suite à la excellente réponse donné par Drakes j'ai trouvé le code ci-dessous après avoir trouvé ce site web avec un tableau très complet des types de fichiers et de leurs en-têtes. En hexadécimal et en chaîne.
J'avais également besoin d'une fonction asynchrone pour gérer de nombreux fichiers et d'autres problèmes liés au projet sur lequel je travaille et qui n'ont pas d'importance ici.
Voici le code en vanilla javascript.
// getFileMimeType
// @param {Object} the file object created by the input[type=file] DOM element.
// @return {Object} a Promise that resolves with the MIME type as argument or undefined
// if no MIME type matches were found.
const getFileMimeType = file => {
// Making the function async.
return new Promise(resolve => {
let fileReader = new FileReader();
fileReader.onloadend = event => {
const byteArray = new Uint8Array(event.target.result);
// Checking if it's JPEG. For JPEG we need to check the first 2 bytes.
// We can check further if more specific type is needed.
if(byteArray[0] == 255 && byteArray[1] == 216){
resolve('image/jpeg');
return;
}
// If it's not JPEG we can check for signature strings directly.
// This is only the case when the bytes have a readable character.
const td = new TextDecoder("utf-8");
const headerString = td.decode(byteArray);
// Array to be iterated [<string signature>, <MIME type>]
const mimeTypes = [
// Images
['PNG', 'image/png'],
// Audio
['ID3', 'audio/mpeg'],// MP3
// Video
['ftypmp4', 'video/mp4'],// MP4
['ftypisom', 'video/mp4'],// MP4
// HTML
['<!DOCTYPE html>', 'text/html'],
// PDF
['%PDF', 'application/pdf']
// Add the needed files for your case.
];
// Iterate over the required types.
for(let i = 0;i < mimeTypes.length;i++){
// If a type matches we return the MIME type
if(headerString.indexOf(mimeTypes[i][0]) > -1){
resolve(mimeTypes[i][1]);
return;
}
}
// If not is found we resolve with a blank argument
resolve();
}
// Slice enough bytes to get readable strings.
// I chose 32 arbitrarily. Note that some headers are offset by
// a number of bytes.
fileReader.readAsArrayBuffer(file.slice(0,32));
});
};
// The input[type=file] DOM element.
const fileField = document.querySelector('#file-upload');
// Event to detect when the user added files.
fileField.onchange = event => {
// We iterate over each file and log the file name and it's MIME type.
// This iteration is asynchronous.
Array.from(fileField.files, async file => {
console.log(file.name, await getFileMimeType(file));
});
};
Notez que dans la fonction getFileMimeType, vous pouvez utiliser deux approches pour trouver le type MIME correct.
- Recherchez les octets directement.
- Recherche de chaînes de caractères après avoir converti les octets en chaîne de caractères.
J'ai utilisé la première approche avec le JPEG car ce qui le rend identifiable sont les 2 premiers octets et ces octets ne sont pas des caractères lisibles.
Avec le reste des types de fichiers, je pourrais vérifier les signatures de caractères lisibles. Par exemple : [video/mp4] -> 'ftypmp4' ou 'ftypisom'.
Si vous avez besoin de prendre en charge un fichier qui ne figure pas dans la liste de Gary Kessler, vous pouvez consoler.log() les octets ou la chaîne convertie pour trouver une signature appropriée pour le fichier obscur que vous devez prendre en charge.
Note1 : La liste de Gary Kessler a été mise à jour et les signatures mp4 sont différentes maintenant, vous devriez la vérifier lors de l'implémentation. Note2 : le Array.from est conçu pour utiliser une fonction de type .map comme deuxième argument.
6 votes
I want to perform a client side checking to avoid unnecessary wastage of server resource.
Je ne comprends pas pourquoi vous dites que la validation doit être effectuée du côté du serveur, mais dites ensuite que vous voulez réduire les ressources du serveur. Règle d'or : Ne jamais faire confiance aux données de l'utilisateur . Quel est l'intérêt de vérifier le type MIME du côté client si vous le faites ensuite du côté serveur. Il s'agit certainement d'un "gaspillage inutile de ressources". client ressource" ?10 votes
Fournir une meilleure vérification du type de fichier/un meilleur retour d'information aux utilisateurs côté client est une bonne idée. Cependant, comme vous l'avez indiqué, les navigateurs se basent simplement sur les extensions de fichier pour déterminer la valeur de la propriété
type
propriété pourFile
objets. Le code source de webkit, par exemple, révèle cette vérité. Il est possible d'identifier avec précision les fichiers côté client en recherchant, entre autres, des "octets magiques" dans les fichiers. Je travaille actuellement sur une bibliothèque MIT (dans le peu de temps libre dont je dispose) qui fera exactement cela. Si vous êtes intéressé par mes progrès, jetez un coup d'œil à github.com/rnicholus/determinater .54 votes
@IanClark, le fait est que si le fichier est d'un type non valide, je peux le rejeter du côté client plutôt que de gaspiller la bande passante de téléchargement pour ensuite le rejeter du côté serveur.
0 votes
@RayNicholus, cool mec ! Je le regarderai quand j'aurai le temps. Merci :)
0 votes
Etes-vous sûr que votre fichier de test a toujours le mimetype
image/jpeg
et vous ne l'avez pas modifié en changeant l'extension ?0 votes
Le type Mime n'est pas une solution miracle, c'est juste une hypothèse. Les fichiers binaires eux-mêmes ne portent pas cette propriété, il n'y a donc aucun moyen de l'obtenir de manière transparente côté client. Il est défini par les serveurs lorsqu'ils envoient des données aux clients, mais même dans ce cas, il est souvent deviné par l'extension du fichier, ou explicitement défini par les développeurs backend qui savent quel type de contenu ils envoient. fr.wikipedia.org/wiki/Mime_type
1 votes
@QuestionOverflow Un peu tard, mais j'ai ajouté une solution complète et une démo vivante et fonctionnelle dans ma réponse. Profitez-en.