Хочу поделится небольшим решением проблемы, которая возникла у меня при использовании laravel 5, в частности, при загрузке файла он не всегда приходит валидацию по правилу mimes, несмотря на правильное расширение и совершенную валидность. Так же в конце статьи мы напишем свой собственный православный валидатор под 5-ю версию.
После вдумчивого гугления проблемы и просмотра сырков (добрался до Symfony библиотек), выяснился следующий момент:
Если доступна php-функция passthru (проверка что надо, все очевидно с первого раза же), то в класс MimeTypeGuesser, который используется в Symfony\Component\HttpFoundation\File, подмешается, можно сказать, «дополнительный валидатор» FileBinaryMimeTypeGuesser, который попытается для вашего загруженного файла выполнить:
Бинго! Данная утилита очень зависима от системных таблиц mime типов, в которых может не оказаться такой экзотики, как docx, сохраненный из openoffice, txt файл (да-да!). В таком случае в результате после всех абстракций все преобразуется к расширению файла: bin
А вы добавили, это, можно сказать, «расширение» в таблицу разрешенных типов валидатора?
Два варианта:
Если с первым вариантом, думаю, все думаю понятно, фактически образуется дыра, где любые бинарные файлы с неопределенным mime залетают за валидатор, то мы попробуем это решить хоть как-то (у меня еще есть более глубокое решение на уровне SH скриптов, но мы не будем углублять статью). Заодно покажу, как создать свой валидатор.
Поехали:
Как известно, мы можем создавать любые файлы в пределах namespace \App. Например, создаем файл — app/Classes/CustomValidator.php:
Подключаем в любом провайдере, для примера взял — app\Providers\AppServiceProvider.php. Заменяем/дополняем метод boot:
Последним шагом дополняем ваш файл языка — app/resources/lang/en/validation.php.
Хотелось бы пояснить, что тут за магия. Оказывается, Laravel при валидации ищет метод validate{Имя правила} в своем же классе валидации и выполняет его. Если было возвращено логическое FALSE, то он из стандартного файла языка вернет текст ошибки, предварительно скормив его в магический метод replace{Имя правила} для пост обработки.
Edjoy!
Введение
После вдумчивого гугления проблемы и просмотра сырков (добрался до Symfony библиотек), выяснился следующий момент:
Если доступна php-функция passthru (проверка что надо, все очевидно с первого раза же), то в класс MimeTypeGuesser, который используется в Symfony\Component\HttpFoundation\File, подмешается, можно сказать, «дополнительный валидатор» FileBinaryMimeTypeGuesser, который попытается для вашего загруженного файла выполнить:
file -b --mime {путь к файлу} 2>/dev/null
Бинго! Данная утилита очень зависима от системных таблиц mime типов, в которых может не оказаться такой экзотики, как docx, сохраненный из openoffice, txt файл (да-да!). В таком случае в результате после всех абстракций все преобразуется к расширению файла: bin
А вы добавили, это, можно сказать, «расширение» в таблицу разрешенных типов валидатора?
Решение проблемы
Два варианта:
- Добавить расширение bin в список разрешенных типов (а что выдает txt? Домашнее задание!)
- Написать свой валидатор
Если с первым вариантом, думаю, все думаю понятно, фактически образуется дыра, где любые бинарные файлы с неопределенным mime залетают за валидатор, то мы попробуем это решить хоть как-то (у меня еще есть более глубокое решение на уровне SH скриптов, но мы не будем углублять статью). Заодно покажу, как создать свой валидатор.
Поехали:
Как известно, мы можем создавать любые файлы в пределах namespace \App. Например, создаем файл — app/Classes/CustomValidator.php:
<?php namespace App\Classes;
class CustomValidator extends \Illuminate\Validation\Validator {
protected function validateExt($attribute, $file, $allowExtension)
{
return in_array($file->getClientOriginalExtension(), $allowExtension);
}
protected function replaceExt($message, $attribute, $rule, $parameters)
{
return str_replace(':values', implode(', ', $parameters), $message);
}
}
Подключаем в любом провайдере, для примера взял — app\Providers\AppServiceProvider.php. Заменяем/дополняем метод boot:
public function boot()
{
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new \App\Classes\CustomValidator($translator, $data, $rules, $messages);
});
}
Последним шагом дополняем ваш файл языка — app/resources/lang/en/validation.php.
"ext" => "The :attribute must be a file of type: :values.",
Хотелось бы пояснить, что тут за магия. Оказывается, Laravel при валидации ищет метод validate{Имя правила} в своем же классе валидации и выполняет его. Если было возвращено логическое FALSE, то он из стандартного файла языка вернет текст ошибки, предварительно скормив его в магический метод replace{Имя правила} для пост обработки.
Edjoy!