Możesz łatwo określić typ MIME pliku za pomocą JavaScript FileReader
przed przesłaniem go na serwer. Zgadzam się, że powinniśmy preferować sprawdzanie po stronie serwera niż po stronie klienta, ale sprawdzanie po stronie klienta jest nadal możliwe. Pokażę ci, jak i zapewnię działające demo na dole.
Sprawdź, czy Twoja przeglądarka obsługuje zarówno File
i Blob
. Wszystkie najważniejsze powinny.
if (window.FileReader && window.Blob) {
// All the File APIs are supported.
} else {
// File and Blob are not supported
}
Krok 1:
Możesz pobrać File
informacje z <input>
elementu takiego jak ten ( 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>
Oto wersja powyższego ( ref ) typu „przeciągnij i upuść” :
<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>
Krok 2:
Możemy teraz przeglądać pliki i usuwać nagłówki oraz typy MIME.
✘ Szybka metoda
Możesz naiwnie zapytać Bloba o typ MIME dowolnego pliku, który reprezentuje, używając tego wzorca:
var blob = files[i]; // See step 1 above
console.log(blob.type);
W przypadku obrazów typy MIME powracają w następujący sposób:
image / jpeg
image / png
...
Uwaga: typ MIME jest wykrywany na podstawie rozszerzenia pliku i może zostać oszukany lub sfałszowany. Można zmienić nazwę a .jpg
na a, .png
a typ MIME zostanie zgłoszony jako image/png
.
✓ Właściwa metoda kontroli nagłówka
Aby uzyskać prawdziwy typ MIME pliku po stronie klienta, możemy pójść o krok dalej i sprawdzić kilka pierwszych bajtów danego pliku, aby porównać je z tak zwanymi liczbami magicznymi . Ostrzegamy, że nie jest to całkowicie proste, ponieważ na przykład JPEG ma kilka „magicznych liczb”. Dzieje się tak, ponieważ format ewoluował od 1991 roku. Możesz uciec od sprawdzania tylko pierwszych dwóch bajtów, ale ja wolę sprawdzić co najmniej 4 bajty, aby zredukować fałszywe alarmy.
Przykładowe podpisy plików JPEG (pierwsze 4 bajty):
FF D8 FF E0 (SOI + ADD0)
FF D8 FF E1 (SOI + ADD1)
FF D8 FF E2 (SOI + ADD2)
Oto podstawowy kod do pobrania nagłówka pliku:
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);
Następnie możesz określić rzeczywisty typ MIME w ten sposób (więcej sygnatur plików tutaj i tutaj ):
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;
}
Akceptuj lub odrzucaj przesyłanie plików, jak chcesz, na podstawie oczekiwanych typów MIME.
Próbny
Oto działające demo dla plików lokalnych i plików zdalnych (musiałem ominąć CORS tylko dla tego demo). Otwórz fragment kodu, uruchom go i powinieneś zobaczyć trzy zdalne obrazy różnych typów. U góry możesz wybrać lokalny obraz lub plik danych, a zostanie wyświetlony podpis pliku i / lub typ MIME.
Zauważ, że nawet jeśli nazwa obrazu zostanie zmieniona, można określić jego prawdziwy typ MIME. Zobacz poniżej.
Zrzut ekranu
// 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.
Nie rozumiem, dlaczego mówisz, że walidacja musi być wykonywana po stronie serwera, ale potem mówisz, że chcesz zmniejszyć zasoby serwera. Złota zasada: nigdy nie ufaj wprowadzaniu danych przez użytkownika . Jaki jest sens sprawdzania typu MIME po stronie klienta, jeśli robisz to po prostu po stronie serwera. Z pewnością jest to „niepotrzebne marnotrawstwo zasobów klienta ”?