Ogranicz format pliku przy użyciu <input type = „file”>?


667

Chciałbym ograniczyć typ pliku, który można wybrać z natywnego selektora plików systemu operacyjnego, gdy użytkownik kliknie przycisk Przeglądaj w <input type="file">elemencie HTML. Mam wrażenie, że to niemożliwe, ale chciałbym wiedzieć, czy jest jakieś rozwiązanie. Chciałbym trzymać się wyłącznie HTML i JavaScript; proszę nie Flash.


1
Z PHP jest to możliwe, ale nie wiem, czy możesz tego użyć, więc nie opublikuję kodu.
Latox,

2
Mogę, ale mam rozwiązanie współpracujące z JavaScriptem - usuwa to irytację związaną z przesyłaniem pliku, a następnie uzyskiwaniem „Błędnego pliku!” błąd.
Bojangles,


Należy zauważyć, że chociaż nie jest to świetne do sprawdzania poprawności, accept ograniczy widoczne pliki do akceptowanych podczas przeglądania przez użytkownika (przynajmniej w niektórych przeglądarkach ...). Jest to więc bardziej ergonomiczna funkcja interfejsu użytkownika niż funkcja sprawdzania poprawności.
Christophe Roussy,

Odpowiedzi:


1119

Ściśle mówiąc, odpowiedź brzmi „ nie” . Deweloper nie może uniemożliwić użytkownikowi przesyłania plików dowolnego typu lub rozszerzenia.

Mimo to atrybut accept<input type = "file"> może pomóc w zapewnieniu filtru w oknie dialogowym wyboru pliku w systemie operacyjnym. Na przykład,

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

powinien zapewnić sposób na odfiltrowanie plików innych niż .xls lub .xlsx. Chociaż strona MDN dla inputelementu zawsze mówiła, że ​​to obsługuje, ku mojemu zaskoczeniu, nie działało to dla mnie w Firefoksie do wersji 42. To działa w IE 10+, Edge i Chrome.

Tak więc, do obsługi Firefoksa starszego niż 42 wraz z IE 10+, Edge, Chrome i Opera, myślę, że lepiej jest używać listy typów MIME oddzielonych przecinkami:

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

Zachowanie [ Edge (EdgeHTML): lista rozwijana filtru typów plików pokazuje typy plików wymienione tutaj, ale nie jest domyślna w liście rozwijanej. Domyślny filtr to All files (*).]

Możesz także używać gwiazdek w typach MIME. Na przykład:

<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 zaleca autorom określenie w acceptatrybucie zarówno typów MIME, jak i odpowiednich rozszerzeń . Zatem najlepszym podejściem jest:

<!-- 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 tego samego: tutaj .

Odniesienie: Lista typów MIME

WAŻNE: Użycie tego acceptatrybutu zapewnia jedynie sposób filtrowania w interesujących plikach typów. Przeglądarki nadal pozwalają użytkownikom wybierać pliki dowolnego typu. Należy wykonać dodatkowe kontrole (po stronie klienta) (przy użyciu JavaScript, jednym ze sposobów byłoby to ), a zdecydowanie typy plików MUSZĄ zostać zweryfikowane na serwerze , przy użyciu kombinacji typu MIME przy użyciu zarówno rozszerzenia pliku, jak i jego podpisu binarnego ( ASP .NET , PHP , Ruby , Java ). Możesz także zapoznać się z tymi tabelami, aby uzyskać informacje o typach plików i ich magicznych liczbach, aby przeprowadzić bardziej niezawodną weryfikację po stronie serwera.

Oto trzy dobre czyta na przesyłaniu plików i bezpieczeństwa.

EDYCJA: Może weryfikacja typu pliku za pomocą jego podpisu binarnego może być również przeprowadzona po stronie klienta za pomocą JavaScript (a nie tylko poprzez spojrzenie na rozszerzenie) za pomocą interfejsu API plików HTML5, ale plik musi zostać zweryfikowany na serwerze, ponieważ złośliwy użytkownik nadal będzie mógł przesyłać pliki, wysyłając niestandardowe żądanie HTTP.


