Batasi format file saat menggunakan <input type = "file">?

667

Saya ingin membatasi jenis file yang dapat dipilih dari pemilih file OS asli ketika pengguna mengklik tombol Browse di <input type="file">elemen dalam HTML. Saya punya perasaan itu tidak mungkin, tapi saya ingin tahu apakah ada adalah solusi. Saya hanya ingin tetap menggunakan HTML dan JavaScript; tolong jangan flash.

Bojangles
sumber
1
Mudah dengan PHP, tapi saya tidak tahu apakah Anda bisa menggunakannya sehingga saya tidak akan memposting kode.
Latox
2
Saya bisa, tetapi saya punya solusi yang bekerja dengan JavaScript - itu menghilangkan gangguan mengunggah file kemudian mendapatkan "File yang salah!" kesalahan.
Bojangles
Lihat juga pertanyaan terbaru: stackoverflow.com/questions/181214/…
Christophe Roussy
Satu hal yang perlu diperhatikan adalah meskipun tidak bagus untuk validasi, accept akan membatasi file yang terlihat ke yang diterima saat pengguna menjelajahinya (setidaknya di beberapa browser ...). Jadi ini lebih merupakan fitur ergonomi UI daripada yang validasi.
Christophe Roussy

Jawaban:

1119

Sebenarnya, jawabannya adalah tidak . Pengembang tidak dapat mencegah pengguna dari mengunggah file jenis atau ekstensi apa pun.

Namun tetap saja, atribut accept<input type = "file"> dapat membantu menyediakan filter di kotak dialog pilih file OS. Sebagai contoh,

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

harus menyediakan cara untuk memfilter file selain .xls atau .xlsx. Meskipun halaman MDN untuk inputelemen selalu mengatakan bahwa ia mendukung ini, saya terkejut, ini tidak berfungsi untuk saya di Firefox hingga versi 42. Ini berfungsi di IE 10+, Edge, dan Chrome.

Jadi, untuk mendukung Firefox yang lebih tua dari 42 bersama dengan IE 10+, Edge, Chrome, dan Opera, saya kira lebih baik menggunakan daftar tipe-MIME yang dipisahkan koma:

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

Perilaku [ Edge (EdgeHTML): Dropdown filter tipe file menunjukkan tipe file yang disebutkan di sini, tetapi bukan default dalam dropdown. Filter default adalah All files (*).]

Anda juga dapat menggunakan tanda bintang di tipe-MIME. Sebagai contoh:

<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 merekomendasikan penulis untuk menentukan tipe MIME dan ekstensi yang sesuai dalam acceptatribut. Jadi, pendekatan terbaik adalah:

<!-- 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 sama: di sini .

Referensi: Daftar tipe-MIME

PENTING: Menggunakan acceptatribut hanya menyediakan cara pemfilteran dalam file tipe yang menarik. Browser masih memungkinkan pengguna untuk memilih file jenis apa pun. Pemeriksaan tambahan (sisi klien) harus dilakukan (menggunakan JavaScript, salah satu caranya adalah ini ), dan pasti jenis file HARUS diverifikasi di server , menggunakan kombinasi tipe MIME menggunakan ekstensi file dan tanda tangan binernya ( ASP) .NET , PHP , Ruby , Java ). Anda mungkin juga ingin merujuk ke tabel ini untuk jenis file dan angka ajaibnya, untuk melakukan verifikasi sisi server yang lebih kuat.

Berikut adalah tiga bacaan yang bagus tentang pengunggahan file dan keamanan.

EDIT: Mungkin verifikasi jenis file menggunakan tanda tangan binernya juga dapat dilakukan di sisi klien menggunakan JavaScript (bukan hanya dengan melihat ekstensi) menggunakan HTML5 File API, tetapi tetap saja, file tersebut harus diverifikasi di server, karena pengguna jahat masih dapat mengunggah file dengan membuat permintaan HTTP khusus.

