Версия фреймворка:
5.4 4.2
Прогресс перевода
Перевод полностью актуален оригиналу.

Валидация

Введение

Laravel предоставляет несколько способов для валидации входящих данных. По умолчанию базовый контроллер использует трейт ValidatesRequests, который обеспечивает удобный способ валидации HTTP запросов c большим количеством правил валидации.

Быстрый старт

Перед тем как узнать обо всех функциях, давайте рассмотрим полный пример валидации формы и вывод сообщений об ошибках для пользователя.

Определение роутов

Во первых, представим что мы имеем следующие роуты в файле routes/web.php:

Route::get('post/create', 'PostController@create');

Route::post('post', 'PostController@store');

Конечно, роут GET отображает форму для создания нового поста в блоге, в то время как POST будет сохранять новую запись в базе данных.

Создание контроллера

Посмотрим на простой контроллер, который обрабатывает эти роуты. Метод store пока оставим пустым:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * Показать форму для создания новой записи в блоге.
     *
     * @return Response
     */
    public function create()
    {
        return view('post.create');
    }

    /**
     * Хранить новую запись в блоге.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Validate and store the blog post...
    }
}

Написание логики валидации

Теперь мы готовы заполнить метод store валидацией при создания нового поста. Если проанализировать базовый контроллер (App\Http\Controllers\Controller), вы заметите, что он включает в себя трейт ValidatesRequests, который обеспечивает все контроллеры удобным методом validate.

Метод validate принимает два параметра экземпляр HTTP запроса и правила валидации. Если все правила не нарушены, код будет выполняться далее. Однако, если проверка не пройдена, будет выброшено исключение и сообщение об ошибке автоматически отправится обратно пользователю. По традициям HTTP запроса, ответ будет перенаправлен обратно с заполненными flash-переменными, в то время как на AJAX запрос отправится JSON.

Для лучшего понимания метода validate, вернемся обратно к store:

/**
 * Store a new blog post.
 *
 * @param  Request  $request
 * @return Response
 */