2
@ Sandesire Nie sądzę, że można ograniczyć rozmiary plików w HTML. Jest to możliwe przy użyciu JavaScript, jak sugerowałeś.
Sachin Joseph,

1
Z mojego osobistego doświadczenia wygląda to na dobrą odpowiedź, sam typ MIME nie będzie działał na wszystkich przeglądarkach.
Christophe Roussy,

1
Nawiasem mówiąc acceptnadal nie działa w Krawędzi: stackoverflow.com/questions/31875617/... . Więcej informacji tutaj: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/...
SharpC

1
Na przykład chciałbym mieć możliwość wykluczenia plików exclude="exe". ¯_ (ツ) _ / ¯
Sagiv bg

1
Aby wyjaśnić zachowanie Edge'a (zgodnie z moimi testami), doda inne filtry w zależności od tego, co określisz, ale a) nie jest dołączone, więc wyświetli każde rozszerzenie jako osobną opcję i b) zawsze doda trochę buduj rozszerzenia, takie jak .html i c), jak już wspomniano, zawsze wybierze wstępnie (*). Co sprawia, że ​​jest to duży bałagan i w większości przypadków bezużyteczny. Głosowałem na link do faktury użytkownika, miejmy nadzieję, że wcześniej czy później posłuchają.
Arie

198

Istnieje atrybut accept dla znacznika wejściowego. Jednak nie jest w żaden sposób wiarygodny. Przeglądarki najprawdopodobniej traktują to jako „sugestię”, co oznacza, że ​​użytkownik, w zależności od menedżera plików, będzie miał wstępny wybór, który wyświetla tylko żądane typy. Nadal mogą wybrać „wszystkie pliki” i przesłać dowolny plik.

Na przykład:

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

Przeczytaj więcej w specyfikacji HTML5

Należy pamiętać, że może on służyć jedynie jako „pomoc” dla użytkownika w znalezieniu odpowiednich plików. Każdy użytkownik może wysłać dowolne żądanie na serwer. Zawsze musisz zweryfikować wszystko po stronie serwera.

Więc odpowiedź brzmi: nie ty nie może ograniczać , ale można ustawić preselekcji, ale nie można na nim polegać.

Alternatywnie lub dodatkowo możesz zrobić coś podobnego, sprawdzając nazwę pliku (wartość pola wejściowego) za pomocą JavaScript, ale to nonsens, ponieważ nie zapewnia ochrony, a także nie ułatwia wyboru użytkownika. To tylko potencjalnie może skłonić webmastera do myślenia, że ​​jest chroniony i otwiera lukę w zabezpieczeniach. Dla użytkowników, którzy mają alternatywne rozszerzenia plików (na przykład jpeg zamiast jpg), duże lub nie mają żadnych rozszerzeń plików (jak to często bywa w systemach Linux), może to być kłopotliwe.


3
dodatkowe informacje można znaleźć na stackoverflow.com/questions/181214/…
Martin Meeser,

1
Chociaż prawdą jest, że nie można uniemożliwić użytkownikowi wybrania JAKIEKOLWIEK typu pliku, obecnie można skorzystać z interfejsu API plików HTML5 i pracować z wybranym plikiem do przesłania, zanim zostanie on faktycznie przesłany na serwer, w tym wykryć jego typ, rozmiar i więcej. Spróbuj. Jest bardzo łatwy w użyciu, a jednocześnie bardzo wydajny i użyteczny.
TheCuBeMan

96

Możesz użyć changezdarzenia do monitorowania tego, co użytkownik wybiera i powiadamiania go w tym momencie, że plik jest niedopuszczalny. Nie ogranicza faktycznej listy wyświetlanych plików, ale jest to najbliższa czynność po stronie klienta, oprócz słabo obsługiwanego acceptatrybutu.

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, jest to przykład ... może obejmować dowolne rozszerzenia, na które chcesz zezwolić.
Gabriele Petrioli,

