Vous pouvez facilement déterminer le type de fichier MIME avec JavaScript FileReader
avant de le télécharger sur un serveur. Je conviens que nous devrions préférer la vérification côté serveur plutôt que côté client, mais la vérification côté client est toujours possible. Je vais vous montrer comment et fournir une démo fonctionnelle en bas.
Vérifiez que votre navigateur prend en charge à la fois File
et Blob
. Tous les principaux devraient.
if (window.FileReader && window.Blob) {
// All the File APIs are supported.
} else {
// File and Blob are not supported
}
Étape 1:
Vous pouvez récupérer les File
informations d'un <input>
élément comme celui-ci ( ref ):
<input type="file" id="your-files" multiple>
<script>
var control = document.getElementById("your-files");
control.addEventListener("change", function(event) {
// When the control has changed, there are new files
var files = control.files,
for (var i = 0; i < files.length; i++) {
console.log("Filename: " + files[i].name);
console.log("Type: " + files[i].type);
console.log("Size: " + files[i].size + " bytes");
}
}, false);
</script>
Voici une version glisser-déposer de ce qui précède ( ref ):
<div id="your-files"></div>
<script>
var target = document.getElementById("your-files");
target.addEventListener("dragover", function(event) {
event.preventDefault();
}, false);
target.addEventListener("drop", function(event) {
// Cancel default actions
event.preventDefault();
var files = event.dataTransfer.files,
for (var i = 0; i < files.length; i++) {
console.log("Filename: " + files[i].name);
console.log("Type: " + files[i].type);
console.log("Size: " + files[i].size + " bytes");
}
}, false);
</script>
Étape 2:
Nous pouvons maintenant inspecter les fichiers et découvrir les en-têtes et les types MIME.
✘ Méthode rapide
Vous pouvez naïvement demander à Blob le type MIME du fichier qu'il représente en utilisant ce modèle:
var blob = files[i]; // See step 1 above
console.log(blob.type);
Pour les images, les types MIME reviennent comme suit:
image / image jpeg
/ png
...
Attention: le type MIME est détecté à partir de l'extension de fichier et peut être trompé ou usurpé. On peut renommer a .jpg
en a .png
et le type MIME sera signalé comme image/png
.
✓ Méthode appropriée d'inspection de l'en-tête
Pour obtenir le type MIME de bonne foi d'un fichier côté client, nous pouvons aller plus loin et inspecter les premiers octets du fichier donné pour les comparer aux soi-disant nombres magiques . Soyez averti que ce n'est pas tout à fait simple car, par exemple, JPEG a quelques «nombres magiques». C'est parce que le format a évolué depuis 1991. Vous pourriez vous en tirer en ne vérifiant que les deux premiers octets, mais je préfère vérifier au moins 4 octets pour réduire les faux positifs.
Exemple de signatures de fichier JPEG (4 premiers octets):
FF D8 FF E0 (SOI + ADD0)
FF D8 FF E1 (SOI + ADD1)
FF D8 FF E2 (SOI + ADD2)
Voici le code indispensable pour récupérer l'en-tête du fichier:
var blob = files[i]; // See step 1 above
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
var header = "";
for(var i = 0; i < arr.length; i++) {
header += arr[i].toString(16);
}
console.log(header);
// Check the file signature against known types
};
fileReader.readAsArrayBuffer(blob);
Vous pouvez ensuite déterminer le type MIME réel comme ceci (plus de signatures de fichiers ici et ici ):
switch (header) {
case "89504e47":
type = "image/png";
break;
case "47494638":
type = "image/gif";
break;
case "ffd8ffe0":
case "ffd8ffe1":
case "ffd8ffe2":
case "ffd8ffe3":
case "ffd8ffe8":
type = "image/jpeg";
break;
default:
type = "unknown"; // Or you can use the blob.type as fallback
break;
}
Acceptez ou rejetez les téléchargements de fichiers à votre guise en fonction des types MIME attendus.
Démo
Voici une démo fonctionnelle pour les fichiers locaux et distants (j'ai dû contourner CORS juste pour cette démo). Ouvrez l'extrait de code, exécutez-le et vous devriez voir trois images distantes de types différents affichés. En haut, vous pouvez sélectionner une image locale ou un fichier de données, et la signature du fichier et / ou le type MIME seront affichés.
Notez que même si une image est renommée, son vrai type MIME peut être déterminé. Voir ci-dessous.
Capture d'écran
// Return the first few bytes of the file as a hex string
function getBLOBFileHeader(url, blob, callback) {
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
var header = "";
for (var i = 0; i < arr.length; i++) {
header += arr[i].toString(16);
}
callback(url, header);
};
fileReader.readAsArrayBuffer(blob);
}
function getRemoteFileHeader(url, callback) {
var xhr = new XMLHttpRequest();
// Bypass CORS for this demo - naughty, Drakes
xhr.open('GET', '//cors-anywhere.herokuapp.com/' + url);
xhr.responseType = "blob";
xhr.onload = function() {
callback(url, xhr.response);
};
xhr.onerror = function() {
alert('A network error occurred!');
};
xhr.send();
}
function headerCallback(url, headerString) {
printHeaderInfo(url, headerString);
}
function remoteCallback(url, blob) {
printImage(blob);
getBLOBFileHeader(url, blob, headerCallback);
}
function printImage(blob) {
// Add this image to the document body for proof of GET success
var fr = new FileReader();
fr.onloadend = function() {
$("hr").after($("<img>").attr("src", fr.result))
.after($("<div>").text("Blob MIME type: " + blob.type));
};
fr.readAsDataURL(blob);
}
// Add more from http://en.wikipedia.org/wiki/List_of_file_signatures
function mimeType(headerString) {
switch (headerString) {
case "89504e47":
type = "image/png";
break;
case "47494638":
type = "image/gif";
break;
case "ffd8ffe0":
case "ffd8ffe1":
case "ffd8ffe2":
type = "image/jpeg";
break;
default:
type = "unknown";
break;
}
return type;
}
function printHeaderInfo(url, headerString) {
$("hr").after($("<div>").text("Real MIME type: " + mimeType(headerString)))
.after($("<div>").text("File header: 0x" + headerString))
.after($("<div>").text(url));
}
/* Demo driver code */
var imageURLsArray = ["http://media2.giphy.com/media/8KrhxtEsrdhD2/giphy.gif", "http://upload.wikimedia.org/wikipedia/commons/e/e9/Felis_silvestris_silvestris_small_gradual_decrease_of_quality.png", "http://static.giantbomb.com/uploads/scale_small/0/316/520157-apple_logo_dec07.jpg"];
// Check for FileReader support
if (window.FileReader && window.Blob) {
// Load all the remote images from the urls array
for (var i = 0; i < imageURLsArray.length; i++) {
getRemoteFileHeader(imageURLsArray[i], remoteCallback);
}
/* Handle local files */
$("input").on('change', function(event) {
var file = event.target.files[0];
if (file.size >= 2 * 1024 * 1024) {
alert("File size must be at most 2MB");
return;
}
remoteCallback(escape(file.name), file);
});
} else {
// File and Blob are not supported
$("hr").after( $("<div>").text("It seems your browser doesn't support FileReader") );
} /* Drakes, 2015 */
img {
max-height: 200px
}
div {
height: 26px;
font: Arial;
font-size: 12pt
}
form {
height: 40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form>
<input type="file" />
<div>Choose an image to see its file signature.</div>
</form>
<hr/>
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 faite côté serveur, mais que vous voulez ensuite réduire les ressources du serveur. Règle d'or: ne faites jamais confiance aux commentaires des utilisateurs . Quel est l'intérêt de vérifier le type MIME côté client si vous ne faites que le faire côté serveur. C'est sûrement un «gaspillage inutile de ressources client »?