public function store(Request $request)
{
    $this->validate($request, [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // The blog post is valid, store in database...
}

Как видно, мы передаем экземпляр с данными HTTP запроса и правила валидации в метод validate. Помните, что если проверка завершится неудачей, будет автоматически сгенерирован ответ с сообщением об ошибках, иначе ваш контроллер продолжит работать.

Остановка после первой неудачной проверки

Иногда нужно остановить выполнение остальных правил после первой неудачной проверки. Для этого используется атрибут bail:

$this->validate($request, [
    'title' => 'bail|unique:posts|max:255',
    'body' => 'required',
]);

В этом примере, если для атрибута title не выполняется правило required, следующие правило unique проверяться не будет. Правила выполняются именно в той последовательности, в какой они назначаются.

Заметка о вложенных атрибутах

Если данные HTTP запроса содержат "вложенные" параметры, можно указать их, используя синтаксис с точкой:

$this->validate($request, [
    'title' => 'required|unique:posts|max:255',
    'author.name' => 'required',
    'author.description' => 'required',
]);

Отображение ошибок валидации

Что, если входящие данные не проходят проверку с учетом правил? Как упоминалось ранее, Laravel автоматически перенаправляет пользователя на предыдущую страницу. Кроме того, все ошибки валидации будут автоматически записаны во flash-переменные.

Опять же, обратите внимание, что мы не должны явно передавать сообщения об ошибках в шаблоне роута GET. Это потому, что Laravel будет проверять наличие ошибок в текущем сеансе и автоматически привязывать их к шаблону, если они доступны. Переменная $errors является экземпляром Illuminate\Support\MessageBag. Для получения дополнительных сведений о работе с этим объектом, смотрите в документации.

Переменная $errorsпривязана к посреднику Illuminate\View\Middleware\ShareErrorsFromSession, который входит в группу посредников web . При использовании этого посредника, $errors всегда будет доступна в ваших шаблонах, что позволяет удобно и безопасно ее использовать.

В нашем примере пользователь будет перенаправлен в метод create вашего контроллера и можно отобразить сообщения об ошибках в шаблоне:

<!-- /resources/views/post/create.blade.php -->

<h1>Create Post</h1>

@if ($errors->any())
    

Accepted Active URL After (Date) After Or Equal (Date) Alpha Alpha Dash Alpha Numeric Array Before (Date) Before Or Equal (Date) Between Boolean Confirmed Date Date Format Different Digits Digits Between Dimensions (Image Files) Distinct E-Mail Exists (Database) File Filled Image (File) In In Array Integer IP Address JSON Max MIME Types MIME Type By File Extension Min Nullable Not In Numeric Present Regular Expression Required Required If Required Unless Required With Required With All Required Without Required Without All Same Size String Timezone Unique (Database) URL

accepted

Поле должно быть в значении yes, on или 1. Это полезно для проверки принятия правил и лицензий.

active_url

Поле должно иметь действительную A или AAAA DNS-запись согласно функции PHP dns_get_record.

after:date

Поле проверки должно быть после date. Строки приводятся к датам функцией strtotime:

'start_date' => 'required|date|after:tomorrow'

Вместо того чтобы приводить строки к датам, вы можете указать другое поле для сравнения даты:

'finish_date' => 'required|date|after:start_date'

after_or_equal:date

Поле проверки должно быть после или равно date. Для получения дополнительной информации смотрите правило after

alpha

Поле должно содержать только алфавитные символы.

alpha_dash

Поле можно содержать только алфавитные символы, цифры, знаки подчёркивания _ и дефисы -.

alpha_num

Поле можно содержать только алфавитные символы и цифры.

array

Поле должно быть PHP-массивом.

before:date

Поле должно быть датой более ранней, чем заданная дата. Строки приводятся к датам функцией strtotime.

before_or_equal:date

Поле должно быть более ранней или равной заданной дате. Строки приводятся к датам функцией strtotime.

between:min,max

Поле должно быть числом в диапазоне от min до max. Размеры строк, чисел и файлов трактуются аналогично правилу size.

boolean

Поле должно быть логическим (булевым). Разрешенные значения: true, false, 1, 0, "1", и "0".

confirmed

Значение поля должно соответствовать значению поля с этим именем, плюс foo_confirmation. Например, если проверяется поле password, то на вход должно быть передано совпадающее по значению поле password_confirmation.

date

Поле должно быть правильной датой в соответствии с PHP функцией strtotime.

date_format:format

Поле должно соответствовать заданному формату. Необходимо использовать функцию date или date_format при проверке поля, но не обе.

different:field

Значение проверяемого поля должно отличаться от значения поля field.

digits:value

Поле должно быть числовым и иметь точную длину значения.

digits_between:min,max

Длина значения поля проверки должна быть между min и max.

dimensions

Файл изображения должен иметь ограничения согласно параметрам:

'avatar' => 'dimensions:min_width=100,min_height=200'

Доступные ограничения: min_width, max_width, min_height, max_height, width, height, ratio.

Ограничение ratio должно быть представлено как ширина к высоте. Это может быть обыкновенная (3/2) или десятичная (1.5) дробь:

'avatar' => 'dimensions:ratio=3/2'

Поскольку это правило требует несколько аргументов, вы можете использовать метод Rule::dimensions:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'avatar' => [
        'required',
        Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
    ],
]);

distinct

При работе с массивами, поле не должно иметь повторяющихся значений.

'foo.*.id' => 'distinct'

email

Поле должно быть корректным адресом e-mail.

exists:table,column

Поле должно существовать в указанной таблице базы данных.

Базовое использование правила Exists

'state' => 'exists:states'

Указание пользовательского названия столбца

'state' => 'exists:states,abbreviation'