Sachin Joseph
sumber
2
@Sandesire Saya tidak berpikir Anda dapat membatasi ukuran file dalam HTML. Mungkin menggunakan JavaScript, seperti yang Anda sarankan.
Sachin Joseph
1
Dari pengalaman pribadi saya ini sepertinya jawaban yang bagus, tipe mime saja tidak akan berfungsi di semua browser.
Christophe Roussy
1
Kebetulan acceptmasih tidak berfungsi di Edge: stackoverflow.com/questions/31875617/… . Lebih detail di sini: wpdev.uservoice.com/forums/257854-microsoft-edge-developer/…
SharpC
1
Saya berharap kami punya pilihan untuk mengecualikan file juga, misalnya exclude="exe". ¯_ (ツ) _ / ¯
Sagiv bg
1
Untuk memperjelas perilaku Edge lebih lanjut (menurut pengujian saya), itu akan menambahkan filter berbeda berdasarkan apa yang Anda tentukan, tetapi a) itu tidak dibundel, sehingga akan mencantumkan setiap ekstensi sebagai opsi terpisah dan b) itu akan selalu menambahkan beberapa informasi tambahan. membangun ekstensi seperti .html, dan c) sebagaimana telah dinyatakan, ekstensi akan selalu dipilih sebelumnya (*). Yang membuatnya berantakan besar dan tidak berguna dalam banyak kasus. Saya memberi suara pada tautan uservoice, mari berharap mereka mendengarkan cepat atau lambat.
Arie
198

Ada atribut accept untuk tag input. Namun, itu tidak dapat diandalkan dengan cara apa pun. Peramban kemungkinan besar memperlakukannya sebagai "saran", yang berarti pengguna akan, tergantung pada pengelola file juga, memiliki pilihan awal yang hanya menampilkan jenis yang diinginkan. Mereka masih dapat memilih "semua file" dan mengunggah file apa pun yang mereka inginkan.

Sebagai contoh:

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

Baca lebih lanjut di spec HTML5

Perlu diingat bahwa itu hanya untuk digunakan sebagai "bantuan" bagi pengguna untuk menemukan file yang tepat. Setiap pengguna dapat mengirim permintaan apa pun yang dia inginkan ke server Anda. Anda selalu harus memvalidasi semua sisi server.

Jadi jawabannya adalah: tidak, Anda tidak dapat membatasi , tetapi Anda dapat mengatur pra-pemilihan tetapi Anda tidak dapat mengandalkannya.

Sebagai alternatif atau tambahan, Anda dapat melakukan sesuatu yang serupa dengan memeriksa nama file (nilai bidang input) dengan JavaScript, tetapi ini tidak masuk akal karena tidak memberikan perlindungan dan juga tidak memudahkan pemilihan bagi pengguna. Itu hanya berpotensi menipu webmaster untuk berpikir bahwa dia dilindungi dan membuka celah keamanan. Ini bisa menyebalkan bagi pengguna yang memiliki ekstensi file alternatif (misalnya jpeg alih-alih jpg), huruf besar, atau tidak ada ekstensi file apa pun (seperti yang biasa terjadi pada sistem Linux).

The Surrican
sumber
3
untuk informasi tambahan, lihat stackoverflow.com/questions/181214/…
Martin Meeser
1
Meskipun benar bahwa tidak mungkin untuk mencegah pengguna dari memilih jenis file APAPUN pada akhirnya, hari ini Anda dapat memanfaatkan File API HTML5 dan bekerja dengan file yang dipilih untuk diunggah, sebelum benar-benar diunggah ke server, termasuk mendeteksi jenisnya, ukuran dan banyak lagi. Cobalah. Ini sangat mudah digunakan, namun sangat kuat dan bermanfaat.
TheCuBeMan
96

Anda dapat menggunakan changeacara tersebut untuk memantau apa yang dipilih pengguna dan memberi tahu mereka pada saat itu bahwa file tersebut tidak dapat diterima. Itu tidak membatasi daftar aktual file yang ditampilkan, tetapi ini adalah yang terdekat yang dapat Anda lakukan di sisi klien, selain acceptatribut yang didukung kurang .

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

