Ограничить формат файла при использовании <input type = «file»>?

667

Я хотел бы ограничить тип файла, который можно выбрать из средства выбора файлов собственной ОС, когда пользователь нажимает кнопку «Обзор» в <input type="file">элементе в HTML. У меня есть ощущение , что это невозможно, но я хотел бы знать , если это решение. Я хотел бы придерживаться исключительно HTML и JavaScript; Нет вспышки, пожалуйста.

Bojangles
источник
1
Это легко возможно с PHP, но я не знаю, можете ли вы использовать это, поэтому я не буду публиковать код.
Латокс
2
Я могу, но у меня есть решение , работая с JavaScript - это снимает раздражение загрузки файла , то получает «Неверный файл!» ошибка.
Bojangles
Также см. Более свежий вопрос: stackoverflow.com/questions/181214/…
Кристоф Русси,
Стоит отметить, что, хотя он не подходит для валидации, но при его принятии видимые файлы будут ограничены принятыми, пока пользователь просматривает их (по крайней мере, в некоторых браузерах ...). Так что это скорее функция эргономики пользовательского интерфейса, чем функция проверки.
Кристоф Русси,

Ответы:

1120

Строго говоря, ответ - нет . Разработчик не может запретить пользователю загружать файлы любого типа или расширения.

Но все же атрибут accept<input type = "file"> может помочь обеспечить фильтр в диалоговом окне выбора файлов в ОС. Например,

<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox 42+) -->
<input type="file" accept=".xls,.xlsx" />

должен предоставить способ отфильтровать файлы, отличные от .xls или .xlsx. Хотя на странице MDN для inputэлемента всегда говорилось, что она поддерживает это, к моему удивлению, это не работало для меня в Firefox до версии 42. Это работает в IE 10+, Edge и Chrome.

Итак, для поддержки Firefox старше 42 лет вместе с IE 10+, Edge, Chrome и Opera, я думаю, лучше использовать список MIME-типов через запятую:

<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox) -->
<input type="file"
 accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" /> 

Поведение [ Edge (EdgeHTML): раскрывающийся список фильтров типов файлов показывает типы файлов, упомянутые здесь, но не является значением по умолчанию в раскрывающемся списке. Фильтр по умолчанию All files (*).]

Вы также можете использовать звездочки в MIME-типах. Например:

<input type="file" accept="image/*" /> <!-- all image types --> 
<input type="file" accept="audio/*" /> <!-- all audio types --> 
<input type="file" accept="video/*" /> <!-- all video types --> 

W3C рекомендует авторам указывать в acceptатрибуте как MIME-типы, так и соответствующие расширения . Итак, лучший подход это:

<!-- Right approach: Use both file extensions and corresponding MIME-types. -->
<!-- (IE 10+, Edge (EdgeHTML), Edge (Chromium), Chrome, Firefox) -->
<input type="file"
 accept=".xls,.xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" /> 

JSFiddle из того же: здесь .

Ссылка: список MIME-типов.

ВАЖНО: Использование acceptатрибута обеспечивает только способ фильтрации в файлах типов, представляющих интерес. Браузеры по-прежнему позволяют пользователям выбирать файлы любого типа. Дополнительно ( на стороне клиента) проверки должны быть сделаны ( с использованием JavaScript, один из способов было бы это ), и определенно типы файлов должны быть проверены на сервере , используя комбинацию MIME-типа с использованием как расширение файла и его двоичную подпись ( ASP .NET , PHP , Ruby , Java ). Вы также можете обратиться к этим таблицам для типов файлов и их магических чисел, чтобы выполнить более надежную проверку на стороне сервера.

Вот три хороших чтения по загрузке файлов и безопасности.

РЕДАКТИРОВАТЬ: Может быть, проверка типа файла с использованием его двоичной подписи также может быть выполнена на стороне клиента с помощью JavaScript (а не просто путем просмотра расширения) с использованием HTML5 File API, но, тем не менее, файл должен быть проверен на сервере, поскольку злоумышленник по-прежнему будет в состоянии загружать файлы, сделав собственный HTTP-запрос.