tak możesz. ale TY NIE! i może ktoś już to skopiował! a co z plikami z prawidłowym typem MIME, ale bez rozszerzenia?
The Surrican

49
@ Joe .. cóż ... staram się zapewnić kierunek i logikę dźwiękową. Nie w pełni wdrożone rozwiązania dla każdego przypadku. Ufam, że widzowie
kierują się

7
Co powiesz na „Some.File.jpg”? Być może ten wiersz wyrażenia regularnego musi brzmieć: var ext = this.value.match (/ \. ([^.] +) $ /) [1];
Jon Kloske

Problem z tym podejściem polega na tym, że coś może być technicznie JPEG, nawet jeśli nie kończy się na tym rozszerzeniu. Rozszerzenia! == typy mime
Matt Fletcher

46

Tak masz rację. To niemożliwe z HTML. Użytkownik będzie mógł wybrać dowolny plik, który chce.

Możesz napisać fragment kodu JavaScript, aby uniknąć przesłania pliku na podstawie jego rozszerzenia. Należy jednak pamiętać, że w żaden sposób nie uniemożliwi to złośliwemu użytkownikowi przesłania dowolnego pliku, który naprawdę chce.

Coś jak:

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

Kod HTML:

<form method="post" onsubmit="return beforeSubmit();">
    <input type="file" id="ifile" name="ifile"/>
</form>

3
istnieje w pełni poprawny atrybut HTML, więc jest to możliwe. nie jest po prostu szanowany przez przeglądarki, ale jest to problem normalizacyjny. podobnie jak wszystkie elementy obsługiwane po stronie klienta w niezabezpieczonych znacznikach nie mogą ograniczać niczego, co skrypt Java nie jest rozwiązaniem.
The Surrican,

2
Bardzo dobra uwaga. Na wszelki wypadek dodam drugi moduł sprawdzania PHP. Nie może być zbyt ostrożny!
Bojangles,

2
Cóż, to nie szkodzi, jeśli używam również skryptu sprawdzania poprawności PHP, więc użyję obu.
Bojangles,

17
@Joe: przestań mówić, że moja odpowiedź jest do bani! :-) W każdym razie nie jest to idealne rozwiązanie. Jak powiedziałem na początku: „nie można” robić tego, czego chce OP. Możesz jednak pomóc użytkownikowi w pewnym stopniu, jeśli pozwalasz mu wybierać pliki tylko z pewnymi rozszerzeniami. Real walidacja typ pliku musi być wykonane po stronie serwera .
Pablo Santa Cruz,

11
@JoeHopfgartner: Stary, jesteś zbyt surowy dla Pablo tutaj. sprawdzanie poprawności po stronie klienta odbywa się w wielu miejscach i chociaż nie jest niezawodny (powinno być [b] zawsze [/ b] dołączone sprawdzanie poprawności po stronie serwera), może zaoszczędzić trochę czasu użytkownikowi (bez postback dla głupiego sprawdzania rozszerzenia itp.). Chociaż skrypt podany przez Pablo nie jest doskonały, ma on jedynie służyć jako przykład rozwiązania tego problemu ... Może powinieneś wysłać e-maila do techników z firmy Microsoft i poprosić ich o usunięcie sprawdzania poprawności po stronie klienta z ich walidatorów ASP.NET, ponieważ to wszystko dla ciebie zwykłe śmieci ...
Nathan

18

Technicznie możesz określić acceptatrybut (alternatywny w html5 ) dla inputelementu, ale nie jest on poprawnie obsługiwany.


Obsługa przeglądarki W3Schools kończy się niepowodzeniem! Naprawdę szkoda. Jest to również kwestia bezpieczeństwa - ludzie mogą włamać się do kodu po stronie klienta i przesyłać cokolwiek chcą.
Bojangles,