Gabriele Petrioli
sumber
11
@ Jo, ini adalah contoh ... itu bisa meluas ke ekstensi apa pun yang ingin Anda izinkan.
Gabriele Petrioli
ya kamu bisa. tetapi Anda TIDAK! dan maby seseorang sudah menyalinnya! dan bagaimana dengan file dengan tipe mime yang benar tetapi tanpa ekstensi?
The Surrican
49
@ Jo .. yah .. saya mencoba memberikan arahan dan logika suara. Tidak sepenuhnya solusi yang diimplementasikan untuk setiap kasus. Saya percaya pemirsa menggunakan akal sehat saat menyalin / menempelkan kode dari web;)
Gabriele Petrioli
7
Bagaimana dengan "Some.File.jpg"? Mungkin garis regex itu perlu dibaca: var ext = this.value.match (/ \. ([^.] +) $ /) [1];
Jon Kloske
Masalah dengan pendekatan ini adalah bahwa sesuatu secara teknis masih bisa menjadi jpeg bahkan jika itu tidak berakhir dengan ekstensi itu. Ekstensi! == jenis mime
Matt Fletcher
46

Ya kamu benar. Tidak mungkin dengan HTML. Pengguna akan dapat memilih file apa pun yang dia inginkan.

Anda bisa menulis sepotong JavaScript kode untuk menghindari pengiriman file berdasarkan ekstensi. Tetapi perlu diingat bahwa ini tidak berarti akan mencegah pengguna jahat untuk mengirimkan file apa pun yang ia inginkan.

Sesuatu seperti:

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

Kode HTML:

<form method="post" onsubmit="return beforeSubmit();">
    <input type="file" id="ifile" name="ifile"/>
</form>
Pablo Santa Cruz
sumber
3
ada atribut html yang sepenuhnya valid untuk itu sehingga dimungkinkan. itu tidak dihormati oleh browser, tapi itu masalah standardisasi. serta hal-hal yang ditangani pihak klien dalam markup yang tidak dilindungi tidak dapat membatasi skrip java apa pun bukanlah solusi.
The Surrican
2
Poin yang sangat bagus. Saya akan menambahkan pemeriksa PHP kedua untuk jaga-jaga. Tidak bisa terlalu hati-hati!
Bojangles
2
Yah, tidak ada salahnya jika saya menggunakan skrip validasi PHP juga, jadi saya akan menggunakan keduanya.
Bojangles
17
@ Jo: berhenti mengatakan bahwa jawaban saya menyebalkan! :-) Bagaimanapun, ini bukan solusi yang sempurna. Seperti yang saya katakan di awal: "tidak mungkin" melakukan apa yang diinginkan OP. Tetapi Anda dapat memiliki beberapa tingkat bantuan bagi pengguna jika Anda hanya membiarkannya memilih file dengan ekstensi tertentu. Validasi jenis file NYATA harus dilakukan di sisi server .
Pablo Santa Cruz
11
@ JoHopfgartner: Bung, kau terlalu keras untuk Pablo di sini. validasi di sisi klien dilakukan di banyak tempat dan meskipun tidak mudah (harus [b] selalu ada [/ b] termasuk validasi di sisi server) ini dapat menghemat waktu pengguna (tidak ada postback untuk pemeriksaan ekstensi bodoh dll). Meskipun skrip yang diberikan oleh Pablo tidak sempurna, itu hanya dimaksudkan untuk menjadi contoh bagaimana mengatasi masalah ini ... Mungkin Anda harus mengirim surel ke orang-orang teknologi di Microsoft dan meminta mereka untuk menghapus validasi Clientside dari validator ASP.NET mereka sejak itu semua sampah biasa bagimu ...
Nathan
18

Secara teknis Anda dapat menentukan acceptatribut (alternatif di html5 ) pada inputelemen, tetapi tidak didukung dengan benar.