Иногда может потребоваться подключение к базе данных и использование в запросе exists, этого можно добиться путем добавления к соединению название таблицы, используя синтаксис с точкой:

'email' => 'exists:connection.staff,email'

Если бы вы хотите модифицировать запрос, можно использовать класс Rule, в данном примере мы будем использовать массив вместо знака |:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::exists('staff')->where(function ($query) {
            $query->where('account_id', 1);
        }),
    ],
]);

file

Поле должно быть успешно загруженным файлом.

filled

Поле не должно быть пустым.

image

Загруженный файл должен быть в формате jpeg, png, bmp, gif или svg.

in:foo,bar,...

Значение поля должно быть одним из перечисленных. Поскольку это правило иногда вынуждает вас использовать функцию implode, для этого случая есть метод Rule::in:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'zones' => [
        'required',
        Rule::in(['first-zone', 'second-zone']),
    ],
]);

in_array:anotherfield

В массиве должны существовать значения anotherfield.

integer

Поле должно иметь корректное целочисленное значение.

ip

Поле должно быть корректным IP-адресом.

ipv4

Поле должно быть IPv4-адресом.

ipv6

Поле должно быть IPv6-адресом.

json

Поле должно быть валидной строкой JSON.

max:value

Значение поля должно быть меньше или равно value. Размеры строк, чисел и файлов трактуются аналогично правилу size.

mimetypes:text/plain,...

MIME-тип загруженного файла должен быть одним из перечисленных:

'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'

Чтобы определить MIME-тип загруженного файла, фреймворк будет читать содержимое и пытаться угадать MIME-тип, который может отличаться от того, что указал пользователь.

mimes:foo,bar,...

MIME-тип загруженного файла должен быть одним из перечисленных.

Основное использование MIME-правила

'photo' => 'mimes:jpeg,bmp,png'

Даже если необходимо только указать расширение, это правило проверяет MIME-тип файла, читая содержимое файла и пытаясь угадать его.

Полный список MIME-типов и соответствующие им расширения можно найти в: https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

min:value

Значение поля должно быть больше value. Размеры строк, чисел и файлов трактуются аналогично правилу size.

nullable

Поле может быть равно null. Это особенно полезно при проверке примитивов, такие как строки и целые числа, которые могут содержать null значения.

not_in:foo,bar,...

Поле не должно быть включено в заданный список значений. Метод Rule::notIn можно использовать для конструирования этого правила:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'toppings' => [
        'required',
        Rule::notIn(['sprinkles', 'cherries']),
    ],
]);

numeric

Поле должно иметь корректное числовое или дробное значение.

present

Поле для проверки должно присутствовать во входных данных, но может быть пустым.

regex:pattern

Поле должно соответствовать заданному регулярному выражению.

Примечание: Для использования regex может быть необходимо определить правила в виде массива вместо использования разделителя, особенно если регулярное выражение содержит символ разделителя.

required

Проверяемое поле должно иметь непустое значение. Поле считается пустым, если одно из следующих значений верно:

  • Если значение равно null.
  • Если значение — пустая строка.
  • Если значение является пустым массивом или пустым объектом Countable.
  • Если значение это загруженный файл без пути.

required_if:anotherfield,value,...

Поле должно присутствовать и не быть пустым, если anotherfield равно любому value.

required_unless:anotherfield,value,...

Поле должно присутствовать и не быть пустым, за исключением случая, когда anotherfield равно любому value.

required_with:foo,bar,...

Проверяемое поле должно иметь непустое значение, но только если присутствует хотя бы одно из перечисленных полей (foo, bar и т.д.).

required_with_all:foo,bar,...

Проверяемое поле должно иметь непустое значение, но только если присутствуют все перечисленные поля (foo, bar и т.д.).

required_without:foo,bar,...

Проверяемое поле должно иметь непустое значение, но только если не присутствует хотя бы одно из перечисленных полей (foo, bar и т.д.).