5
To prawda, że ​​najlepiej nie używać tego ze względów bezpieczeństwa, ale zdecydowanie poprawia użyteczność w przeglądarkach, które go obsługują. Użytkownikom wyświetlane są tylko pliki dozwolone przez witrynę (nie wszystkie inne śmieci, które mogą znajdować się w tym samym folderze) i nie muszą przechodzić przez cały proces przesyłania, aby otrzymać błąd, będą od razu wiedzieć. Kodery powinny z tego skorzystać.
Simon East

10

Użyj inputtagu z acceptatrybutem

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

Kliknij tutaj, aby wyświetlić najnowszą tabelę zgodności przeglądarki

Demo na żywo tutaj

Aby wybrać tylko pliki obrazów, możesz użyć tego accept="image/*"

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

Demo na żywo tutaj

Wyświetlane będą tylko gif, jpg i png, zrzut ekranu z przeglądarki Chrome w wersji 44 Wyświetlane będą tylko gif, jpg i png, zrzut ekranu z przeglądarki Chrome w wersji 44


Dzięki! W Chrome na Win10, jeśli go używam accept="image/*", w selektorze plików jest napisane „Pliki obrazów” zamiast „Pliki niestandardowe”, co jest miłe dla użytkownika końcowego.
Teddy

Ale użytkownik może to zmienić i przesłać inny plik rozszerzenia
Prashant Prajapati

@PrashantPrajapati Tak, tak powstają przeglądarki, powinna istnieć odpowiednia walidacja na serwerze. Funkcjonalność przeglądarki jest po prostu dla lepszego doświadczenia użytkownika.
kiranvj

9

Wiem, że to trochę za późno.

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;
}

5

Możesz to zrobić za pomocą javascript, ale pamiętaj, że js jest po stronie klienta, więc w rzeczywistości „ostrzegasz użytkowników”, jakie typy plików mogą przesłać, jeśli chcesz UNIKNĄĆ (ograniczyć lub ograniczyć, jak powiedziałeś) określonego rodzaju plików, które MUSISZ zrób to po stronie serwera.

Spójrz na ten podstawowy poradnik, jeśli chcesz zacząć od sprawdzania poprawności po stronie serwera. Aby zobaczyć cały samouczek, odwiedź tę stronę .

Powodzenia!


4

Jak wspomniano w poprzednich odpowiedziach, nie możemy ograniczać użytkownika do wybierania plików tylko dla podanych formatów plików. Ale naprawdę przydatne jest użycie atrybutu accept w pliku html.

Jeśli chodzi o sprawdzanie poprawności, musimy to zrobić po stronie serwera. Możemy to również zrobić po stronie klienta w js, ale nie jest to niezawodne rozwiązanie. Musimy zweryfikować po stronie serwera.

W przypadku tych wymagań naprawdę wolę środowisko programowania aplikacji WWW struts2 Java. Dzięki wbudowanej funkcji przesyłania plików przesyłanie plików do aplikacji internetowych opartych na struts2 jest dziecinnie proste. Wystarczy wspomnieć o formatach plików, które chcielibyśmy zaakceptować w naszej aplikacji, a całą resztę zajmuje sam rdzeń frameworka. Możesz to sprawdzić na oficjalnej stronie firmy Struts.


3

Mogę zasugerować następujące:

  • Jeśli musisz domyślnie wybrać dowolny plik obrazu, użyj accept = "image / *"

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

  • jeśli chcesz ograniczyć się do określonych typów obrazów, użyj accept = "image / bmp, image / jpeg, image / png"

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

  • jeśli chcesz ograniczyć się do określonych typów, użyj accept = ". bmp, .doc, .pdf"

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

  • Nie można ograniczyć użytkownika do zmiany filtru plików na wszystkie pliki, dlatego zawsze należy sprawdzać poprawność typu pliku w skrypcie i serwerze


1
Właśnie tego szukałem: accept = ". Bmp" Działa dobrze na chrome.
MichaelRom
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.