Глава 87 · Практика
Fileinfo: типы файлов, кодировки и все функции
Определение типа по содержимому: полный API finfo, все флаги, различия версий и применение при приёме документов.
Файл назван photo.jpg — есть ли внутри фотография?
Имя photo.jpg ещё не означает фотографию
В собственном учебном файле photo.jpg записан текст Hello world. Проверим, что определит сервер по содержимому.
- Имя: photo.jpg
Имя — строка. Суффикс не изменяет байты файла.
- finfo::file
FILEINFO_MIME_TYPE включает поиск предполагаемого формата по правилам libmagic.
- text/plain
По содержимому найден обычный текст.
- Проверка политики
Форма фотографии отвергнет тип. Совпадение допустимого типа потребовало бы дальнейшей проверки формата.
Fileinfo классифицирует содержимое эвристически. Права, размер, целостность формата и правила хранения остаются отдельными проверками.
К заявке приложили photo.jpg. В нашем архиве этот файл содержит обычный текст «Pickup order 104». Имя обещает фотографию, но не меняет байты. Fileinfo анализирует признаки содержимого и возвращает MIME-тип — имя предполагаемого формата, например image/jpeg или text/plain. Получим видимое решение: этот файл нельзя отправить в обработчик фотографий.
- photo.jpg содержит текст Pickup order 104
- new finfo(FILEINFO_MIME_TYPE) выбирает ответ в виде MIME
- finfo_file читает признаки содержимого
- text/plain → попросить настоящее изображение
| Запись | Что она делает |
|---|---|
| new finfo(FILEINFO_MIME_TYPE) | Создать объект определителя. Константа выбирает короткое MIME-имя вместо свободного описания. |
| finfo_file($detector, $path) | Передать определитель и путь. Возвращается строка предполагаемого типа либо false при отказе. |
| $type === 'image/jpeg' | Сравнить точное значение; расширение имени в этом сравнении не участвует. |
<?php
declare(strict_types=1);
$path = __DIR__ . '/photo.jpg';
$detector = new finfo(FILEINFO_MIME_TYPE);
$type = finfo_file($detector, $path);
if ($type === false) { throw new RuntimeException('Не определить тип'); }
echo 'Содержимое: ', file_get_contents($path);
echo 'Определённый тип: ', $type, "\n";
echo $type === 'image/jpeg' ? "Продолжить проверку JPEG.\n" : "Нужно настоящее изображение JPEG.\n";
Ожидаемый результат
Содержимое: Pickup order 104
Определённый тип: text/plain
Нужно настоящее изображение JPEG.
Это локальный документ из архива, не настоящая HTTP-загрузка. Fileinfo использует базу libmagic и эвристики: даже совпавший image/jpeg ещё потребует подходящего декодера, лимитов размеров и правил доступа. Имя photo.jpg и Content-Type от отправителя не доказывают формат.
| Что уже есть | Что передавать |
|---|---|
| Файл на диске | Путь в finfo_file или метод file: не требуется собирать весь файл в строку PHP. |
| Небольшая строка с самими байтами | Строку в finfo_buffer или метод buffer. Строка пути здесь будет прочитана как обычные буквы. |
| Много файлов | Создать один finfo перед циклом и использовать для каждого файла. |
| Один файл без специальных настроек | mime_content_type даёт короткий вызов. |
База magic содержит правила узнавания байтов и структуры, а не разрешения пользователей. Полный приём загрузки; Строки и байты; Объект и метод.
Установка, база сигнатур и переход от ресурса к объекту
Fileinfo по умолчанию входит в PHP; в Windows включают поставляемую php_fileinfo.dll через extension=fileinfo в используемом php.ini. Проверяйте отдельно CLI и веб-SAPI: их конфигурации могут различаться. libmagic входит в PHP с собственными исправлениями, поэтому результат и поддерживаемые форматы зависят от версии среды и базы.
- Проверили реальный SAPI и php.ini
- Расширение fileinfo загружено
- MAGIC не переопределяет базу неожиданно
- Собственные типовые файлы проверены на этой версии
<?php
declare(strict_types=1);
var_dump(extension_loaded('fileinfo'));
$detector = finfo_open(FILEINFO_MIME_TYPE);
if ($detector === false) { throw new RuntimeException('Cannot initialize detector'); }
echo get_debug_type($detector), "\n";
Ожидаемый результат
bool(true)
finfo
В PHP 8.1+ возвращается объект; is_resource больше не является проверкой успешного finfo_open. На PHP 8.0 возвращался ресурс, это подтверждено исходником тега 8.0.30.
Обычно используйте встроенную базу и не задавайте MAGIC. Собственную базу выбирают для специального формата и тестируют на своём наборе файлов; она не должна загружаться из произвольного пути посетителя. finfo_open и finfo::__construct объясняют отличие false от исключения.
Все флаги Fileinfo и длительность настройки
Флаг — именованное число, выбирающее режим libmagic. Совместимые режимы объединяются побитовым |. Флаги конструктора и set_flags сохраняются у объекта, ненулевые флаги file/buffer применяются только к одному вызову. FILEINFO_NONE в таком отдельном вызове не обнуляет прежнюю настройку.
- Объект создан с MIME_TYPE
- Один buffer вызван с MIME_ENCODING → us-ascii
- Следующий buffer без флага → text/plain
- set_flags(MIME_ENCODING) изменит все последующие вызовы
| Константа | Что меняется и где предел |
|---|---|
| FILEINFO_NONE | Без дополнительных режимов: описательное определение. В аргументе отдельного file/buffer значение 0 сохраняет настройки объекта; чтобы сбросить их, нужен set_flags(FILEINFO_NONE). |
| FILEINFO_SYMLINK | Режим libmagic для следования символическим ссылкам. Открытие пути также зависит от обёртки PHP/системы; отсутствие этого флага не является запретом перехода по ссылке или защитой пути. |
| FILEINFO_MIME_TYPE | Вернуть MIME-тип, например text/plain. Это удобно для точного списка допустимых типов. |
| FILEINFO_MIME_ENCODING | Вернуть предполагаемую кодировку, например us-ascii/utf-8/binary. Это эвристика, не строгая проверка всего формата. |
| FILEINFO_MIME | MIME-тип и charset вместе: text/plain; charset=utf-8. Комбинация MIME_TYPE | MIME_ENCODING. |
| FILEINFO_COMPRESS | Исторический режим анализа распакованного содержимого. В PHP отключён из-за проблем потокобезопасности; не обещайте автоматическую проверку всех вложенных архивов. |
| FILEINFO_DEVICES | Разрешает libmagic исследовать содержимое специальных блочных/символьных устройств. Для пользовательской загрузки обычного файла такой режим не нужен. |
| FILEINFO_CONTINUE | Продолжать поиск и возвращать все совпадения вместо первого. Результат может быть составной строкой; для проверки одного MIME-типа такой формат неудобен. |
| FILEINFO_PRESERVE_ATIME | По возможности сохранить исходное время доступа. Возможность зависит от платформы и прав; это не обещание отсутствия любого изменения метаданных. |
| FILEINFO_RAW | Не заменять непечатаемые символы описания октальными escape-последовательностями. При выводе в HTML всё равно требуется HTML-экранирование. |
| FILEINFO_EXTENSION | PHP 7.2+: предполагаемые расширения для найденного типа, иногда несколько через /, например jpeg/jpg/jpe/jfif. Если база не знает — ???. Это не имя загруженного файла и не безопасная политика его переименования. |
| FILEINFO_APPLE | Коды Apple creator/type, если известны базе. Специальные метаданные, не обычный MIME-тип. |
<?php
declare(strict_types=1);
var_dump(FILEINFO_MIME === (FILEINFO_MIME_TYPE | FILEINFO_MIME_ENCODING));
$detector = new finfo(FILEINFO_MIME);
echo $detector->buffer("Привет\n"), "\n";
Ожидаемый результат
bool(true)
text/plain; charset=utf-8
Этот ответ содержит параметры после точки с запятой. Если проверяете список форматов, заранее выберите MIME_TYPE, а не пытайтесь сравнить всю строку с text/plain.
Применение: принять файл, не доверяя имени и заголовку
Для загрузки сначала проверяют HTTP-метод, структуру $_FILES, код UPLOAD_ERR_*, доступ пользователя и лимит размера. Fileinfo получает серверный tmp_name после этих проверок. Предполагаемый MIME сравнивают с точным разрешённым набором. Затем выполняют подходящую проверку самого формата, назначают серверное имя и хранят файл с нужными ограничениями доступа и исполнения.
- Форма → $_FILES и код результата загрузки
- Размер/права/CSRF проверены
- Fileinfo → предполагаемый формат
- Проверка формата и безопасное хранение по правилам сервиса
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$type = $detector->file('photo.jpg');
if ($type === false) { throw new RuntimeException('Cannot detect type'); }
$allowed = ['image/jpeg', 'image/png'];
echo in_array($type, $allowed, true) ? 'continue format validation' : 'reject type';
echo "\n";
Ожидаемый результат
reject type
Это изолированная часть политики с собственным файлом, не проверка настоящей HTTP-загрузки. Успешное совпадение означало бы продолжение проверки формата, а не безусловное сохранение.
Не принимайте любой image/*: разные форматы имеют разные возможности. Даже распознанный тип не доказывает целостность или отсутствие опасных данных. Для изображения нужен подходящий декодер с ограничениями размера/ресурсов; архив и PDF требуют своих правил. Не открывайте загруженный файл через include. Полный обработчик с HTML-формой, кодами ошибок и хранением разобран в главе загрузок.
Производительность: ограничивайте размер до обработки, повторно используйте определитель в цикле, анализируйте файл через file вместо загрузки всего содержимого в дополнительную строку, если строка не нужна дальше. Это снижает лишнюю работу приложения, но не гарантирует фиксированное время/память libmagic для любого формата. Тестируйте свой набор файлов на своей версии.
Упражнение: сервис принимает только text/plain. Есть два собственных документа с разными именами, оба содержат текст. Проверьте содержимое каждого одним объектом и покажите решение без доверия к расширению.
Решение упражнения
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
foreach (['note.txt', 'note.jpg'] as $path) {
$mime = $detector->file($path);
if ($mime === false) { throw new RuntimeException('Cannot detect type'); }
echo $path, ': ', $mime === 'text/plain' ? 'text candidate' : 'reject', "\n";
}
Ожидаемый результат
note.txt: text candidate
note.jpg: text candidate
Оба кандидата содержат текст. Реальная политика сервиса может дополнительно проверять имя/расширение, допустимую кодировку, структуру текста и размер. Fileinfo решает только свою часть.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
finfo_openПодготовить определитель типов с выбранными настройками и базой сигнатур.
finfo_open(int $flags = FILEINFO_NONE, ?string $magic_database = null): finfo|falseПодготовить определитель типов с выбранными настройками и базой сигнатур.
| Часть вызова | Договор |
|---|---|
| flags | Один флаг или комбинация через |. По умолчанию FILEINFO_NONE: текстовое описание; MIME_TYPE удобнее для сравнения типов. Все флаги. |
| magic_database | Путь к собственной базе сигнатур. null/пустая строка означают стандартный выбор: MAGIC environment, если задана, иначе база PHP. Обычно оставляют базу PHP и MAGIC незаданной. Nullable с 8.0.3. |
| Результат | В PHP 8.1+ finfo, при неуспехе false с предупреждениями. До 8.1 функция возвращала ресурс. |
| Срок жизни | Один объект можно использовать для многих файлов. Он освобождается автоматически; finfo_close не нужен в современном коде. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- PHP загрузил базу правил
- MIME_TYPE выбирает формат ответа
- Объект finfo готов к file/buffer
- Следующий файл проверяется тем же объектом
База magic содержит правила узнавания байтов и структуры. Это не файл с разрешениями пользователей. new создаёт объект, скобки передают настройки; ->buffer передаёт сам текст для анализа.
<?php
declare(strict_types=1);
$detector = finfo_open(FILEINFO_MIME_TYPE);
if ($detector === false) { throw new RuntimeException('Не подготовить определитель'); }
$text = "Pickup order 104\n";
echo 'Памятка: ', $text;
echo 'Формат: ', $detector->buffer($text), "\n";
Ожидаемый результат
Памятка: Pickup order 104
Формат: text/plain
Объект хранит базу правил и выбранный формат ответа. finfo_open может вернуть false; new finfo при ошибке конструктора бросает исключение, поэтому сравнение созданного объекта с false не нужно.
<?php
declare(strict_types=1);
$detector = finfo_open(FILEINFO_MIME_TYPE);
if ($detector === false) { throw new RuntimeException('Не подготовить определитель'); }
foreach (['pickup.txt', 'instructions.html'] as $name) {
$type = $detector->file(__DIR__ . '/' . $name);
if ($type === false) { throw new RuntimeException('Не определить тип'); }
echo $name, ': ', $type, "\n";
}
Ожидаемый результат
pickup.txt: text/plain
instructions.html: text/html
Определитель создаётся до цикла и используется повторно. Каждый вызов всё равно анализирует содержимое. Текстовая памятка и HTML-инструкция требуют разных способов показа: HTML нельзя безусловно вставлять как доверенную разметку.
<?php
declare(strict_types=1);
$warned = false;
set_error_handler(static function (int $level) use (&$warned): bool {
if ($level !== E_WARNING) { return false; }
$warned = true;
return true;
});
try { $detector = finfo_open(FILEINFO_MIME_TYPE, __DIR__ . '/missing.magic'); }
finally { restore_error_handler(); }
if ($detector === false) { echo "Проверка документов недоступна: база типов не загружена.\n"; }
if ($warned) { echo "Файловое предупреждение получено; нужна проверка настройки сервера.\n"; }
Ожидаемый результат
Проверка документов недоступна: база типов не загружена.
Файловое предупреждение получено; нужна проверка настройки сервера.
Отсутствует именно настроенная база, а не пользовательский документ. Не подменяйте отказ сервиса ответом «разрешённый формат». Handler показан только для контролируемого опыта и сразу восстановлен.
Сравните: finfo, finfo::file, finfo::buffer, finfo_set_flags, finfo_close. Тип, кодировка и границы определения.
finfo::__constructПодготовить определитель типов с выбранными настройками и базой сигнатур.
public function __construct(int $flags = FILEINFO_NONE, ?string $magic_database = null)Подготовить определитель типов с выбранными настройками и базой сигнатур.
| Часть вызова | Договор |
|---|---|
| flags | Один флаг или комбинация через |. По умолчанию FILEINFO_NONE: текстовое описание; MIME_TYPE удобнее для сравнения типов. Все флаги. |
| magic_database | Путь к собственной базе сигнатур. null/пустая строка означают стандартный выбор: MAGIC environment, если задана, иначе база PHP. Обычно оставляют базу PHP и MAGIC незаданной. Nullable с 8.0.3. |
| Результат | new создаёт finfo; при ошибке загрузки базы конструктор бросает Exception. |
| Срок жизни | Один объект можно использовать для многих файлов. Он освобождается автоматически; finfo_close не нужен в современном коде. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- PHP загрузил базу правил
- MIME_TYPE выбирает формат ответа
- Объект finfo готов к file/buffer
- Следующий файл проверяется тем же объектом
База magic содержит правила узнавания байтов и структуры. Это не файл с разрешениями пользователей. new создаёт объект, скобки передают настройки; ->buffer передаёт сам текст для анализа.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$text = "Pickup order 104\n";
echo 'Памятка: ', $text;
echo 'Формат: ', $detector->buffer($text), "\n";
Ожидаемый результат
Памятка: Pickup order 104
Формат: text/plain
Объект хранит базу правил и выбранный формат ответа. finfo_open может вернуть false; new finfo при ошибке конструктора бросает исключение, поэтому сравнение созданного объекта с false не нужно.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
foreach (['pickup.txt', 'instructions.html'] as $name) {
$type = $detector->file(__DIR__ . '/' . $name);
if ($type === false) { throw new RuntimeException('Не определить тип'); }
echo $name, ': ', $type, "\n";
}
Ожидаемый результат
pickup.txt: text/plain
instructions.html: text/html
Определитель создаётся до цикла и используется повторно. Каждый вызов всё равно анализирует содержимое. Текстовая памятка и HTML-инструкция требуют разных способов показа: HTML нельзя безусловно вставлять как доверенную разметку.
<?php
declare(strict_types=1);
try { new finfo(FILEINFO_MIME_TYPE, 'missing.magic'); }
catch (Exception $error) { echo "Cannot load configured database\n"; }
Ожидаемый результат
Cannot load configured database
Конструктор не возвращает false. Это отказ конфигурации сервиса, а не сообщение посетителю о плохом файле.
Сравните: finfo, finfo::file, finfo::buffer, finfo_set_flags, finfo_close. Тип, кодировка и границы определения.
finfo_fileОпределить тип файла по его содержимому, а не по суффиксу имени.
finfo_file(finfo $finfo, string $filename, int $flags = FILEINFO_NONE, ?resource $context = null): string|falseОпределить тип файла по его содержимому, а не по суффиксу имени.
| Часть вызова | Договор |
|---|---|
| finfo | Настроенный объект finfo. До 8.1 процедурная функция принимала ресурс. |
| filename | Путь к анализируемому файлу. Строка пути не является содержимым. Для загруженного файла берут проверенный $_FILES[…]["tmp_name"], не клиентское name. |
| flags | Необязательный ненулевой набор временно заменяет флаги объекта на один вызов, затем прежние восстанавливаются. FILEINFO_NONE = 0 здесь сохраняет текущие настройки; для постоянного сброса set_flags(FILEINFO_NONE). |
| context | Контекст потока, nullable с 8.0. Может влиять на открытие через поддерживаемую обёртку. Не позволяйте посетителю выбирать произвольный URL для проверки: это создаёт сетевой запрос сервера. |
| Возврат | Строка описания/типа/кодировки по флагам или false при ошибке. Не равняйте неизвестный application/octet-stream ошибке вызова. |
| Ошибки | Недоступный файл — предупреждение и false. Пустой путь — ValueError. Нулевой байт в пути с 8.5 даёт ValueError, раньше TypeError. Это не то же правило, что для нулевого байта в buffer. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- Файл document.jpg содержит Hello world
- libmagic проверяет содержимое по правилам
- MIME_TYPE возвращает text/plain
- Приложение отдельно решает, разрешён ли этот тип
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$type = finfo_file($detector, 'document.jpg');
if ($type === false) { throw new RuntimeException('Cannot detect type'); }
echo $type, "\n";
Ожидаемый результат
text/plain
Файл назван .jpg, но его содержимое — текст. Имя не превратило его в изображение; MIME-тип остаётся эвристическим результатом, не полным разбором формата.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
echo finfo_file($detector, 'document.jpg', FILEINFO_MIME_ENCODING), "\n";
echo finfo_file($detector, 'document.jpg'), "\n";
echo finfo_file($detector, 'document.jpg', FILEINFO_NONE), "\n";
Ожидаемый результат
us-ascii
text/plain
text/plain
Второй и третий результаты показывают, что временный режим не остался у объекта. Переданный 0 не сбрасывает его в описательный режим.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
try { $type = finfo_file($detector, "bad\0path"); }
catch (ValueError $error) { echo "Invalid path\n"; }
Ожидаемый результат
Invalid path
Пример рассчитан на PHP 8.5+. Нулевой байт отвергнут до открытия; раньше этот случай имел TypeError. Не убирайте такой байт молча, превращая исходное имя в другой путь.
У анализа пути тоже есть стоимость чтения и внутренней обработки. Ограничивайте допустимые размеры до тяжёлых операций; не используйте анализ каталогов/устройств как эквивалент приёма обычного файла. Полный путь приёма загрузки.
Сравните: finfo::buffer, finfo_set_flags, mime_content_type. Тип, кодировка и границы определения.
finfo_bufferОпределить тип данных, которые уже находятся в строке PHP.
finfo_buffer(finfo $finfo, string $string, int $flags = FILEINFO_NONE, ?resource $context = null): string|falseОпределить тип данных, которые уже находятся в строке PHP.
| Часть вызова | Договор |
|---|---|
| finfo | Настроенный объект finfo. До 8.1 процедурная функция принимала ресурс. |
| string | Сами бинарные данные в PHP-строке, не путь и не Base64-представление. Строка может содержать нулевые байты. |
| flags | Необязательный ненулевой набор временно заменяет флаги объекта на один вызов, затем прежние восстанавливаются. FILEINFO_NONE = 0 здесь сохраняет текущие настройки; для постоянного сброса set_flags(FILEINFO_NONE). |
| context | Игнорируется; явная передача, включая null, deprecated с 8.5. Nullable с 8.0. В новом коде аргумент опускают. |
| Возврат | Строка описания/типа/кодировки по флагам или false при ошибке. Не равняйте неизвестный application/octet-stream ошибке вызова. |
| Ошибки | Ошибка распознавания может выдать E_WARNING и false. Тип аргумента должен соответствовать сигнатуре. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- $contents содержит Pickup order 104
- buffer анализирует саму строку
- Возвращает text/plain
- Текст пока не преобразован и не проверен по бизнес-схеме
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$contents = "Pickup order 104\n";
$type = finfo_buffer($detector, $contents);
if ($type === false) { throw new RuntimeException('Не определить тип'); }
echo 'Данные: ', $contents;
echo 'Формат: ', $type, "\n";
Ожидаемый результат
Данные: Pickup order 104
Формат: text/plain
buffer анализирует сами байты строки. Передача "pickup.txt" означала бы анализ букв имени, а не открытие файла. Для файла, который ещё лежит на диске, выбирайте file.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
echo finfo_buffer($detector, "Hello world\n", FILEINFO_MIME_ENCODING), "\n";
echo finfo_buffer($detector, "Hello world\n"), "\n";
echo finfo_buffer($detector, "Hello world\n", FILEINFO_NONE), "\n";
Ожидаемый результат
us-ascii
text/plain
text/plain
Второй и третий результаты показывают, что временный режим не остался у объекта. Переданный 0 не сбрасывает его в описательный режим.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$bytes = hex2bin('47494638396101000100800000000000ffffff21f90401000000002c00000000010001000002024401003b');
if ($bytes === false) { throw new RuntimeException('Invalid fixed fixture'); }
echo finfo_buffer($detector, $bytes), "\n";
echo finfo_buffer($detector, base64_encode($bytes)), "\n";
Ожидаемый результат
image/gif
text/plain
GIF — небольшой собственный бинарный fixture. Base64 — уже другой набор текстовых байтов. Декодирование внешнего Base64 выполняют строго и с ограничением размера; результат MIME не заменяет полноценное декодирование изображения.
Если файл уже лежит на диске, file обычно позволяет не загружать весь документ в отдельную PHP-строку. buffer полезен для небольших уже полученных данных; не используйте file_get_contents большого файла только ради MIME-проверки. Полный путь приёма загрузки.
Сравните: finfo::file, finfo_set_flags, mime_content_type. Тип, кодировка и границы определения.
finfo::bufferОпределить тип данных, которые уже находятся в строке PHP.
public function buffer(string $string, int $flags = FILEINFO_NONE, ?resource $context = null): string|falseОпределить тип данных, которые уже находятся в строке PHP.
| Часть вызова | Договор |
|---|---|
| string | Сами бинарные данные в PHP-строке, не путь и не Base64-представление. Строка может содержать нулевые байты. |
| flags | Необязательный ненулевой набор временно заменяет флаги объекта на один вызов, затем прежние восстанавливаются. FILEINFO_NONE = 0 здесь сохраняет текущие настройки; для постоянного сброса set_flags(FILEINFO_NONE). |
| context | Игнорируется; явная передача, включая null, deprecated с 8.5. Nullable с 8.0. В новом коде аргумент опускают. |
| Возврат | Строка описания/типа/кодировки по флагам или false при ошибке. Не равняйте неизвестный application/octet-stream ошибке вызова. |
| Ошибки | Ошибка распознавания может выдать E_WARNING и false. Тип аргумента должен соответствовать сигнатуре. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- $contents содержит Pickup order 104
- buffer анализирует саму строку
- Возвращает text/plain
- Текст пока не преобразован и не проверен по бизнес-схеме
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$contents = "Pickup order 104\n";
$type = $detector->buffer($contents);
if ($type === false) { throw new RuntimeException('Не определить тип'); }
echo 'Данные: ', $contents;
echo 'Формат: ', $type, "\n";
Ожидаемый результат
Данные: Pickup order 104
Формат: text/plain
buffer анализирует сами байты строки. Передача "pickup.txt" означала бы анализ букв имени, а не открытие файла. Для файла, который ещё лежит на диске, выбирайте file.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
echo $detector->buffer("Hello world\n", FILEINFO_MIME_ENCODING), "\n";
echo $detector->buffer("Hello world\n"), "\n";
echo $detector->buffer("Hello world\n", FILEINFO_NONE), "\n";
Ожидаемый результат
us-ascii
text/plain
text/plain
Второй и третий результаты показывают, что временный режим не остался у объекта. Переданный 0 не сбрасывает его в описательный режим.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$bytes = hex2bin('47494638396101000100800000000000ffffff21f90401000000002c00000000010001000002024401003b');
if ($bytes === false) { throw new RuntimeException('Invalid fixed fixture'); }
echo $detector->buffer($bytes), "\n";
echo $detector->buffer(base64_encode($bytes)), "\n";
Ожидаемый результат
image/gif
text/plain
GIF — небольшой собственный бинарный fixture. Base64 — уже другой набор текстовых байтов. Декодирование внешнего Base64 выполняют строго и с ограничением размера; результат MIME не заменяет полноценное декодирование изображения.
Если файл уже лежит на диске, file обычно позволяет не загружать весь документ в отдельную PHP-строку. buffer полезен для небольших уже полученных данных; не используйте file_get_contents большого файла только ради MIME-проверки. Полный путь приёма загрузки.
Сравните: finfo::file, finfo_set_flags, mime_content_type. Тип, кодировка и границы определения.
finfo_set_flagsПостоянно изменить формат определения для следующих вызовов этого объекта.
finfo_set_flags(finfo $finfo, int $flags): trueПостоянно изменить формат определения для следующих вызовов этого объекта.
| Часть вызова | Договор |
|---|---|
| finfo | Настроенный объект finfo; до 8.1 процедурный вызов принимал ресурс. |
| flags | Один флаг или комбинация через |. Полностью заменяет предыдущие настройки, а не добавляет их автоматически. |
| Возврат | Всегда true при штатном вызове; это подтверждает применение настройки, не успешную классификацию будущего файла. |
| Общая ссылка | Две переменные с одним объектом видят одну настройку. Для двух независимых политик создайте два finfo. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- Было FILEINFO_MIME_TYPE
- set_flags(FILEINFO_MIME_ENCODING)
- Следующий buffer возвращает us-ascii
- Настройка сохраняется до следующей смены
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$text = "Pickup order 104\n";
echo 'Тип: ', $detector->buffer($text), "\n";
finfo_set_flags($detector, FILEINFO_MIME_ENCODING);
echo 'Кодировка: ', $detector->buffer($text), "\n";
Ожидаемый результат
Тип: text/plain
Кодировка: us-ascii
set_flags заменяет постоянный режим объекта. Данные $text не перекодируются: изменился вопрос, на который отвечает определитель.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
finfo_set_flags($detector, FILEINFO_MIME_TYPE | FILEINFO_MIME_ENCODING);
echo $detector->buffer("Привет\n"), "\n";
Ожидаемый результат
text/plain; charset=utf-8
Оператор | объединяет битовые флаги. FILEINFO_MIME — готовая константа той же комбинации. Для точного списка допустимых MIME удобнее MIME_TYPE, иначе charset станет частью сравниваемой строки.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$text = "Pickup order 104\n";
finfo_set_flags($detector, FILEINFO_NONE);
echo 'Описание: ', $detector->buffer($text), "\n";
finfo_set_flags($detector, FILEINFO_MIME_TYPE);
echo 'Для сравнения форматов: ', $detector->buffer($text), "\n";
Ожидаемый результат
Описание: ASCII text
Для сравнения форматов: text/plain
Точная свободная формулировка описания зависит от libmagic; здесь показан фактический результат учебного runtime. Для списка допустимых форматов используют стабильнее выраженный MIME_TYPE, а не сравнивают полное описание.
Сравните: finfo_open, finfo::buffer, finfo::file. Тип, кодировка и границы определения.
finfo::set_flagsПостоянно изменить формат определения для следующих вызовов этого объекта.
public function set_flags(int $flags): trueПостоянно изменить формат определения для следующих вызовов этого объекта.
| Часть вызова | Договор |
|---|---|
| flags | Один флаг или комбинация через |. Полностью заменяет предыдущие настройки, а не добавляет их автоматически. |
| Возврат | Всегда true при штатном вызове; это подтверждает применение настройки, не успешную классификацию будущего файла. |
| Общая ссылка | Две переменные с одним объектом видят одну настройку. Для двух независимых политик создайте два finfo. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- Было FILEINFO_MIME_TYPE
- set_flags(FILEINFO_MIME_ENCODING)
- Следующий buffer возвращает us-ascii
- Настройка сохраняется до следующей смены
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$text = "Pickup order 104\n";
echo 'Тип: ', $detector->buffer($text), "\n";
$detector->set_flags(FILEINFO_MIME_ENCODING);
echo 'Кодировка: ', $detector->buffer($text), "\n";
Ожидаемый результат
Тип: text/plain
Кодировка: us-ascii
set_flags заменяет постоянный режим объекта. Данные $text не перекодируются: изменился вопрос, на который отвечает определитель.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$detector->set_flags(FILEINFO_MIME_TYPE | FILEINFO_MIME_ENCODING);
echo $detector->buffer("Привет\n"), "\n";
Ожидаемый результат
text/plain; charset=utf-8
Оператор | объединяет битовые флаги. FILEINFO_MIME — готовая константа той же комбинации. Для точного списка допустимых MIME удобнее MIME_TYPE, иначе charset станет частью сравниваемой строки.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$text = "Pickup order 104\n";
$detector->set_flags(FILEINFO_NONE);
echo 'Описание: ', $detector->buffer($text), "\n";
$detector->set_flags(FILEINFO_MIME_TYPE);
echo 'Для сравнения форматов: ', $detector->buffer($text), "\n";
Ожидаемый результат
Описание: ASCII text
Для сравнения форматов: text/plain
Точная свободная формулировка описания зависит от libmagic; здесь показан фактический результат учебного runtime. Для списка допустимых форматов используют стабильнее выраженный MIME_TYPE, а не сравнивают полное описание.
Сравните: finfo_open, finfo::buffer, finfo::file. Тип, кодировка и границы определения.
finfo_closeРаспознать устаревшее закрытие ресурса в старом проекте и убрать ненужный вызов.
#[Deprecated(since: "8.5")] finfo_close(finfo $finfo): trueРаспознать устаревшее закрытие ресурса в старом проекте и убрать ненужный вызов.
| Часть вызова | Договор |
|---|---|
| finfo | В современном PHP объект finfo, до 8.1 был ресурс. |
| Возврат | Всегда true; в PHP 8.1+ вызов не выполняет закрытие. Тип возврата true явно указан с 8.5, ранее bool. |
| Статус | Deprecated с PHP 8.5: объекты освобождаются автоматически. Удалите вызов в новом коде; unset убирает одну ссылку, другие могут удерживать объект. |
| История | Таблица изменений относит ресурс→объект и no-op к 8.1. Вводный абзац текущей страницы упоминает 8.0; проверка официальных исходников PHP 8.0.30 (RETURN_RES) и 8.1.0 (RETURN_OBJ) подтверждает границу 8.1. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- Раньше finfo_open возвращал ресурс
- С PHP 8.1 возвращается finfo
- Срок жизни управляется ссылками на объект
- finfo_close устарел в 8.5 и не нужен
<?php
declare(strict_types=1);
$reflection = new ReflectionFunction('finfo_close');
$attributes = $reflection->getAttributes(Deprecated::class);
echo $attributes[0]->newInstance()->since, "\n";
Ожидаемый результат
8.5
Это пример PHP 8.5 с метаданными. Он не вызывает устаревшую функцию и не подавляет предупреждение; на старом PHP атрибута может не быть.
<?php
declare(strict_types=1);
function detectDocumentType(string $text): string
{
$detector = new finfo(FILEINFO_MIME_TYPE);
$type = $detector->buffer($text);
if ($type === false) { throw new RuntimeException('Не определить тип'); }
return $type;
}
echo 'Памятка заказа 104: ', detectDocumentType("Pickup order 104\n"), "\n";
Ожидаемый результат
Памятка заказа 104: text/plain
После возврата локальная ссылка $detector исчезает, объект освобождается, если его больше никто не удерживает. finfo_close не нужен в PHP8.1+ и deprecated с8.5. Явный unset после каждого файла тоже не обязателен.
Сравните: finfo_open, finfo, unset. Тип, кодировка и границы определения.
mime_content_typeУзнать MIME-тип локального файла или доступного читаемого потока одним вызовом.
mime_content_type(resource|string $filename): string|falseУзнать MIME-тип локального файла или доступного читаемого потока одним вызовом.
| Часть вызова | Договор |
|---|---|
| filename | Путь к файлу либо ресурс потока. Строка — путь, не содержимое. |
| Возврат | MIME-тип, например text/plain/application/octet-stream; false при неуспехе и E_WARNING. |
| Ошибки аргумента | В проверенном PHP 8.5.11 пустой путь даёт ValueError, путь с NUL — TypeError. Не переносите правило finfo_file автоматически: там с 8.5 NUL даёт ValueError. |
| Поток | Реализация пытается перейти к началу и восстановить позицию. Для перематываемого собственного потока это проверено; для сетевого/неперематываемого потока такую гарантию давать нельзя. |
| Альтернатива | Для серии файлов finfo позволяет один раз создать объект и выбрать режим. MIME сам по себе не проверяет безопасность содержимого. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- report.txt — путь к данным
- Функция открывает и анализирует содержимое
- Возвращается строка text/plain
- Решение о допустимости принимает приложение
<?php
declare(strict_types=1);
$mime = mime_content_type('report.txt');
if ($mime === false) { throw new RuntimeException('Cannot detect type'); }
echo $mime, "\n";
Ожидаемый результат
text/plain
Здесь нет загрузки от посетителя: report.txt — собственный учебный файл. Для формы нужен tmp_name после проверки структуры $_FILES и кода загрузки.
<?php
declare(strict_types=1);
$stream = fopen('php://temp', 'w+b');
if ($stream === false) { throw new RuntimeException('Cannot open temporary stream'); }
try {
fwrite($stream, "Hello world\n");
fseek($stream, 3);
echo mime_content_type($stream), "\n";
echo ftell($stream), "\n";
} finally { fclose($stream); }
Ожидаемый результат
text/plain
3
После распознавания собственный поток остался на позиции 3. Это проверка конкретного перематываемого потока; она не означает поддержку такой семантики у любого ресурса/URL.
Сравните: finfo::file, finfo::buffer, fopen. Тип, кодировка и границы определения.
finfoОбъединить базу правил и настройки определения типа в многократно используемом объекте.
class finfo { __construct(int $flags = FILEINFO_NONE, ?string $magic_database = null); buffer(string $string, int $flags = FILEINFO_NONE, ?resource $context = null): string|false; file(string $filename, int $flags = FILEINFO_NONE, ?resource $context = null): string|false; set_flags(int $flags): true; }Объединить базу правил и настройки определения типа в многократно используемом объекте.
| Часть вызова | Договор |
|---|---|
| Создание | new finfo(...), либо finfo_open(...) с проверкой false. |
| Методы | buffer — готовые байты, file — путь, set_flags — постоянная смена режима. Полные контракты каждого доступны ниже по ссылкам. |
| Состояние | Настройка принадлежит объекту. Отдельные объекты могут иметь разные режимы; обычное присваивание переменной не копирует объект. |
| Граница | Эвристический определитель формата, не конвертер, антивирус, декодер изображения или проверка доступа. |
В коде $ начинает имя переменной, = сохраняет возвращённое значение, скобки передают аргументы вызова. new finfo(...) создаёт настроенный объект; ->file(...) или ->buffer(...) вызывает его метод. === false проверяет именно неуспех, не любую пустую строку. throw new RuntimeException(...) останавливает обычный путь выполнения с объектом ошибки; catch перехватывает указанный тип, а finally завершает обязательную очистку даже при ошибке. Разбор try, catch и finally.
- $types настроен на MIME_TYPE
- $encoding настроен на MIME_ENCODING
- Одинаковые байты передаются двум объектам
- Результаты text/plain и us-ascii отвечают на разные вопросы
<?php
declare(strict_types=1);
$types = new finfo(FILEINFO_MIME_TYPE);
$encoding = new finfo(FILEINFO_MIME_ENCODING);
$contents = "Hello world\n";
echo $types->buffer($contents), "\n", $encoding->buffer($contents), "\n";
Ожидаемый результат
text/plain
us-ascii
Первый результат отвечает «какой формат», второй — «какая предполагается кодировка». Ни одна операция не перекодировала contents.
<?php
declare(strict_types=1);
$detector = new finfo(FILEINFO_MIME_TYPE);
$same = $detector;
$same->set_flags(FILEINFO_MIME_ENCODING);
echo $detector->buffer("Hello world\n"), "\n";
var_dump($same === $detector);
Ожидаемый результат
us-ascii
bool(true)
Изменение видно через обе переменные, потому что объект один. Чтобы соседние операции не меняли друг другу политику, передавайте временный флаг на вызов или создайте отдельные объекты.
Сравните: finfo::__construct, finfo::buffer, finfo::file, finfo::set_flags. Тип, кодировка и границы определения.