[PHP] Sprawdzanie typu (MIME) pliku

Witajcie po bardzo długiej przerwie. W wyniku kilku spraw nie mogłem znaleźć weny i czasu na naskrobanie czegoś na bloga. Nadszedł czas troszkę to nadrobić - zacznę, mam nadzieję, konkretnie.

Dziś na warsztat pójdzie sprawdzanie typu pliku na podstawie jego MIME. Jak dobrze wiadomo, sprawdzanie po rozszerzeniu jest niepewną i ryzykowną formą - rozszerzenie można zmienić, a nieraz (wskutek takiej czy innej konfiguracji serwera) można wykonać plik zamaskowany rozszerzeniem .jpg jako normalny plik PHP. Potencjalnych skutków chyba nie trzeba opisywać ;) Przechodząc do rzeczy:

1) Korzystając z klasy Fileinfo

To rozszerzenie PHP powstało właśnie do tego celu i jest aktualnie najlepszą metodą na osiągnięcie naszego celu. Poniżej krótki i treściwy przykład działania klasy.

<?php 
$file1 = 'image.png'; // Faktyczny obrazek w PNG
$file2 = 'kod.png'; // Plik PHP ze zmienionym rozszerzeniem

$finfo = new finfo(FILEINFO_MIME);

echo $finfo->file($file1, FILEINFO_MIME_TYPE); // Wyświetli: image/png
echo $finfo->file($file2, FILEINFO_MIME_TYPE); // Wyświetli: text/x-php

W tym miejscu już doskonale widać przewagę tego rozwiązania nad sprawdzaniem rozszerzenia pliku - oszust został zdemaskowany.

2)  Poprzez funkcję mime_content_type

Uwaga, ten sposób jest gorszy! Wspomniana funkcja została zdeprecjonowana i nie powinno się jej używać. Jednakże dosyć często zachodzi sytuacja, w której na serwerze nie jest dostępna pierwsza metoda (klasa fileinfo), a możemy użyć owej funkcji - dlatego o niej wspominam.

<?php
echo mime_content_type('php.gif'); // Wyświetli: image/gif

3) Sprawdzanie typu pliku po jego zawartości

Każdy typ pliku zawiera na swoim początku zestaw charakterystycznych dla niego kilku bajtów. Sprawdzając je, możemy określić typ pliku - należy jednak wspomnieć, że to właśnie z tej metody korzystają powyższe rozwiązania, więc zabawę z ręczną jej implementacją możemy rozpocząć gdy jesteśmy zdesperowani i nie mamy żadnej z powyższych możliwości.

Poniżej krótki przykład, pobranie trzech pierwszych bajtów pliku, skonwertowanie ich do postaci heksadecymalnej i porównanie ich z bajtami charakterystycznymi dla pliku MP3

<?php
$file = fopen('plik.mp3', 'r');
$bytes = bin2hex(fread($file, 3));

if($bytes == '494433') {
    // Sprawdzany plik jest plkiem MP3
}
else {
    // Inny plik
}

fclose($file);

Dużą listę takich charakterystycznych bajtów możecie znaleźć tutaj, można też skorzystać z serwisu FileExt.com.

Mam nadzieję, że komuś przydał się ten wpis. Dziękuję za uwagę :)

4 komentarze do “[PHP] Sprawdzanie typu (MIME) pliku

  1. Ta… Ciekawe co to za sprawy były ;) Sprawdzanie nagłówków także może być niepewne swoją drogą. Nagłówek może sugerować zawartość jakiej można się spodziewać po pliku lecz plik może być czymś innym. W drugim listingu masz błąd to jest zamiast _ masz spacje.

    PS
    Ostyluj ten button od formularza z komentarzami.

    • Sobak pisze:

      1) Oczywiście, nagłówki też można podstawić inne, jednak na pewno jest to pewniejsza metoda niż sprawdzanie po rozszerzeniu (lub odczytywanie z tablicy $_FILES przy uploadzie).

      2) Listing #2 jest poprawny, spacje zamiast podkreślenia pojawiają się dopiero po wykonaniu dwukliku (widok do kopiowania), a błąd dodatkowo występuje tylko w Operze.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *