Веб

Laravel валидация boolean: проверка флагов на true

Как правильно настроить валидацию в Laravel Form Request для проверки boolean флагов на true. Почему in:true не работает с FormData и JSON, и как использовать prepareForValidation с filter_var для надежной проверки.

Как правильно настроить валидацию в Laravel для проверки, что значение поля равно true? В моем Form Request классе я использую следующие правила:

php
public function rules(): array
{
 return [
 'flag1' => ['required', 'in:true'],
 'flag2' => ['required', 'in:true'],
 'flag3' => ['required', 'in:true'],
 'flag4' => ['required', 'in:true'],
 ];
}

Подходит ли такой подход для проверки, что все четыре флага установлены в true? Я заметил, что при отправке в FormData просто true валидация проходит успешно, но при отправке строки "true" (в кавычках) - нет. Однако при отправке JSON вида:

json
{
 "flag1": "true"
}

валидация проходит, хотя это тоже строка. Почему такое поведение и как правильно реализовать валидацию для булевых значений в Laravel?

Использовать правило in:true для проверки, что поле равно true — ненадёжно: сравнение зависит от типа и формата входных данных (FormData / application/json). Для корректной laravel валидация boolean-флагов нормализуйте вход (например, в prepareForValidation() с filter_var) и затем проверяйте через правило boolean/accepted или через кастомное правило, которое явно требует true. Это уберёт разницу между строками "true", числами 1 и настоящим булевым true.


Содержание


Как работает правило boolean в Laravel

Правило boolean в документации Laravel описано как проверка, что поле может быть приведено к логическому типу: “Accepted input are true, false, 1, 0, “1”, and “0”.” Это означает, что Laravel ожидает значения вроде true, false, 1, 0, "1", "0" и приведёт совместимые значения к boolean перед дальнейшей обработкой — подробнее в документации Laravel и в русской версии laravel.su.

Правило in — другое: оно проверяет, что значение равно одному из перечисленных параметров (либо строка, либо значение, зависящее от типов). Это делает in:true хрупким решением: всё зависит от того, как именно пришло значение (строка "true", булево true, строка с кавычками "\"true\"" и т.д.). Сообщество неоднократно обсуждало неоднозначности поведения boolean-валидации в разных сценариях — см. обсуждение на Stack Overflow и на GitHub.


Почему in:true даёт неожиданные результаты для FormData и JSON

Коротко: всё зависит от типа, который попадает в PHP. Два ключевых момента:

  • FormData / application/x-www-form-urlencoded: браузер присылает значения как строки. В JS formData.append('flag', true) превращает true в строку "true". Если вы случайно добавите лишние кавычки (например, formData.append('flag', '"true"')) — в запрос попадёт строка с кавычками и сравнение не пройдёт.
  • application/json: если клиент отправил JSON и значение без кавычек — { "flag": true } — то json_decode выдаст в PHP булево true. Если же вы отправили { "flag": "true" }, то это строка "true".

Пример клиента (FormData):

js
const fd = new FormData();
fd.append('flag1', true); // отправится как "true"
fd.append('flag2', 'true'); // отправится как "true"
fd.append('flag3', '"true"'); // отправится как "\"true\"" — опасно

Пример клиента (JSON):

js
fetch('/api/flags', {
 method: 'POST',
 headers: { 'Content-Type': 'application/json' },
 body: JSON.stringify({ flag1: true }) // булевое true
});

Итог: in:true иногда проходит и иногда нет, потому что сервер может получать либо булево, либо строку, либо строку с лишними символами. Поэтому полагаться на in:true для API, где формат входа меняется, — плохая идея. На эту проблему указывает и обсуждение на Stack Overflow.


Надёжные способы: prepareForValidation, кастомное Rule, accepted