Сачин Иосиф
источник
2
@Sandesire Я не думаю, что вы можете ограничить размеры файлов в HTML. Это возможно с помощью JavaScript, как вы предложили.
Сачин Иосиф
1
Из моего личного опыта это выглядит как хороший ответ, один тип MIME не будет работать во всех браузерах.
Кристоф Русси,
1
Между прочим, acceptвсе еще не работает в Edge: stackoverflow.com/questions/31875617/… . Подробнее здесь: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
SharpC
1
Я бы хотел, чтобы у нас был выбор, например, исключить файлы exclude="exe". _ (ツ) _ / ¯
Sagiv BG
1
Чтобы прояснить поведение Edge далее (согласно моим тестам), он будет добавлять различные фильтры в зависимости от того, что вы укажете, но а) он не связан, поэтому он будет перечислять каждое расширение как отдельную опцию и б) он всегда будет добавлять некоторые строить расширения, такие как .html и c), как уже было сказано, он всегда будет предварительно выбран (*). Что делает это большим беспорядком и бесполезным в большинстве случаев. Я проголосовал по ссылке uservoice, будем надеяться, что рано или поздно они будут слушать.
Арье
198

Для входного тега есть атрибут accept. Тем не менее, это не надежно в любом случае. Браузеры, скорее всего, рассматривают его как «предложение», то есть пользователь, в зависимости от файлового менеджера, также имеет предварительный выбор, отображающий только нужные типы. Они по-прежнему могут выбрать «все файлы» и загрузить любой файл, который они хотят.

Например:

<form>
    <input type="file" name="pic" id="pic" accept="image/gif, image/jpeg" />
</form>

Читайте больше в спецификации HTML5

Имейте в виду, что он должен использоваться только как «помощь» для пользователя, чтобы найти нужные файлы. Каждый пользователь может отправить любой запрос на свой сервер. Вы всегда должны проверять все на стороне сервера.

Таким образом, ответ: нет, вы не можете ограничить , но вы можете установить предварительный выбор, но вы не можете полагаться на него.

В качестве альтернативы или дополнения вы можете сделать что-то похожее, проверив имя файла (значение поля ввода) с помощью JavaScript, но это бессмыслица, потому что не обеспечивает защиты, а также не облегчает выбор для пользователя. Это только обманывает веб-мастера, заставляя его думать, что он защищен и открывает дыру в безопасности. Это может быть проблемой для пользователей, которые имеют альтернативные расширения файлов (например, jpeg вместо jpg), прописные буквы или вообще не имеют расширений файлов (как обычно в системах Linux).

Суррик
источник
3
для получения дополнительной информации см. stackoverflow.com/questions/181214/…
Мартин Мизер
1
Хотя это правда, что в конечном итоге невозможно запретить пользователю выбирать ЛЮБОЙ тип файла, в наши дни вы можете воспользоваться API-интерфейсом файлов HTML5 и работать с выбранным файлом для загрузки, прежде чем он будет фактически загружен на сервер, включая обнаружение его тип, размер и многое другое. Попробуйте. Он очень прост в использовании, но очень мощный и полезный.
TheCuBeMan
96

Вы можете использовать это changeсобытие для отслеживания того, что выбирает пользователь, и уведомить его в тот момент, что файл неприемлем. Он не ограничивает фактический список отображаемых файлов, но он ближе всего подходит для клиентской части, кроме плохо поддерживаемого acceptатрибута.

var file = document.getElementById('someId');

file.onchange = function(e) {
  var ext = this.value.match(/\.([^\.]+)$/)[1];
  switch (ext) {
    case 'jpg':
    case 'bmp':
    case 'png':
    case 'tif':
      alert('Allowed');
      break;
    default:
      alert('Not allowed');
      this.value = '';
  }
};
<input type="file" id="someId" />

JSFiddle

Габриэле Петриоли
источник
11
@joe, это пример ... он может распространяться на любые расширения, которые вы хотите разрешить.
Габриэле Петриоли
да, вы можете но ты не сделал! и Мэйби, кто-то уже скопировал это! а как насчет файлов с правильным типом mime, но без расширения?
Surrican
49
@ Джо .. хорошо .. я пытаюсь обеспечить направление и звуковую логику. Не полностью реализованные решения для каждого случая. Я доверяю зрителям использовать здравый смысл при копировании / вставке кода из Интернета;)
Габриэле Петриоли
7
Как насчет "Some.File.jpg"? Возможно, эту строку регулярного выражения нужно прочитать: var ext = this.value.match (/ \. ([^.] +) $ /) [1];
Джон Клоске
Проблема с этим подходом заключается в том, что технически что-то может быть в формате JPEG, даже если это не заканчивается этим расширением. Расширения! == MIME
Мэтт Флетчер,
46

Да ты прав. Это невозможно с HTML. Пользователь сможет выбрать любой файл, который он / она хочет.

Вы могли бы написать кусок JavaScript кода чтобы избежать отправки файла на основании его расширения. Но имейте в виду, что это никоим образом не помешает злоумышленнику отправить любой файл, который он / она действительно хочет.

Что-то вроде:

function beforeSubmit()
{
    var fname = document.getElementById("ifile").value;
    // check if fname has the desired extension
    if (fname hasDesiredExtension) {
        return true;
    } else {
        return false;
    }
}

HTML код:

<form method="post" onsubmit="return beforeSubmit();">
    <input type="file" id="ifile" name="ifile"/>
</form>
Пабло Санта Круз
источник
3
для этого есть полностью допустимый атрибут html, так что это возможно. это просто не соблюдается браузерами, но это проблема стандартизации. так же как любые вещи, которые обрабатываются на стороне клиента в незащищенной разметке, не могут ограничивать ничего, java-скрипт не является решением.
Surrican
2
Очень хороший момент. Я добавлю вторую проверку PHP на всякий случай. Не могу быть слишком осторожным!
Bojangles
2
Ну, это не повредит, если я тоже использую сценарий проверки PHP, поэтому я буду использовать оба.
Bojangles
17
@Joe: перестань говорить, что мой ответ отстой! :-) В любом случае, это не идеальное решение. Как я уже сказал в начале, «невозможно» делать то, что хочет ОП. Но вы можете оказать некоторую помощь пользователю, если вы позволите ему / ей выбирать файлы с определенными расширениями. РЕАЛЬНАЯ проверка типа файла должна выполняться на стороне сервера .
Пабло Санта Круз
11
@JoeHopfgartner: Чувак, ты слишком резок для Пабло. проверка на стороне клиента выполняется в сотнях мест, и хотя она не защищена от ошибок (всегда должна быть [b] всегда [/ b] проверка на стороне сервера), она может сэкономить пользователю довольно много времени (без обратной передачи для глупой проверки расширения и т. д.). Хотя сценарий, предложенный Пабло, не идеален, он просто предназначен для того, чтобы стать примером того, как решить эту проблему ... Может быть, вам следует отправить электронное сообщение техническим специалистам в Microsoft и попросить их удалить проверку Clientside из их валидаторов ASP.NET, поскольку для тебя все это чепуха ...
Натан
18

Технически вы можете указать acceptатрибут (альтернативный в html5 ) для inputэлемента, но он не поддерживается должным образом.

zzzzBov
источник
Сбой поддержки браузера W3Schools! Это действительно позор. Это также проблема безопасности - люди могут взломать код на стороне клиента и загрузить все, что захотят.
Bojangles
5
Правда, лучше не использовать это для безопасности, но это определенно помогает юзабилити в браузерах, которые его поддерживают. Пользователям показываются только те файлы, которые разрешает сайт (не все другие нежелательные файлы, которые они могут иметь в одной и той же папке), и им не нужно проходить весь процесс загрузки, чтобы получить ошибку, они сразу же узнают об этом. Кодеры должны использовать это.
Саймон Ист
10

