Валидация и фильтрация в PHP: сравниваем четыре подхода
filter_var, встроенные проверки фреймворка, отдельная библиотека или регулярки — у каждого способа своя цена. Разбираем, где что использовать и на чём чаще всего обжигаются.

Форма регистрации принимает поле email, разработчик оборачивает его в filter_var($email, FILTER_VALIDATE_EMAIL) и считает задачу закрытой. Через месяц в базе оказываются строки вида user@localhost, адреса с плюс-алиасами, которые ломают внешний сервис рассылки, и одна запись, где в поле name лежит кусок HTML. Проверка формата и защита от вредных данных — разные задачи, и путаница между ними стоит дороже всего. Разберём четыре рабочих подхода к валидации и фильтрации в PHP 8.x, у каждого своя цена.
Сразу разведём два понятия, потому что дальше на них всё держится.
Валидация отвечает на вопрос «эти данные вообще корректны?» и либо пропускает значение, либо отклоняет. Фильтрация (санитизация) изменяет данные — вырезает или экранирует то, что считает лишним. Смешивать их в одном шаге — источник тихих багов: вы думаете, что проверили, а на самом деле молча испортили ввод.
Четыре подхода
1. Встроенные фильтры: filter_var и filter_input
PHP из коробки даёт filter_var и filter_input. Первый работает с любой переменной, второй читает прямо из $_GET, $_POST и других суперглобальных массивов, минуя уже, возможно, изменённые значения.
<?php
// PHP 8.x
// Валидация: вернёт нормализованный email или false
$email = filter_var($raw, FILTER_VALIDATE_EMAIL);
if ($email === false) {
// адрес не прошёл проверку формата
}
// Валидация числа в диапазоне
$age = filter_var($raw, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 0, 'max_range' => 150],
]);
// $age === false, если не целое или вне диапазона
// Чтение напрямую из запроса
$page = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT);
Плюс — нулевые зависимости и предсказуемость. Минус — набор фильтров ограничен: e-mail, URL, IP, целые, числа с плавающей точкой, булевы, регулярка через FILTER_VALIDATE_REGEXP. Валидатора «строка длиной от 3 до 20 символов» здесь нет — придётся дописывать руками. И важная ловушка: FILTER_VALIDATE_EMAIL проверяет только синтаксис, но не существование ящика и не то, что домен вам подходит. user@localhost для него валиден.
2. Регулярные выражения
Соблазн описать любое правило через preg_match велик, и для узких форматов он оправдан: артикул товара, номер телефона в вашем формате, код из письма.
<?php
// Код подтверждения: ровно 6 цифр
if (!preg_match('/^\d{6}$/', $code)) {
// неверный формат
}
Цена регулярок — читаемость и безопасность. Регулярку для e-mail по RFC невозможно написать корректно вручную, а популярные «готовые» варианты либо отсекают валидные адреса, либо пропускают мусор. Отдельная опасность — ReDoS: неудачное выражение с вложенными квантификаторами ((a+)+) при специально подобранной строке уводит CPU в потолок. Для форматов, где уже есть встроенный фильтр, регулярка — лишний риск.
3. Валидация средствами фреймворка
Если проект на Laravel или Symfony, валидация уже встроена, и писать её отдельно бессмысленно. В Laravel это правила валидатора, в Symfony — компонент Validator с атрибутами на свойствах DTO.
<?php
// Laravel 11.x — правила в контроллере или Form Request
$validated = $request->validate([
'email' => ['required', 'email:rfc'],
'age' => ['required', 'integer', 'min:0', 'max:150'],
'name' => ['required', 'string', 'min:3', 'max:20'],
]);
// $validated содержит только прошедшие проверку поля
Точные имена правил и опций сверяйте с документацией вашей мажорной версии: набор правил и синтаксис между релизами меняются. Плюс подхода — правила, сообщения об ошибках и локализация уже связаны, а невалидный запрос сам возвращает ответ с ошибками. Минус — вы завязаны на фреймворк: вынести эту валидацию в отдельный CLI-скрипт или очередь без обвязки не получится.
4. Отдельная библиотека валидации
Когда логика проверок сложная, а фреймворк лёгкий или его нет, берут специализированную библиотеку — например respect/validation. Она даёт цепочки правил и работает независимо от HTTP-слоя.
<?php
use Respect\Validation\Validator as v;
$isValid = v::stringType()
->length(3, 20)
->validate($name); // true / false
Плюс — богатый набор правил и переносимость между проектами. Минус — ещё одна зависимость в composer.json, которую надо обновлять и держать совместимой с версией PHP. Точный список доступных валидаторов и их сигнатуры смотрите в документации конкретной версии пакета.
Сравнение
| Подход | Зависимости | Гибкость правил | Где силён | Слабое место |
|---|---|---|---|---|
| filter_var / filter_input | нет | низкая | email, URL, IP, числа | нет проверки длины строк, ограниченный набор |
| Регулярки | нет | высокая, но опасная | узкие фиксированные форматы | читаемость, ReDoS, легко ошибиться |
| Валидатор фреймворка | фреймворк | высокая | формы, API внутри приложения | привязка к фреймворку |
| Библиотека (respect и др.) | composer-пакет | высокая | сложная логика вне HTTP | ещё одна зависимость |
Отдельно про фильтрацию и экранирование
Валидация не защищает от инъекций — это делает правильное экранирование в точке вывода, а не на входе. Здесь главная ошибка — санитизировать данные при приёме «на всякий случай» и потерять оригинал.
- SQL: не экранируйте строки руками, используйте параметризованные запросы (prepared statements) через PDO или mysqli. Значение уходит отдельно от текста запроса — инъекция становится невозможной.
- HTML-вывод: экранируйте в шаблоне через
htmlspecialchars($value, ENT_QUOTES, 'UTF-8'). Не чистите ввод при сохранении: одна и та же строка может выводиться и в HTML, и в JSON, и в письмо — правила экранирования разные. - Богатый HTML от пользователя (комментарии с форматированием) нельзя чистить регуляркой. Здесь нужен специализированный санитайзер вроде HTML Purifier, который парсит DOM и вырезает опасные конструкции по белому списку.
Когда что выбирать
- Проект без фреймворка, простые поля —
filter_varиfilter_inputдля email, URL, чисел плюс ручная проверка длины строк. Не тащите библиотеку ради трёх полей. - Один-два фиксированных формата (код, артикул) — регулярка, но только на плоских выражениях без вложенных квантификаторов.
- Приложение на Laravel/Symfony — штатный валидатор, не изобретайте параллельный слой.
- Сложная переносимая логика, микросервис, обработка в очереди — отдельная библиотека, чтобы валидация не зависела от HTTP-запроса.
Что чаще всего ломается
- Валидацию считают защитой от инъекций. Прошедший
FILTER_VALIDATE_EMAILадрес всё равно нужно параметризовать в запросе и экранировать при выводе. - Чтение из
$_POSTвместоfilter_input(INPUT_POST, ...), когда где-то раньше суперглобальный массив уже изменили. - Санитизация при сохранении: испорченный ввод уже не вернуть, а для JSON или письма экранирование всё равно другое.
- Отсутствие проверки, что поле вообще пришло.
filter_inputвернётnullдля отсутствующего ключа иfalseдля невалидного — это разные случаи, и их надо различать.
Что делать дальше
Разделите в коде два слоя: валидацию на границе приложения и экранирование в точке вывода. Заведите единый Form Request или DTO с правилами, чтобы проверки не расползались по контроллерам. Подключите статический анализатор (PHPStan, Psalm) — он поймает места, где значение из запроса уходит в запрос или вывод без обработки. И проверьте свои регулярки на устойчивость к ReDoS, если через них проходят пользовательские строки произвольной длины.
Проверка грамотности: Орфография, пунктуация, стиль — с объяснением каждой правки
Спросить за 10 ₽Источники: PHP Manual — Data Filtering (filter_var, filter_input), PHP Manual — PDO Prepared Statements
Частые вопросы
У меня старая версия PHP 7.4, эти примеры сработают?
filter_var с FILTER_VALIDATE_EMAIL пропускает адрес, а рассылка его отвергает. Почему?
Можно ли фильтрацией на входе полностью защититься от SQL-инъекций?
Что вернёт filter_input, если поля нет в запросе?
Что такое ReDoS и как понять, что моя регулярка уязвима?
Стоит ли писать собственный класс валидации вместо библиотеки?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.