PHP Filter
Расширение filter в PHP: валидация и санитизация, filter_var(), filter_input(), константы FILTER_VALIDATE_* и FILTER_SANITIZE_*, флаги.
Расширение filter в PHP — это встроенный инструмент для проверки и очистки данных, поступающих извне скрипта: из полей форм, строк запросов, cookies и HTTP-заголовков. Поскольку эти данные контролируются пользователем (а иногда и злоумышленником), им никогда нельзя доверять напрямую. На этой странице объясняется разница между валидацией и санитизацией, описаны основные функции (filter_var() и filter_input()), наиболее полезные константы фильтров и типичные ошибки.
Валидация и санитизация
Расширение filter выполняет две разные задачи, и их путаница — самая распространённая ошибка:
- Валидация — проверяет, соответствует ли значение правилу, и возвращает значение при успехе или
falseпри неудаче. Значение никогда не изменяется. Используйте фильтрыFILTER_VALIDATE_*. - Санитизация — удаляет или экранирует недопустимые символы и возвращает очищенную строку. Она не сообщает, было ли входное значение «правильным». Используйте фильтры
FILTER_SANITIZE_*.
Практическое правило: валидируйте, чтобы решить, принять ли входные данные; санитизируйте, чтобы сделать их безопасными для использования. Эти операции не взаимозаменяемы — санитизированный адрес электронной почты не гарантирует, что он корректно сформирован.
filter_var() — фильтрация одной переменной
filter_var() — основная рабочая функция. Она принимает значение, константу фильтра и необязательные параметры:
filter_var(mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0): mixedВалидация
<?php
$email = "[email protected]";
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "Email is valid\n";
} else {
echo "Email is invalid\n";
}
// Numbers, URLs and IPs work the same way:
var_dump(filter_var("42", FILTER_VALIDATE_INT)); // int(42)
var_dump(filter_var("not-a-number", FILTER_VALIDATE_INT)); // bool(false)
var_dump(filter_var("https://w3docs.com", FILTER_VALIDATE_URL)); // stringВывод:
Email is valid
int(42)
bool(false)
string(18) "https://w3docs.com"Подводный камень: фильтры валидации возвращают
falseпри неудаче, но0и""тоже являются ложными значениями.filter_var("0", FILTER_VALIDATE_INT)возвращаетint(0), что провалит простую проверкуif. Сравнивайте с=== falseили передавайтеFILTER_NULL_ON_FAILURE, чтобы неудачные проверки давалиnullи можно было использовать!== null.
Санитизация
<?php
$dirty = " john (doe)@exa<>mple.com ";
echo filter_var($dirty, FILTER_SANITIZE_EMAIL), "\n"; // [email protected]
$comment = "<script>alert(1)</script>Hi";
echo filter_var($comment, FILTER_SANITIZE_SPECIAL_CHARS), "\n";Вывод:
[email protected]
<script>alert(1)</script>HiПередача параметров и флагов
Многие фильтры принимают дополнительные параметры. Например, можно валидировать целое число только в заданном диапазоне:
<?php
$options = [
"options" => ["min_range" => 1, "max_range" => 120],
];
var_dump(filter_var("130", FILTER_VALIDATE_INT, $options)); // bool(false)
var_dump(filter_var("25", FILTER_VALIDATE_INT, $options)); // int(25)Вывод:
bool(false)
int(25)К полезным флагам относятся: FILTER_NULL_ON_FAILURE (возвращает null вместо false), FILTER_FLAG_STRIP_LOW (удаляет символы ниже ASCII 32), а также FILTER_FLAG_IPV6 / FILTER_FLAG_IPV4 для уточнения FILTER_VALIDATE_IP.
filter_input() — фильтрация данных запроса напрямую
filter_input() считывает значение из суперглобальной переменной (по имени) и фильтрует его за один шаг, так что вам не нужно обращаться к необработанному массиву $_POST / $_GET:
filter_input(int $type, string $var_name, int $filter = FILTER_DEFAULT, array|int $options = 0): mixed$type — одна из констант: INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER или INPUT_ENV:
<?php
// In a real form handler:
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if ($email === false) {
echo "Please enter a valid email.";
} elseif ($email === null) {
echo "The email field was not submitted.";
} else {
echo "Got: $email";
}Обратите внимание на три возможных результата: значение (прошло проверку), false (присутствует, но недействительно) или null (поле не было отправлено). Для фильтрации целой формы за один раз см. filter_var_array() и filter_input_array().
Часто используемые константы фильтров
| Фильтр | Тип | Назначение |
|---|---|---|
FILTER_VALIDATE_EMAIL | валидация | Адрес электронной почты |
FILTER_VALIDATE_URL | валидация | URL |
FILTER_VALIDATE_INT / FILTER_VALIDATE_FLOAT | валидация | Целые / дробные числа |
FILTER_VALIDATE_IP | валидация | Адрес IPv4 / IPv6 |
FILTER_VALIDATE_BOOLEAN | валидация | "yes", "on", "1" → true |
FILTER_SANITIZE_EMAIL | санитизация | Удаление недопустимых символов email |
FILTER_SANITIZE_URL | санитизация | Удаление недопустимых символов URL |
FILTER_SANITIZE_NUMBER_INT | санитизация | Оставляет цифры и + - |
FILTER_SANITIZE_SPECIAL_CHARS | санитизация | HTML-кодирование < > & " ' |
Устарело с PHP 8.1:
FILTER_SANITIZE_STRING(и его псевдонимFILTER_SANITIZE_STRIPPED). Для экранирования вывода используйтеhtmlspecialchars(); для очистки входных данных предпочтительнее конкретный фильтр валидации с контекстно-зависимым экранированием в точке использования.
Когда стоит использовать расширение filter?
- Проверка регистрационной формы или формы обратной связи перед сохранением — используйте совместно с PHP Form Validation и валидацией полей URL и e-mail.
- Проверка того, что параметр
idв строке запроса является положительным целым числом перед запросом к базе данных. - Чтение и проверка значений из cookies или
$_SERVER.
Фильтрация дополняет, но не заменяет другие меры защиты: используйте подготовленные запросы (PHP MySQLi prepared statements) против SQL-инъекций и htmlspecialchars() при выводе пользовательских данных в HTML. Для правил на основе шаблонов, которые нельзя выразить средствами расширения filter, обратитесь к регулярным выражениям.