Определение MIME-типов файлов в PHP

Раздел: Основы программирования на PHP -> Типы данных в PHP

MIME-типы в PHP

Наиболее эффективное решение: расширение Fileinfo (finfo)

Для надёжного определения MIME-типа файла в PHP рекомендуется использовать расширение Fileinfo. Оно анализирует сигнатуры (магические байты) содержимого, а не только расширение. Это гарантирует точность независимо от того, какое имя файла присвоено.

// Проверка наличия расширения
if (!extension_loaded('fileinfo')) {
    echo 'Расширение fileinfo не загружено';
    exit;
}

$filename = 'example.pdf';
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($filename);
echo $mime; // application/pdf

Php check type (проверка типа переменной в php)

Пошаговое объяснение

  • new finfo(FILEINFO_MIME_TYPE) - создаёт объект Fileinfo с режимом возврата только MIME-типа (без кодировки).
  • $finfo->file($filename) - анализирует указанный файл и возвращает строку MIME-типа.

Типичные проблемы и их решение

  • Ошибка: "Class 'finfo' not found" - расширение fileinfo не установлено или не включено в php.ini.
    Решение: Установите пакет php-fileinfo (например, sudo apt install php-fileinfo для Debian/Ubuntu) или раскомментируйте строку extension=fileinfo в php.ini.
  • Пустой результат или false: Файл не существует или недоступен для чтения.
    Решение: Перед вызовом проверьте существование файла is_file() и права доступа.

Как определить MIME-тип с помощью устаревшей функции mime_content_type?

Функция mime_content_type() - более старый способ, основанный на расширении fileinfo (внутренне), но она объявлена устаревшей и может быть удалена в будущем. Для новых проектов лучше использовать finfo.

$mime = mime_content_type('document.docx');
echo $mime; // application/vnd.openxmlformats-officedocument.wordprocessingml.document

Of type string is deprecated php (предупреждение об устаревании типа string в php)

Проблема:

В некоторых окружениях (например, Windows) функция может возвращать application/octet-stream для неизвестных типов, а на Linux - точный тип. Это связано с отсутствием базы данных magic. Установка расширения fileinfo решает проблему.

Как определить MIME-тип по расширению файла без анализа содержимого?

Иногда требуется быстрая (но менее точная) оценка на основе имени файла. Подходит для случаев, когда анализ содержимого невозможен (например, файл удалён, но известно расширение).

function mimeByExtension($filename) {
    $mimes = [
        'txt' => 'text/plain',
        'html' => 'text/html',
        'jpg' => 'image/jpeg',
        'png' => 'image/png',
        'pdf' => 'application/pdf',
        // ... другие типы
    ];
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return $mimes[$ext] ?? 'application/octet-stream';
}

echo mimeByExtension('image.jpg'); // image/jpeg

Php mime type (mime-типы в php)

Ошибки:

  • Расширение может быть подделано (например, файл .exe переименован в .jpg) - MIME-тип будет неверным.
  • Отсутствие соответствия в массиве - вернётся общий тип. Решение: дополнить массив всеми нужными расширениями.

Можно ли доверять MIME-типу из массива $_FILES?

При загрузке файла через форму PHP заполняет $_FILES['file']['type'] значением, переданным браузером. Это значение легко подделывается злоумышленником, так как оно берётся из HTTP-запроса.

// Ненадёжно!
$uploadedType = $_FILES['myfile']['type']; 
if ($uploadedType !== 'image/png') {
    exit('Только PNG разрешены');
}

Проблема:

Браузер может отправить произвольный MIME-тип. Например, вредоносный файл с маскировкой под PNG.
Решение: Никогда не полагайтесь на $_FILES['file']['type'] для безопасности. Используйте finfo для проверки содержимого после загрузки.

- Strict type php (строгая типизация в php)
- Php type int (тип int в php)
- Php 7 types (типы данных в php 7)

Расширенные примеры работы с MIME-типами в PHP

1. Определение MIME-типа из строки или потока (без сохранения файла)

Если данные уже находятся в памяти (например, загружены из базы данных или сгенерированы на лету), можно использовать finfo->buffer().

Пример
$data = file_get_contents('somefile.jpg');
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->buffer($data);
echo $mime; // image/jpeg
image/jpeg

2. Получение MIME-типа с кодировкой для текстовых файлов

По умолчанию FILEINFO_MIME_TYPE возвращает только тип. Константа FILEINFO_MIME вернёт строку с кодировкой.

Пример
$finfo = new finfo(FILEINFO_MIME);
echo $finfo->file('data.txt'); // text/plain; charset=utf-8
text/plain; charset=utf-8

3. Пакетная обработка нескольких файлов

Один объект finfo можно использовать многократно для ускорения.

Пример
$files = ['a.jpg', 'b.png', 'c.pdf'];
$finfo = new finfo(FILEINFO_MIME_TYPE);
foreach ($files as $f) {
    echo $f . ' => ' . $finfo->file($f) . PHP_EOL;
}
a.jpg => image/jpeg
b.png => image/png
c.pdf => application/pdf

4. Определение MIME-типа для содержимого из базы данных (BLOB)

Пример
// Предположим, у нас есть BLOB-поле из MySQL
$blob = $row['file_data']; // бинарные данные
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->buffer($blob);
echo $mime;

5. Обработка ошибок при отсутствии расширения fileinfo

Пример
if (!function_exists('finfo_open')) {
    // Запасной вариант: mime_content_type()
    $mime = mime_content_type($file);
} else {
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime = $finfo->file($file);
}
if ($mime === false) {
    // Ошибка: файл не найден или недоступен
    $mime = 'application/octet-stream';
}
echo $mime;

6. Сравнение производительности: finfo против mime_content_type

Выполним замер для 1000 файлов.

Пример
$files = glob('/var/www/html/*');
$start = microtime(true);
foreach ($files as $f) {
    if (is_file($f)) {
        mime_content_type($f);
    }
}
$elapsed1 = microtime(true) - $start;

$start = microtime(true);
$finfo = new finfo(FILEINFO_MIME_TYPE);
foreach ($files as $f) {
    if (is_file($f)) {
        $finfo->file($f);
    }
}
$elapsed2 = microtime(true) - $start;
echo "mime_content_type: $elapsed1 сек, finfo: $elapsed2 сек";
Примерный вывод:
mime_content_type: 0.045 сек, finfo: 0.038 сек

7. Определение MIME-типа для data URI

Пример
$dataUri = 'data:image/png;base64,iVBORw0KGgo...';
// Извлекаем только данные после запятой
$parts = explode(',', $dataUri, 2);
$raw = base64_decode($parts[1]);
$finfo = new finfo(FILEINFO_MIME_TYPE);
echo $finfo->buffer($raw); // image/png
image/png

8. Работа с пользовательскими магическими файлами

Можно загрузить собственную базу сигнатур (magic.mgc).

Пример
$finfo = new finfo(FILEINFO_MIME_TYPE, '/path/to/custom.magic');
echo $finfo->file('unknown.dat');

Примечание:

Если файл magic не найден, finfo автоматически использует системную базу. Ошибка возникает только при явном указании несуществующего файла.

MIME-типы в PHP - comments

En
Php mime type (php)