Использовать inputтег с acceptатрибутом

<input type="file" name="my-image" id="image" accept="image/gif, image/jpeg, image/png" />

Нажмите здесь для просмотра последней таблицы совместимости браузера

Live демо здесь

Чтобы выбрать только файлы изображений, вы можете использовать это accept="image/*"

<input type="file" name="my-image" id="image" accept="image/*" />

Демо здесь

Будут показаны только GIF, JPG и PNG, захват экрана из версии Chrome 44 Будут показаны только GIF, JPG и PNG, захват экрана из версии Chrome 44

kiranvj
источник
Спасибо! В Chrome на Win10, если я использую accept="image/*", он говорит «Файлы изображений» вместо «Пользовательские файлы» в средстве выбора файлов, что приятно для конечного пользователя.
Тедди,
Но пользователь может изменить его и загрузить другой файл расширения
Prashant
@PrashantPrajapati Да, это так, как браузеры сделаны, должна быть соответствующая проверка на сервере. Функциональность браузера только для лучшего пользовательского опыта.
kiranvj
9

Я знаю, что это немного поздно.

function Validatebodypanelbumper(theForm)
{
   var regexp;
   var extension =     theForm.FileUpload.value.substr(theForm.FileUpload1.value.lastIndexOf('.'));
   if ((extension.toLowerCase() != ".gif") &&
       (extension.toLowerCase() != ".jpg") &&
       (extension != ""))
   {
      alert("The \"FileUpload\" field contains an unapproved filename.");
      theForm.FileUpload1.focus();
      return false;
   }
   return true;
}
bpross
источник
5

На самом деле вы могли бы сделать это с помощью javascript, но помните, что js на стороне клиента, поэтому вы на самом деле будете «предупреждать пользователей», какие типы файлов они могут загружать, если вы хотите ИЗБЕЖАТЬ (ограничить или ограничить, как вы сказали) определенный тип файлов, которые ДОЛЖНЫ быть сделать это на стороне сервера.

Посмотрите на этот базовый вариант, если вы хотите начать проверку на стороне сервера. Для всего урока посетите эту страницу .

Удачи!

Trufa
источник
4

Как упоминалось в предыдущих ответах, мы не можем ограничивать выбор пользователем файлов только для заданных форматов файлов. Но очень удобно использовать тег accept для атрибута файла в html.

Что касается проверки, мы должны сделать это на стороне сервера. Мы также можем сделать это на стороне клиента в js, но это не надежное решение. Мы должны проверить на стороне сервера.

Для этих требований я действительно предпочитаю Struts2 среду разработки веб-приложений Java. Благодаря встроенной функции выгрузки файлов загрузка файлов в веб-приложения на базе struts2 становится простой задачей. Просто упомяните форматы файлов, которые мы хотели бы принять в нашем приложении, а все остальное заботится о ядре самой платформы. Вы можете проверить это на официальном сайте стойки.

SVG
источник
3

Я могу предложить следующее:

  • Если вам нужно заставить пользователя выбрать любой из файлов изображений по умолчанию, используйте accept = "image / *"

    <input type="file" accept="image/*" />

  • если вы хотите ограничиться определенными типами изображений, используйте accept = "image / bmp, image / jpeg, image / png"

    <input type="file" accept="image/bmp, image/jpeg, image/png" />

  • если вы хотите ограничиться определенными типами, используйте accept = ". bmp, .doc, .pdf"

    <input type="file" accept=".bmp, .doc, .pdf" />

  • Вы не можете запретить пользователю изменять файловый файл для всех файлов, поэтому всегда проверяйте тип файла в скрипте и на сервере.

Имран Джавед
источник
1
Это было то, что я искал: accept = ". Bmp" Отлично работает на Chrome.
MichaelRom