Saya telah membaca ini dan ini pertanyaan yang tampaknya menunjukkan bahwa file tipe MIME dapat diperiksa menggunakan javascript di sisi client. Sekarang, saya mengerti bahwa validasi sebenarnya masih harus dilakukan di sisi server. Saya ingin melakukan pengecekan sisi klien untuk menghindari pemborosan sumber daya server yang tidak perlu.
Untuk menguji apakah ini dapat dilakukan di sisi klien, saya mengubah ekstensi JPEG
file uji .png
dan memilih file untuk diunggah. Sebelum mengirim file, saya meminta objek file menggunakan konsol javascript:
document.getElementsByTagName('input')[0].files[0];
Ini yang saya dapatkan di Chrome 28.0:
File {webkitRelativePath: "", lastModifiedDate: Sel 16 Okt 2012 10:00:00 GMT + 0000 (UTC), nama: "test.png", ketik: "image / png", ukuran: 500055 ...}
Ini menunjukkan tipe image/png
yang tampaknya mengindikasikan bahwa pemeriksaan dilakukan berdasarkan ekstensi file, bukan tipe MIME. Saya mencoba Firefox 22.0 dan memberi saya hasil yang sama. Namun menurut spesifikasi W3C , MIME Sniffing harus diimplementasikan.
Apakah saya berhak mengatakan bahwa tidak ada cara untuk memeriksa jenis MIME dengan javascript saat ini? Atau apakah saya melewatkan sesuatu?
sumber
I want to perform a client side checking to avoid unnecessary wastage of server resource.
Saya tidak mengerti bagaimana mengapa Anda mengatakan bahwa validasi harus dilakukan di sisi server, tetapi kemudian katakan Anda ingin mengurangi sumber daya server. Aturan emas: Jangan pernah percaya pada input pengguna . Apa gunanya memeriksa tipe MIME di sisi klien jika Anda hanya melakukannya di sisi server. Tentunya itu adalah "pemborosan sumber daya klien yang tidak perlu "?type
properti untukFile
objek. Kode sumber webkit, misalnya, mengungkapkan kebenaran ini. Dimungkinkan untuk secara akurat mengidentifikasi file sisi klien dengan mencari "byte ajaib" dalam file, antara lain. Saat ini saya sedang mengerjakan perpustakaan MIT (dalam waktu senggang apa saya punya) yang akan melakukan itu. Jika Anda tertarik dengan kemajuan saya, lihat di github.com/rnicholus/determinater .image/jpeg
, dan Anda tidak benar-benar memodifikasinya dengan mengubah ekstensi?Jawaban:
Anda dapat dengan mudah menentukan jenis file MIME dengan JavaScript
FileReader
sebelum mengunggahnya ke server. Saya setuju bahwa kita harus memilih pemeriksaan sisi-server daripada sisi-klien, tetapi pemeriksaan sisi-klien masih memungkinkan. Saya akan menunjukkan caranya dan memberikan demo yang berfungsi di bagian bawah.Pastikan browser Anda mendukung keduanya
File
danBlob
. Semua yang utama harus.Langkah 1:
Anda dapat mengambil
File
informasi dari<input>
elemen seperti ini ( ref ):Berikut ini adalah versi drag-and-drop di atas ( ref ):
Langkah 2:
Kami sekarang dapat memeriksa file dan mencari header dan tipe MIME.
✘ Metode cepat
Anda bisa bertanya kepada Blob tentang jenis file MIME apa pun yang diwakilinya menggunakan pola ini:
Untuk gambar, tipe MIME kembali seperti berikut:
Peringatan: Jenis MIME terdeteksi dari ekstensi file dan bisa dibodohi atau dipalsukan. Satu dapat mengubah nama
.jpg
ke.png
dan jenis MIME akan dilaporkan sebagaiimage/png
.✓ Metode pemeriksaan header yang benar
Untuk mendapatkan tipe MIME bonafide dari file sisi klien, kita dapat melangkah lebih jauh dan memeriksa beberapa byte pertama dari file yang diberikan untuk membandingkan dengan apa yang disebut angka ajaib . Berhati-hatilah karena itu tidak sepenuhnya langsung karena, misalnya, JPEG memiliki beberapa "angka ajaib". Ini karena formatnya telah berevolusi sejak 1991. Anda mungkin lolos hanya dengan memeriksa dua byte pertama, tetapi saya lebih suka memeriksa setidaknya 4 byte untuk mengurangi false positive.
Contoh tanda tangan file JPEG (4 byte pertama):
Berikut adalah kode penting untuk mengambil file header:
Anda kemudian dapat menentukan tipe MIME yang sebenarnya seperti itu (lebih banyak tanda tangan file di sini dan di sini ):
Terima atau tolak unggahan file sesuai keinginan berdasarkan jenis MIME yang diharapkan.
Demo
Ini demo yang berfungsi untuk file lokal dan file jarak jauh (saya harus mem-bypass CORS hanya untuk demo ini). Buka cuplikan, jalankan, dan Anda akan melihat tiga gambar jarak jauh dari berbagai jenis ditampilkan. Di bagian atas Anda dapat memilih file gambar atau data lokal , dan tanda tangan file dan / atau tipe MIME akan ditampilkan.
Perhatikan bahwa meskipun gambar diubah namanya, jenis MIME yang sebenarnya dapat ditentukan. Lihat di bawah.
Tangkapan layar
Tampilkan cuplikan kode
sumber
fileReader.readAsArrayBuffer(blob.slice(0,4))
? (2) Untuk menyalin / menempelkan tanda tangan file, bukankah header harus dibuat dengan memimpin 0for(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. Bagian penting dari tanda tangan JPEG hanya 2 byte, tetapi untuk mengurangi false positive saya menambahkan tanda tangan 4-byte yang paling umum. Saya harap itu membantu.fileReader.readAsArrayBuffer(blob.slice(0, 4))
Seperti yang dinyatakan dalam jawaban lain, Anda dapat memeriksa jenis pantomim dengan memeriksa tanda tangan file dalam byte pertama file.
Tapi apa jawaban lain yang dilakukan adalah memuat seluruh file dalam memori untuk memeriksa tanda tangan, yang sangat boros dan dapat dengan mudah membekukan browser Anda jika Anda memilih file besar secara tidak sengaja atau tidak.
sumber
readyState
akan selalu adaFileReader.DONE
di event handler ( spec W3C ) bahkan jika ada kesalahan - bukankah seharusnya cek itu kalau(!e.target.error)
bukan?Bagi siapa pun yang ingin tidak menerapkan ini sendiri, Sindresorhus telah membuat utilitas yang berfungsi di browser dan memiliki pemetaan header-to-mime untuk sebagian besar dokumen yang Anda inginkan.
https://github.com/sindresorhus/file-type
Anda dapat menggabungkan saran Vitim.us untuk hanya membaca dalam byte X pertama untuk menghindari memuat semuanya ke dalam memori dengan menggunakan utilitas ini (contoh dalam es6):
sumber
"file-type": "12.4.0"
bekerja dan saya harus menggunakanimport * as fileType from "file-type";
Jika Anda hanya ingin memeriksa apakah file yang diunggah adalah gambar, Anda bisa mencoba memuatnya ke dalam
<img>
tag untuk memeriksa kesalahan panggilan balik.Contoh:
sumber
Inilah yang harus Anda lakukan
Jika Anda ingin memeriksa jenis file gambar maka
sumber
Berikut ini adalah implementasi Typescript yang mendukung webp. Ini didasarkan pada jawaban JavaScript oleh Vitim.us.
sumber
Seperti yang dikatakan Drake, ini bisa dilakukan dengan FileReader. Namun, apa yang saya sajikan di sini adalah versi fungsional. Mempertimbangkan bahwa masalah besar dengan melakukan ini dengan JavaScript adalah mengatur ulang file input. Nah, ini membatasi hanya JPG (untuk format lain Anda harus mengubah tipe mime dan angka ajaib ):
Pertimbangkan bahwa ini diuji pada versi terbaru Firefox dan Chrome, dan pada IExplore 10.
Untuk daftar lengkap tipe pantomim, lihat Wikipedia .
Untuk daftar lengkap angka ajaib, lihat Wikipedia .
sumber
Berikut ini adalah perpanjangan dari jawaban Roberto14 yang melakukan hal berikut:
INI HANYA AKAN MENGIZINKAN GAMBAR
Memeriksa apakah FileReader tersedia dan kembali ke pemeriksaan ekstensi jika tidak tersedia.
Memberikan peringatan kesalahan jika bukan gambar
Jika ini adalah gambar, ia memuat pratinjau
** Anda masih harus melakukan validasi sisi server, ini lebih merupakan kenyamanan bagi pengguna akhir daripada yang lainnya. Tapi ini berguna!
sumber
Jawaban singkatnya adalah tidak.
Seperti yang Anda perhatikan, browser berasal
type
dari ekstensi file. Pratinjau Mac juga tampaknya menjalankan ekstensi. Saya berasumsi karena lebih cepat membaca nama file yang terdapat dalam pointer, daripada melihat ke atas dan membaca file pada disk.Saya membuat salinan jpg berganti nama menjadi png.
Saya dapat secara konsisten mendapatkan yang berikut dari kedua gambar di chrome (harus bekerja di browser modern).
ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
Yang mana Anda bisa meretas cek String.indexOf ('jpeg') untuk jenis gambar.
Berikut adalah biola untuk mengeksplorasi http://jsfiddle.net/bamboo/jkZ2v/1/
Garis yang ambigius yang saya lupa komentari dalam contoh ini
console.log( /^(.*)$/m.exec(window.atob( image.src.split(',')[1] )) );
Kode biola menggunakan decode base64 yang tidak akan berfungsi di IE9, saya memang menemukan contoh yang bagus menggunakan skrip VB yang bekerja di IE http://blog.nihilogic.dk/2008/08/imageinfo-reading-image-metadata-with.html
Kode untuk memuat gambar diambil dari Joel Vardy, yang sedang melakukan beberapa penyesuaian ukuran kanvas gambar sisi klien sebelum mengunggah yang mungkin menarik https://joelvardy.com/writing/javascript-image-upload
sumber
JFIF
gantinya, wellAPP0
tidak harus mengandung JFIF dalam EXIF-JPEG jadi itu juga keluar).