required_without_all:foo,bar,...

Проверяемое поле должно иметь непустое значение, но только если не присутствуют все перечисленные поля (foo, bar и т.д.).

same:field

Поле должно иметь то же значение, что и поле field.

size:value

Поле должно иметь совпадающий с value размер. Для строковых данных value соответствует количество символов, для массива size соответствует количеству элементов массива, для чисел — число, для файлов — размер в килобайтах.

string

Поле должно быть строкой. Если вы хотите, чтобы поле было null, следует доолнитель указать это полю правило nullable.

timezone

Поле должно содержать идентификатор часового пояса (таймзоны), один из перечисленных в php-функции timezone_identifiers_list.

unique:table,column,except,idColumn

Значение поля должно быть уникальным в заданной таблице базы данных. Если column не указано, то будет использовано имя поля.

Указание пользовательского названия столбца:

'email' => 'unique:users,email_address'

Пользовательское подключение к БД

Иногда вам может понадобиться установить собственное соединение с базой данных, как замечено выше, параметр unique:users, будет использовать соединение по умолчанию. Чтобы переопределить это, укажите подключение и имя таблицы через синтаксис с точкой:

'email' => 'unique:connection.users,email_address'

Игнорирование ID при проверке на уникальность:

Иногда потребуется игнорировать ID при проверке на уникальность. Например, рассмотрим обновление профиля пользователя, который включает в себя имя пользователя, адрес электронной почты и местоположение. Конечно, вы хотите убедиться, что адрес электронной почты является уникальным. Однако, если пользователь изменяет только имя и не изменяет электронную почту, нам не требуется вывод ошибки, но тем не менее возникнет исключение, поскольку пользователь уже является владельцем адреса электронной почты.

Для того, чтобы игнорировать ID пользователя, мы будем использовать класс Rule который позволяет гибко строить наши правила в таком случае. В примере, мы укажем правила в качестве массива вместо | символа-разделителя:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::unique('users')->ignore($user->id),
    ],
]);

Если таблица использует имя столбца первичного ключа помимо id, можно указать имя столбца при вызове метода ignore:

'email' => Rule::unique('users')->ignore($user->id, 'user_id')

Добавление дополнительных условий Where:

Вы также можете указать дополнительные условия, используя метод where. Например, давайте добавим ограничение, которое проверяет, что account_id равно 1:

'email' => Rule::unique('users')->where(function ($query) {
    $query->where('account_id', 1);
})

url

Поле должно быть корректным URL.

Добавление правил с условиями

Валидация при наличии поля

Иногда вам нужно проверить некое поле только тогда, когда оно присутствует во входных данных. Для этого добавьте правило sometimes:

$v = Validator::make($data, [
    'email' => 'sometimes|required|email',
]);

В примере выше для поля email будет запущена валидация только, когда оно присутствует в массиве $data.

Если вы пытаетесь валидировать поле, которое всегда должно быть в наличии, но может быть пустым, смотрите эту заметку о необязательных полях

Сложная составная проверка

Иногда возникает необходимость добавить правила с более сложной логикой проверки. Например, потребовать поле, только если другое поле имеет значение большее, чем 100. Или понадобится два поля, когда другое поле присутствует. Добавление этих правил не должно вызывать затруднения. Во-первых, создайте экземпляр Validator с вашими постоянными правилами, которые никогда не изменятся:

$v = Validator::make($data, [
    'email' => 'required|email',
    'games' => 'required|numeric',
]);

Давайте предположим, что наше веб-приложение для коллекционеров игр. Если коллекционер регистрирует в нашем приложении игру и он владеет больше чем 100 играми в данный момент, мы хотим, чтобы он объяснил, почему он владеет таким количеством игр. Возможно, он управляет магазином игр, или возможно, он просто любит их собирать. Чтобы добавить это требование, мы можем использовать метод sometimes в экземпляре валидатора:

$v->sometimes('reason', 'required|max:500', function ($input) {
    return $input->games >= 100;
});

Первый аргумент, переданный в метод sometimes это имя поля, которое мы условно проверяем. Второй аргумент — правила, которые мы хотим добавить. Если анонимная функция передается как третий аргумент, и возвращает значение true, то правила будут добавлены. Этот метод универсален для того, чтобы строить целый комплекс условных проверок. Вы можете даже добавить условные проверки на нескольких полях одновременно:

$v->sometimes(['reason', 'cost'], 'required', function ($input) {
    return $input->games >= 100;
});
Параметр $input переданный в анонимную функцию, будет экземпляром Illuminate\Support\Fluent и может быть использован для доступа к вашим полям и файлам.

Валидация массивов

Проверка массива полей из формы не должна вызывать затруднений. Например, чтобы проверить, что каждая последующая электронная почта является уникальной, вы можете сделать следующее:

$validator = Validator::make($request->all(), [
    'photos.profile' => 'required|image',
]);

Кроме того, вы можете использовать символ * в ваших языковых файлах, использовать одно сообщение для проверки массива полей:

$validator = Validator::make($request->all(), [
    'person.*.email' => 'email|unique:users',
    'person.*.first_name' => 'required_with:person.*.last_name',
]);

Таким же образом, вы можете использовать символ * при указании своих сообщений валидации в своих языковых файлах, значительно упрощая использование одного сообщения валидации для полей, основанных на массивах:

'custom' => [
    'person.*.email' => [
        'unique' => 'Each person must have a unique e-mail address',
    ]
],

Собственные правила валидации

Laravel предоставляет разнообразные и полезные правила для валидации. Однако, возможно, вам потребуется определить некоторые из своих собственных. Один из методов регистрации своих правил метод extend фасада Validator. Давайте зарегистрируем этот метод в сервис-провайдере:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Предварительная загрузка любых сервисов приложения.
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend('foo', function ($attribute, $value, $parameters, $validator) {
            return $value == 'foo';
        });
    }

    /**
     * Регистрация нового сервис-провайдера.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Анонимная функция получает четыре аргумента: имя проверяемого поля ($attribute), значение поля ($value), массив дополнительных параметров ($parameters) и экземпляр валидатора ($validator).

Класс и метод также можно передать методу extend вместо анонимной функции:

Validator::extend('foo', 'FooValidator@validate');

Определение сообщения об ошибки

Необходимо будет также определить сообщение об ошибке для вашего правила. Вы можете сделать это, либо передавая его в виде массива строк в валидатор, либо добавив в файл локализации. Это сообщение должно помещаться на первом уровне массива, но не в массиве custom, который появляется только для сообщения об ошибке конкретного атрибута:

"foo" => "Your input was invalid!",

"accepted" => "The :attribute must be accepted.",

// The rest of the validation error messages...

При создании своих правил проверки, может потребоваться определить места замены для сообщений об ошибках. Вы можете сделать это, реализовав через метод replacer в фасаде Validator. Действие необходимо определить внутри метода boot сервис-провайдера:

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Validator::extend(...);

    Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) {
        return str_replace(...);
    });
}

Скрытые расширения

По умолчанию, когда проверяемый атрибут отсутствует или содержит пустое значение, как в правиле required, валидация не выполняется, в том числе и для ваших расширений. Например, unique не будет выполнено для значения null:

$rules = ['name' => 'unique'];

$input = ['name' => null];

Validator::make($input, $rules)->passes(); // true

Правило должно подразумевать, что атрибут обязателен, даже, если он пуст. Для создания «скрытых» расширений используйте метод Validator::extendImplicit():

Validator::extendImplicit('foo', function ($attribute, $value, $parameters, $validator) {
    return $value == 'foo';
});
"Скрытое" расширение лишь подразумевает, что атрибут является обязательным. Будет ли это на самом деле недействительный или пустой атрибут, зависит только от вас.