Проверка ввода
Вернёмся к бланку заказа. Его мог заполнить кто угодно: в графе «количество» написано «много», а в графе «блюдо» — то, чего нет в меню. Хороший повар сначала сверяет бланк с меню и только потом готовит.
Программе нужна такая же сверка. Каждое значение из запроса выбрал посетитель, и (int) его не проверяет: (int) '15kg' молча даёт 15. Проверка ввода — сравнение значения с правилом до того, как программа его использует. Значение, которое не прошло проверку, не используют, а посетителю показывают ошибку.
filter_var
Функция filter_var проверяет строку по готовому правилу. Правило передают вторым аргументом: константа FILTER_VALIDATE_INT означает целое число, FILTER_VALIDATE_EMAIL — адрес почты.
<?php
var_dump(filter_var('15', FILTER_VALIDATE_INT)); // int(15)
var_dump(filter_var('15kg', FILTER_VALIDATE_INT)); // bool(false)
var_dump((int) '15kg'); // int(15)
var_dump(filter_var('bob@mail.com', FILTER_VALIDATE_EMAIL)); // string(12) "bob@mail.com"
var_dump(filter_var('bob@', FILTER_VALIDATE_EMAIL)); // bool(false)Целое число
FILTER_VALIDATE_INT проверяет всю строку. '15' проходит и возвращается уже числом int(15). В '15kg' после цифр идут буквы, поэтому результат — false.
Приведение (int) в той же ситуации нашло бы цифры в начале и молча дало 15.
Адрес почты
FILTER_VALIDATE_EMAIL возвращает сам адрес, если он правильный, и false, если нет. В 'bob@' нет части после @, и проверка не проходит.
Общее правило filter_var: при успехе она возвращает значение, при неудаче — false. Поэтому результат сравнивают строго: === false.
Белый список
Некоторые значения не нужно проверять по виду: их выбирают из короткого списка. Сортировка бывает по имени или по цене, и любое другое слово в ?sort= — ошибка или попытка взлома. Белый список — список разрешённых значений: всё, чего в нём нет, отвергают.
$_GET = ['sort' => 'date'];
$sort = $_GET['sort'] ?? 'name';
if (!in_array($sort, ['name', 'price'], true)) {
$sort = 'name';
}
echo $sort, "\n"; // nameЗначения 'date' в списке нет, поэтому программа берёт 'name'. Как вы уже знаете, третий аргумент true включает у in_array строгое сравнение. Белый список надёжнее перечня запрещённого: всё опасное не перечислить, а разрешённое умещается в одну строку.
Здесь картинка с меню неточна: у повара одно меню на все заказы. Программе же для каждого поля нужно своё правило — число, адрес почты или список.
Проверка формы
Посетитель часто копирует адрес почты вместе с пробелом, и FILTER_VALIDATE_EMAIL такой адрес отвергает. Поэтому перед проверкой пробелы по краям убирают функцией trim. Ошибки удобно собирать в массив, чтобы показать посетителю все сразу:
$_POST = ['email' => ' ann@mail.ru ', 'age' => '15kg'];
$errors = [];
$email = filter_var(trim($_POST['email'] ?? ''), FILTER_VALIDATE_EMAIL);
if ($email === false) {
$errors[] = 'Check the email';
}
$age = filter_var($_POST['age'] ?? '', FILTER_VALIDATE_INT);
if ($age === false) {
$errors[] = 'Age must be a whole number';
}
echo $email, "\n"; // ann@mail.ru
echo count($errors), ' ', $errors[0], "\n"; // 1 Age must be a whole numberДавайте разберём по шагам:
trimубирает пробелы по краям, и адрес проходит проверку.- Возраст
'15kg'проверку не проходит, и в$errorsпоявляется сообщение. - Пустой
$errorsзначит, что данные можно использовать. Иначе страница снова показывает форму, а над ней — ошибки.
Проверка не заменяет экранирование. Фамилия O'Brien пройдёт любую разумную проверку, но при выводе в HTML её всё равно пропускают через htmlspecialchars. Чем проверка ввода отличается от экранирования вывода, любят спрашивать на собеседовании: первая решает, принять ли значение, второе — как безопасно его напечатать.
Частая ошибка
Результат filter_var проверяют через !:
<?php
$qty = filter_var('0', FILTER_VALIDATE_INT);
if (!$qty) { // ✗
echo 'Not a number', "\n";
}Программа печатает Not a number, хотя '0' — правильное целое число. filter_var вернула int(0), а ноль — ложное значение, поэтому !$qty истинно. Чтобы исправить, сравните строго: if ($qty === false).
После курса
Это последний теоретический урок курса. Сессии, базы данных и фреймворки в курс не вошли.
Дальше проверьте себя на симуляторе собеседования по PHP на этом сайте. Он задаёт вопросы по темам курса и по тем, которых курс не касался, и оценивает ответы.
Главное
- Каждое значение из запроса выбрал посетитель, поэтому перед использованием его проверяют.
filter_varвозвращает проверенное значение илиfalse:'15kg'сFILTER_VALIDATE_INTдаётfalse, хотя(int)дал бы15.- Значение из короткого набора сверяют с белым списком через
in_arrayсо строгим сравнением. - Результат
filter_varсравнивают строго,=== false, потому что0— правильное число.