Ниже — рабочие подходы, упорядоченные от простого к надёжному.

  1. Нормализация в prepareForValidation()
  • Приведите вход к boolean до валидации с помощью PHP filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) — он распознаёт "1", "true", "on", "yes" как true и "0", "false", "off", "no" как false; с флагом FILTER_NULL_ON_FAILURE возвращает null для некорректных значений (хорошо для детекции ошибок). Практический пример и обсуждение такого подхода есть в статье Echebaby.
  1. Использовать правило boolean + строгую проверку
  • После нормализации в prepareForValidation() можно применить правило boolean и затем требовать === true с помощью замыкания или Rule-класса.
  1. Кастомное правило (implements Rule)
  • Реализуйте Rule, которое внутри использует filter_var(..., FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) и возвращает true только если именно true. Это централизует логику и делает код читаемым.
  1. Правило accepted
  • Для HTML-checkbox/тогглов удобнее accepted — оно принимает yes, on, 1, true. Но помните: accepted ориентировано на формы, не на произвольные API-пейлоады.
  1. Валидация после приведения (withValidator/after)
  • Можно проверить все четыре флага сразу в withValidator() и добавить ошибки, если какой-то флаг не равен true.

Замечание: в разных версиях и контекстах поведение boolean/in обсуждалось (см. GitHub issue), поэтому нормализация на вашей стороне — самый устойчивый путь.


Примеры кода (FormRequest и кастомное правило)

Пример FormRequest с нормализацией и строгой проверкой:

php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class FlagsRequest extends FormRequest
{
 protected array $flags = ['flag1', 'flag2', 'flag3', 'flag4'];

 protected function prepareForValidation(): void
 {
 $data = [];
 foreach ($this->flags as $f) {
 $value = $this->input($f, null);
 // NULL при ошибке парсинга, true/false при валидных значениях
 $data[$f] = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
 }
 $this->merge($data);
 }

 public function rules(): array
 {
 // теперь в $this->input($f) будут true/false/null
 return array_combine($this->flags, array_map(fn() => ['required', 'boolean', function($attr, $val, $fail) {
 if ($val !== true) {
 $fail("Поле {$attr} должно быть true.");
 }
 }], $this->flags));
 }
}

Кастомное правило (короткая версия):

php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class IsTrue implements Rule
{
 public function passes($attribute, $value): bool
 {
 return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === true;
 }

 public function message(): string
 {
 return 'Поле :attribute должно быть true.';
 }
}

Использование в правилах:

php
'flag1' => ['required', new \App\Rules\IsTrue()],
// аналогично для flag2..flag4

Рекомендации по отправке данных с клиента

  • Для API: предпочтительнее JSON и реальные булевы значения. Пример:
    fetch(…, { body: JSON.stringify({ flag1: true }) }) — тогда Laravel получит булев true.
  • Для FormData/старых форм: отправляйте однозначные значения, например '1' или 'on', и нормализуйте на сервере. HTML-галочка по умолчанию отправляет on.
  • Всегда логируйте или делайте dd($request->all()), если поведение кажется странным — так вы увидите, что реально пришло на сервер.
  • Не отправляйте строки с кавычками внутри (например "\"true\""), это частая ошибка при сериализации.

Источники

  1. Validation - Laravel 11.x - The PHP Framework For Web Artisans
  2. Validating boolean with Laravel Validation - Stack Overflow
  3. Laravel validate ‘true’ and ‘false’ as booleans — Echebaby blog
  4. Валидация Laravel 12.x (laravel.su)
  5. Boolean validation does not accept “true” and “false”, but accepts “1”, “0” — GitHub

Заключение

Коротко: in:true — ненадёжный способ для проверки булевых флагов, потому что формат и тип данных зависят от клиента (FormData vs JSON). Для корректной laravel валидация нормализуйте вход (prepareForValidation с filter_var или кастомное Rule) и затем требуйте true (через boolean + замыкание или Rule, или через accepted для чекбоксов). Сделав нормализацию, вы получите устойчивую и предсказуемую валидацию вне зависимости от того, приходит ли "true", 1 или настоящий булев true.

Авторы
Проверено модерацией
Модерация
Laravel валидация boolean: проверка флагов на true