Вы можете легко определить тип файла MIME с помощью JavaScript, FileReaderпрежде чем загружать его на сервер. Я согласен, что мы должны предпочесть проверку на стороне сервера, а не на стороне клиента, но проверка на стороне клиента все еще возможна. Я покажу вам, как и предоставить рабочую демонстрацию в нижней части.
Убедитесь, что ваш браузер поддерживает Fileи Blob. Все основные из них должны.
if (window.FileReader && window.Blob) {
// All the File APIs are supported.
} else {
// File and Blob are not supported
}
Шаг 1:
Вы можете извлечь Fileинформацию из такого <input>элемента, как этот ( ссылка ):
<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>
Вот версия вышеупомянутого перетаскивания ( ссылка ):
<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>
Шаг 2:
Теперь мы можем проверять файлы и выявлять заголовки и типы MIME.
✘ Быстрый метод
Вы можете наивно запросить у Blob тип MIME любого файла, который он представляет, используя этот шаблон:
var blob = files[i]; // See step 1 above
console.log(blob.type);
Для изображений MIME-типы возвращаются следующим образом:
изображение / JPEG
изображение / PNG
...
Предостережение: тип MIME определяется по расширению файла и может быть обманутым или поддельным. Можно переименовать a .jpgв a, .pngи тип MIME будет указан как image/png.
✓ Правильный метод проверки заголовка
Чтобы получить истинный MIME-тип файла на стороне клиента, мы можем пойти еще дальше и проверить первые несколько байтов данного файла для сравнения с так называемыми магическими числами . Имейте в виду, что это не совсем просто, потому что, например, JPEG имеет несколько «магических чисел». Это связано с тем, что формат развивался с 1991 года. Возможно, вам не удастся проверить только первые два байта, но я предпочитаю проверять как минимум 4 байта, чтобы уменьшить количество ложных срабатываний.
Пример файла подписи JPEG (первые 4 байта):
FF D8 FF E0 (SOI + ADD0)
FF D8 FF E1 (SOI + ADD1)
FF D8 FF E2 (SOI + ADD2)
Вот необходимый код для получения заголовка файла:
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);
Затем вы можете определить реальный тип MIME следующим образом (больше подписей файлов здесь и здесь ):
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;
}
Принимайте или отклоняйте загрузку файлов по своему усмотрению на основе ожидаемых типов MIME.
демонстрация
Вот рабочая демонстрация для локальных файлов и удаленных файлов (мне пришлось обойти CORS только для этой демонстрации). Откройте фрагмент, запустите его, и вы увидите три удаленных изображения разных типов. Вверху вы можете выбрать локальное изображение или файл данных, и будет отображаться подпись файла и / или тип MIME.
Обратите внимание, что даже если изображение переименовано, можно определить его истинный тип MIME. Увидеть ниже.
Скриншот

// 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.Я не понимаю, почему вы говорите, что проверка должна выполняться на стороне сервера, но потом говорите, что хотите уменьшить ресурсы сервера. Золотое правило: никогда не доверяйте пользовательскому вводу . Какой смысл проверять тип MIME на стороне клиента, если вы просто делаете это на стороне сервера. Конечно, это «ненужная потеря ресурсов клиента »?