В Laravel довольно удобно сделана валидация данных, переданных в запросе (например, от формы). Достаточно написать в контроллере
$data = $this->validate($request,[
'myvalue' => 'required|integer',
'myfile' => 'file',
// ...
]);
и в $data
попадет отвалидированный массив данных, если все условия соблюдены. А если нет — будет возвращен код ошибки 422 с соответствующими сообщениями.
Перечень доступных из коробки правил можно найти в документации. Иногда их оказывается недостаточно. У меня вот, например, возникла нужда отвалидировать, что пользователь загрузил файл docx. Стандартное правило должно по идее выглядеть вот так:
'myfile' => 'file|mimes:docx',
но на деле оказывается, что оно не работает. Во всяком случае у меня. На каждый нормальный, сделанный опен-офисом файл Ларавел ругается и говорит, что это не docx. Выяснилось, что методы, используемые для определения формата файла, возвращают application/octet-stream
, то есть считают мой документ мутным непонятным бинарником. Как заставить систему определять файл правильно — я пока не понял. Если вы знаете, как, напишите пожалуйста в комментах или в stackoverflow.
А пока ответ не найден, я решил просто написать кастомное правило, валидирующее docx-файл с помощью соответствующей профильной библиотеки PHPWord, которая всё равно в моем проекте уже используется. Сделать это в Ларавеле довольно нетрудно.
Сначала создаем файл для правила:
php artisan make:rule ValidDocx
Затем редактируем код класса с правилом. Реализовать нужно всего два метода: passes()
, который определяет, прошло значение валидацию, или нет. И message()
, который возвращает сообщение, показываемое пользователю в случае ошибки.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use PhpOffice\PhpWord\Reader\Word2007;
class ValidDocx implements Rule
{
public function passes($attribute, $value) {
// сначала попробуем определить тип стандартным способом
// optional() нужен на случай если в $value передан вообще не файл, а, например, строка
$mimeType = optional($value)->getMimeType();
if (!$mimeType) {
// если нет никакого типа, то это не файл
return false;
}
if ($mimeType == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
// если тип уже определился как docx, нет нужды применять тяжелую проверку через PHPWord
return true;
}
if ($mimeType != 'application/octet-stream') {
// Если не octet-stream, то это файл какого-то другого типа
// например, картинка. Нет нужны проверять через PHPWord.
return false;
}
// проверяем файл через PHPWord
$doc = new Word2007();
try {
$doc->load($value->getRealPath());
} catch (\Exception $e) {
return false;
}
if ($doc) {
return true;
}
return false;
}
public function message() {
return 'The :attribute value must be a valid .docx file.';
}
}
Теперь правило для проверки загруженного docx-файла будет выглядеть вот так:
'myfile' => ['file', new ValidDocx],