Я прочитал это и это вопросы, которые, кажется, предполагают, что MIME-тип файла можно проверить с помощью javascript на стороне клиента. Теперь я понимаю, что настоящая проверка еще должна выполняться на стороне сервера. Я хочу выполнить проверку на стороне клиента, чтобы избежать ненужной потери ресурсов сервера.
Чтобы проверить, можно ли это сделать на стороне клиента, я изменил расширение JPEG
тестового файла на .png
и выбрал файл для загрузки. Перед отправкой файла я запрашиваю объект файла с помощью консоли javascript:
document.getElementsByTagName('input')[0].files[0];
Вот что я получаю на Chrome 28.0:
Файл {webkitRelativePath: "", lastModifiedDate: вторник, 16 октября 2012 г., 10:00:00 GMT + 0000 (UTC), имя: "test.png", тип: "image / png", размер: 500055…}
Он показывает тип, image/png
который, по-видимому, указывает на то, что проверка выполняется на основе расширения файла, а не MIME-типа. Я попробовал Firefox 22.0, и он дает мне тот же результат. Но согласно спецификации W3C , MIME Sniffing должен быть реализован.
Прав ли я сказать, что в настоящее время нет способа проверить тип MIME с помощью javascript? Или я что-то упустил?
источник
I want to perform a client side checking to avoid unnecessary wastage of server resource.
Я не понимаю, почему вы говорите, что проверка должна выполняться на стороне сервера, но потом говорите, что хотите уменьшить ресурсы сервера. Золотое правило: никогда не доверяйте пользовательскому вводу . Какой смысл проверять тип MIME на стороне клиента, если вы просто делаете это на стороне сервера. Конечно, это «ненужная потеря ресурсов клиента »?type
свойства дляFile
объектов. Например, исходный код webkit раскрывает эту истину. Можно точно идентифицировать файлы на стороне клиента, среди прочего, ища в них «волшебные байты». В настоящее время я работаю над библиотекой MIT (в то время, когда у меня мало свободного времени), которая будет заниматься именно этим. Если вы заинтересованы в моем прогрессе, взгляните на github.com/rnicholus/determinater .image/jpeg
, и вы на самом деле не изменили его, изменив расширение?Ответы:
Вы можете легко определить тип файла MIME с помощью JavaScript,
FileReader
прежде чем загружать его на сервер. Я согласен, что мы должны предпочесть проверку на стороне сервера, а не на стороне клиента, но проверка на стороне клиента все еще возможна. Я покажу вам, как и предоставить рабочую демонстрацию в нижней части.Убедитесь, что ваш браузер поддерживает
File
иBlob
. Все основные из них должны.Шаг 1:
Вы можете извлечь
File
информацию из такого<input>
элемента, как этот ( ссылка ):Вот версия вышеупомянутого перетаскивания ( ссылка ):
Шаг 2:
Теперь мы можем проверять файлы и выявлять заголовки и типы MIME.
✘ Быстрый метод
Вы можете наивно запросить у Blob тип MIME любого файла, который он представляет, используя этот шаблон:
Для изображений MIME-типы возвращаются следующим образом:
Предостережение: тип MIME определяется по расширению файла и может быть обманутым или поддельным. Можно переименовать a
.jpg
в a,.png
и тип MIME будет указан какimage/png
.✓ Правильный метод проверки заголовка
Чтобы получить истинный MIME-тип файла на стороне клиента, мы можем пойти еще дальше и проверить первые несколько байтов данного файла для сравнения с так называемыми магическими числами . Имейте в виду, что это не совсем просто, потому что, например, JPEG имеет несколько «магических чисел». Это связано с тем, что формат развивался с 1991 года. Возможно, вам не удастся проверить только первые два байта, но я предпочитаю проверять как минимум 4 байта, чтобы уменьшить количество ложных срабатываний.
Пример файла подписи JPEG (первые 4 байта):
Вот необходимый код для получения заголовка файла:
Затем вы можете определить реальный тип MIME следующим образом (больше подписей файлов здесь и здесь ):
Принимайте или отклоняйте загрузку файлов по своему усмотрению на основе ожидаемых типов MIME.
демонстрация
Вот рабочая демонстрация для локальных файлов и удаленных файлов (мне пришлось обойти CORS только для этой демонстрации). Откройте фрагмент, запустите его, и вы увидите три удаленных изображения разных типов. Вверху вы можете выбрать локальное изображение или файл данных, и будет отображаться подпись файла и / или тип MIME.
Обратите внимание, что даже если изображение переименовано, можно определить его истинный тип MIME. Увидеть ниже.
Скриншот
Показать фрагмент кода
источник
fileReader.readAsArrayBuffer(blob.slice(0,4))
? (2) Для того, чтобы копировать / вставлять подписи файлов, не должен ли заголовок быть составлен с начальными нулямиfor(var i = 0; i < bytes.length; i++) { var byte = bytes[i]; fileSignature += (byte < 10 ? "0" : "") + byte.toString(16); }
?FF D8 FF E2
= CANNON EOS JPEG FILE,FF D8 FF E3
= SAMSUNG D500 JPEG FILE. Ключевая часть подписи JPEG составляет всего 2 байта, но для уменьшения ложных срабатываний я добавил наиболее распространенные 4-байтовые подписи. Надеюсь, это поможет.fileReader.readAsArrayBuffer(blob.slice(0, 4))
Как указано в других ответах, вы можете проверить тип MIME, проверив подпись файла в первых байтах файла.
Но другие ответы делают загрузку всего файла в память для проверки подписи, что очень расточительно и может легко заморозить ваш браузер, если вы случайно выберете большой файл или нет.
источник
readyState
что всегда будетFileReader.DONE
в обработчике событий ( спецификация W3C ), даже если была ошибка - разве проверка должна быть, если(!e.target.error)
вместо этого?Для тех, кто хочет не реализовывать это самостоятельно, Sindresorhus создал утилиту, которая работает в браузере и имеет сопоставления заголовка с пантомимой для большинства документов, которые вы можете захотеть.
https://github.com/sindresorhus/file-type
Вы можете объединить предложение Vitim.us о чтении только в первых X байтах, чтобы избежать загрузки всего в память с помощью этой утилиты (пример в es6):
источник
"file-type": "12.4.0"
сработала, и мне пришлось использоватьimport * as fileType from "file-type";
Если вы просто хотите проверить, является ли загруженный файл изображением, вы можете просто попытаться загрузить его в
<img>
тег проверки на обратный вызов ошибок.Пример:
источник
Это то, что вы должны сделать
Если вы хотите проверить типы файлов изображений, то
источник
Вот реализация Typescript, которая поддерживает webp. Это основано на ответе JavaScript от Vitim.us.
источник
Как утверждает Дрейк, это можно сделать с помощью FileReader. Однако то, что я представляю здесь, является функциональной версией. Примите во внимание, что большая проблема с этим с JavaScript состоит в том, чтобы сбросить входной файл. Ну, это ограничивается только JPG (для других форматов вам придется изменить тип mime и магическое число ):
Примите во внимание, что это было протестировано на последних версиях Firefox и Chrome и на IExplore 10.
Полный список типов пантомимы см. В Википедии .
Полный список магических чисел см. В Википедии .
источник
Вот расширение ответа Roberto14, которое делает следующее:
ЭТО ТОЛЬКО РАЗРЕШИТ ИЗОБРАЖЕНИЯ
Проверяет, доступен ли FileReader, и возвращается к проверке расширений, если она недоступна.
Выдает предупреждение об ошибке, если не изображение
Если это изображение, оно загружает предварительный просмотр
** Вы все равно должны выполнить проверку на стороне сервера, это более удобно для конечного пользователя, чем что-либо еще. Но это удобно!
источник
Краткий ответ - нет.
Как вы заметили, браузеры происходят
type
от расширения файла. Предпросмотр Mac также, кажется, бежит вне расширения. Я предполагаю его, потому что он быстрее читает имя файла, содержащегося в указателе, а не ищет и читает файл на диске.Я сделал копию JPG, переименованный в PNG.
Мне удалось последовательно получить следующее из обоих изображений в Chrome (должно работать в современных браузерах).
ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
Который вы могли бы взломать проверку String.indexOf ('jpeg') для типа изображения.
Вот скрипка для изучения http://jsfiddle.net/bamboo/jkZ2v/1/
Неоднозначную строчку я забыл прокомментировать в примере
console.log( /^(.*)$/m.exec(window.atob( image.src.split(',')[1] )) );
В скриптовом коде используется декодирование base64, которое не работает в IE9, я нашел хороший пример использования скрипта VB, который работает в IE http://blog.nihilogic.dk/2008/08/imageinfo-reading-image-metadata-with.html
Код для загрузки изображения был взят от Джоэла Варди, который перед загрузкой делает несколько классных изображений для изменения размера холста на стороне клиента, которые могут быть интересны https://joelvardy.com/writing/javascript-image-upload
источник
JFIF
,APP0
не обязательно содержать JFIF в EXIF-JPEG, так что это тоже не нужно).