Przeczytałem to i to pytanie, które wydaje się sugerować, że typ MIME pliku można sprawdzić za pomocą javascript po stronie klienta. Teraz rozumiem, że prawdziwa walidacja nadal musi zostać przeprowadzona po stronie serwera. Chcę przeprowadzić kontrolę po stronie klienta, aby uniknąć niepotrzebnego marnowania zasobów serwera.
Aby sprawdzić, czy można to zrobić po stronie klienta, zmieniłem rozszerzenie JPEG
pliku testowego na .png
i wybrałem plik do przesłania. Przed wysłaniem pliku odpytuję obiekt pliku za pomocą konsoli javascript:
document.getElementsByTagName('input')[0].files[0];
Oto, co otrzymuję w Chrome 28.0:
Plik {webkitRelativePath: "", lastModifiedDate: wt. 16 października 2012 10:00:00 GMT + 0000 (UTC), nazwa: "test.png", typ: "image / png", rozmiar: 500055…}
Pokazuje typ, image/png
który wydaje się wskazywać, że sprawdzanie odbywa się na podstawie rozszerzenia pliku zamiast typu MIME. Wypróbowałem Firefox 22.0 i daje mi ten sam wynik. Ale zgodnie ze specyfikacją W3C , MIME Sniffing powinno być zaimplementowane .
Czy mam rację mówiąc, że w tej chwili nie ma możliwości sprawdzenia typu MIME za pomocą javascript? A może coś mi brakuje?
źródło
I want to perform a client side checking to avoid unnecessary wastage of server resource.
Nie rozumiem, dlaczego mówisz, że walidacja musi być wykonywana po stronie serwera, ale potem mówisz, że chcesz zmniejszyć zasoby serwera. Złota zasada: nigdy nie ufaj wprowadzaniu danych przez użytkownika . Jaki jest sens sprawdzania typu MIME po stronie klienta, jeśli robisz to po prostu po stronie serwera. Z pewnością jest to „niepotrzebne marnotrawstwo zasobów klienta ”?type
właściwościFile
obiektów. Na przykład kod źródłowy webkita ujawnia tę prawdę. Możliwe jest dokładne zidentyfikowanie plików po stronie klienta, między innymi wyszukując w nich „magiczne bajty”. Obecnie pracuję nad biblioteką MIT (w jakim mam wolny czas), która właśnie to zrobi. Jeśli jesteś zainteresowany moimi postępami, zajrzyj na github.com/rnicholus/determinater .image/jpeg
i nie zmodyfikowałeś go, zmieniając rozszerzenie?Odpowiedzi:
Możesz łatwo określić typ MIME pliku za pomocą JavaScript
FileReader
przed przesłaniem go na serwer. Zgadzam się, że powinniśmy preferować sprawdzanie po stronie serwera niż po stronie klienta, ale sprawdzanie po stronie klienta jest nadal możliwe. Pokażę ci, jak i zapewnię działające demo na dole.Sprawdź, czy Twoja przeglądarka obsługuje zarówno
File
iBlob
. Wszystkie najważniejsze powinny.Krok 1:
Możesz pobrać
File
informacje z<input>
elementu takiego jak ten ( ref ):Oto wersja powyższego ( ref ) typu „przeciągnij i upuść” :
Krok 2:
Możemy teraz przeglądać pliki i usuwać nagłówki oraz typy MIME.
✘ Szybka metoda
Możesz naiwnie zapytać Bloba o typ MIME dowolnego pliku, który reprezentuje, używając tego wzorca:
W przypadku obrazów typy MIME powracają w następujący sposób:
Uwaga: typ MIME jest wykrywany na podstawie rozszerzenia pliku i może zostać oszukany lub sfałszowany. Można zmienić nazwę a
.jpg
na a,.png
a typ MIME zostanie zgłoszony jakoimage/png
.✓ Właściwa metoda kontroli nagłówka
Aby uzyskać prawdziwy typ MIME pliku po stronie klienta, możemy pójść o krok dalej i sprawdzić kilka pierwszych bajtów danego pliku, aby porównać je z tak zwanymi liczbami magicznymi . Ostrzegamy, że nie jest to całkowicie proste, ponieważ na przykład JPEG ma kilka „magicznych liczb”. Dzieje się tak, ponieważ format ewoluował od 1991 roku. Możesz uciec od sprawdzania tylko pierwszych dwóch bajtów, ale ja wolę sprawdzić co najmniej 4 bajty, aby zredukować fałszywe alarmy.
Przykładowe podpisy plików JPEG (pierwsze 4 bajty):
Oto podstawowy kod do pobrania nagłówka pliku:
Następnie możesz określić rzeczywisty typ MIME w ten sposób (więcej sygnatur plików tutaj i tutaj ):
Akceptuj lub odrzucaj przesyłanie plików, jak chcesz, na podstawie oczekiwanych typów MIME.
Próbny
Oto działające demo dla plików lokalnych i plików zdalnych (musiałem ominąć CORS tylko dla tego demo). Otwórz fragment kodu, uruchom go i powinieneś zobaczyć trzy zdalne obrazy różnych typów. U góry możesz wybrać lokalny obraz lub plik danych, a zostanie wyświetlony podpis pliku i / lub typ MIME.
Zauważ, że nawet jeśli nazwa obrazu zostanie zmieniona, można określić jego prawdziwy typ MIME. Zobacz poniżej.
Zrzut ekranu
Pokaż fragment kodu
źródło
fileReader.readAsArrayBuffer(blob.slice(0,4))
? (2) Czy aby skopiować / wkleić podpisy plików, czy nagłówek nie powinien zawierać początkowych zerfor(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. Kluczowa część podpisu JPEG ma tylko 2 bajty, ale aby zredukować fałszywe alarmy, dodałem najpopularniejsze 4-bajtowe podpisy. Mam nadzieję że to pomogło.fileReader.readAsArrayBuffer(blob.slice(0, 4))
Jak stwierdzono w innych odpowiedziach, typ MIME można sprawdzić, sprawdzając podpis pliku w pierwszych bajtach pliku.
Ale inne odpowiedzi to ładowanie całego pliku do pamięci w celu sprawdzenia podpisu, co jest bardzo marnotrawne i może łatwo zawiesić przeglądarkę, jeśli przez przypadek wybierzesz duży plik lub nie.
źródło
readyState
zawsze będzieFileReader.DONE
w programie obsługi zdarzeń ( specyfikacja W3C ), nawet jeśli wystąpił błąd - czy nie powinno być sprawdzania, czy(!e.target.error)
zamiast tego?Dla każdego, kto nie chce wdrożyć tego samodzielnie, Sindresorhus stworzył narzędzie, które działa w przeglądarce i ma odwzorowania nagłówka na mime dla większości dokumentów, które chcesz.
https://github.com/sindresorhus/file-type
Możesz połączyć sugestię Vitim.us, aby czytać tylko pierwsze X bajtów, aby uniknąć ładowania wszystkiego do pamięci za pomocą tego narzędzia (przykład w es6):
źródło
"file-type": "12.4.0"
działała i musiałem korzystaćimport * as fileType from "file-type";
Jeśli chcesz tylko sprawdzić, czy przesłany plik jest obrazem, możesz po prostu spróbować załadować go do
<img>
tagu i sprawdzić, czy nie ma żadnego wywołania zwrotnego.Przykład:
źródło
Oto, co musisz zrobić
Jeśli chcesz sprawdzić typy plików obrazów, to
źródło
Oto implementacja Typescript obsługująca webp. Jest to oparte na odpowiedzi JavaScript firmy Vitim.us.
źródło
Jak twierdzi Drake, można to zrobić za pomocą FileReader. Jednak to, co tu przedstawiam, to wersja funkcjonalna. Weź pod uwagę, że dużym problemem przy robieniu tego w JavaScript jest zresetowanie pliku wejściowego. Cóż, ogranicza się to tylko do JPG (w przypadku innych formatów będziesz musiał zmienić typ MIME i magiczną liczbę ):
Weź pod uwagę, że zostało to przetestowane w najnowszych wersjach przeglądarek Firefox i Chrome oraz w IExplore 10.
Pełną listę typów MIME można znaleźć w Wikipedii .
Pełną listę magicznych liczb można znaleźć w Wikipedii .
źródło
Oto rozszerzenie odpowiedzi Roberto14, które wykonuje następujące czynności:
POZWOLI TYLKO NA OBRAZY
Sprawdza, czy FileReader jest dostępny i wraca do sprawdzania rozszerzenia, jeśli nie jest dostępne.
Daje alert o błędzie, jeśli nie jest obrazem
Jeśli jest to obraz, wczytuje podgląd
** Nadal powinieneś przeprowadzić walidację po stronie serwera, jest to bardziej wygoda dla użytkownika końcowego niż cokolwiek innego. Ale jest poręczny!
źródło
Krótka odpowiedź brzmi: nie.
Jak zauważyłeś, przeglądarki wywodzą się
type
z rozszerzenia pliku. Wydaje się, że podgląd na Maca również działa bez rozszerzenia. Zakładam, że to dlatego, że szybciej odczytuje nazwę pliku zawartą we wskaźniku, zamiast patrzeć w górę i czytać plik na dysku.Zrobiłem kopię pliku jpg o zmienionej nazwie na png.
Udało mi się konsekwentnie uzyskać następujące informacje z obu obrazów w chrome (powinno działać w nowoczesnych przeglądarkach).
ÿØÿàJFIFÿþ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90
Które możesz zhakować String.indexOf ('jpeg') sprawdzanie typu obrazu.
Oto skrzypce do odkrycia http://jsfiddle.net/bamboo/jkZ2v/1/
Niejednoznaczna linia, o której zapomniałem skomentować w przykładzie
console.log( /^(.*)$/m.exec(window.atob( image.src.split(',')[1] )) );
Kod skrzypcowy wykorzystuje dekodowanie base64, które nie działa w IE9, znalazłem fajny przykład użycia skryptu VB, który działa w IE http://blog.nihilogic.dk/2008/08/imageinfo-reading-image-metadata-with.html
Kod do załadowania obrazu pochodzi od Joela Vardy'ego, który przed załadowaniem robi fajne płótno do zmiany rozmiaru obrazu, co może być interesujące https://joelvardy.com/writing/javascript-image-upload
źródło
JFIF
zamiast tego, cóżAPP0
, nie musi zawierać JFIF w plikach EXIF-JPEG, więc to też się skończyło).