zzzzBov
sumber
Dukungan browser W3Schools gagal! Sayang sekali kok. Ini juga merupakan masalah keamanan - orang dapat meretas kode sisi klien masa lalu dan mengunggah apa pun yang mereka inginkan.
Bojangles
5
Benar, yang terbaik adalah tidak menggunakan ini untuk keamanan, tetapi jelas membantu kegunaan pada browser yang mendukungnya. Pengguna hanya diperlihatkan file yang diizinkan situs (tidak semua sampah lain yang mungkin mereka miliki di folder yang sama) dan mereka tidak harus melalui seluruh proses unggahan untuk diberi kesalahan, mereka akan langsung tahu. Coder harus menggunakan ini.
Simon East
10

Gunakan inputtag dengan acceptatribut

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

Klik di sini untuk tabel kompatibilitas browser terbaru

Demo langsung di sini

Untuk hanya memilih file gambar, Anda dapat menggunakan ini accept="image/*"

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

Demo langsung di sini

Hanya gif, jpg, dan png yang akan ditampilkan, ambil layar dari Chrome versi 44 Hanya gif, jpg, dan png yang akan ditampilkan, ambil layar dari Chrome versi 44

kiranvj
sumber
Terima kasih! Di Chrome pada Win10, jika saya menggunakan accept="image/*", ia mengatakan "File Gambar" bukan "File Kustom" di pemilih file, yang bagus untuk pengguna akhir.
Teddy
Tetapi pengguna dapat mengubahnya dan mengunggah file ekstensi lainnya
Prashant Prajapati
@ PrashantPrajapati Ya, begitulah browser dibuat, harus ada validasi yang sesuai di server. Fungsionalitas browser hanya untuk pengalaman pengguna yang lebih baik.
kiranvj
9

Saya tahu ini agak terlambat.

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
sumber
5

Anda sebenarnya dapat melakukannya dengan javascript tetapi ingat js adalah sisi klien, jadi Anda sebenarnya akan "memperingatkan pengguna" jenis file apa yang dapat mereka unggah, jika Anda ingin MENGHINDARI (membatasi atau membatasi seperti yang Anda katakan) jenis file tertentu yang HARUS DILAKUKAN. lakukan di sisi server.

Lihatlah tut dasar ini jika Anda ingin memulai dengan validasi sisi server. Untuk keseluruhan tutorial, kunjungi halaman ini .

Semoga berhasil!

Trufa
sumber
4

Seperti disebutkan dalam jawaban sebelumnya, kami tidak dapat membatasi pengguna untuk memilih file hanya untuk format file yang diberikan. Tapi itu sangat berguna untuk menggunakan tag accept pada atribut file dalam html.

Adapun validasi, kita harus melakukannya di sisi server. Kita juga bisa melakukannya di sisi klien dalam js tetapi itu bukan solusi yang mudah. Kita harus memvalidasi di sisi server.

Untuk persyaratan ini saya sangat suka kerangka kerja pengembangan aplikasi web struts2 Java. Dengan fitur unggah file bawaannya, mengunggah file ke aplikasi web berbasis struts2 adalah hal yang mudah. Cukup sebutkan format file yang ingin kami terima di aplikasi kami dan sisanya diurus oleh inti kerangka itu sendiri. Anda dapat memeriksanya di situs resmi struts.

svg
sumber
3

Saya dapat menyarankan berikut:

  • Jika Anda harus membuat pengguna memilih salah satu file gambar secara default, gunakan accept = "image / *"

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

  • jika Anda ingin membatasi untuk tipe gambar tertentu maka gunakan accept = "image / bmp, image / jpeg, image / png"

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

  • jika Anda ingin membatasi untuk tipe tertentu maka gunakan accept = ". bmp, .doc, .pdf"

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

  • Anda tidak dapat membatasi pengguna untuk mengubah file filer ke semua file, jadi selalu memvalidasi jenis file dalam skrip dan server

Imran Javed
sumber
1
Ini yang saya cari: accept = ". Bmp" Bekerja dengan baik di chrome.
MichaelRom