Основные методы фильтрации данных в PHP
Фильтрация данных в PHP: основные подходы
Наиболее эффективное решение
Для обеспечения безопасности веб-приложений следует использовать встроенные функции PHP filter_var() и filter_input(). Они позволяют как валидировать (проверять соответствие формату), так и санитизировать (очищать от опасных символов) данные. Этот подход работает единообразно для всех типов данных и снижает риск ошибок, связанных с ручной обработкой.
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if ($email === false) {
// обработка ошибки
}
Access php (доступ к файлам в php)
В примере проверяется, является ли значение из $_POST['email'] корректным электронным адресом. Если нет, функция возвращает false. Для санитизации используется FILTER_SANITIZE_STRING (устарел, но в качестве примера) или FILTER_SANITIZE_SPECIAL_CHARS.
Пошаговая инструкция:
- Определить тип ожидаемых данных (email, URL, целое число и т.д.).
- Выбрать соответствующий фильтр из списка констант FILTER_VALIDATE_* или FILTER_SANITIZE_*.
- Передать данные и фильтр в filter_var() или filter_input().
- Проверить результат: если валидация не пройдена, выдать сообщение об ошибке; если санитизация - использовать очищенное значение.
- Никогда не доверять отфильтрованным данным как окончательно безопасным для SQL или вывода - всегда использовать подготовленные запросы и экранирование контекста.
Как фильтровать входные данные напрямую из суперглобальных массивов?
Функция filter_input() принимает тип входных данных (INPUT_GET, INPUT_POST, INPUT_COOKIE и др.), имя переменной и фильтр. Это сокращает код и гарантирует, что данные извлекаются только из указанного источника.
$user_id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 1000)));
if ($user_id === false || $user_id === null) {
// неверные данные
}
Php filter (фильтрация данных в php)
Проблемы и ошибки:
Если переменная не существует, filter_input() возвращает null, что можно спутать с успешной валидацией. Всегда проверять на false и null отдельно.
Также стоит помнить, что для FILTER_SANITIZE_STRING (устарел) может быть неочевидное поведение при работе с многобайтовыми кодировками.
Как очистить строку от нежелательных символов?
Фильтры санитизации удаляют или преобразуют опасные символы. Например, FILTER_SANITIZE_SPECIAL_CHARS экранирует HTML-сущности, а FILTER_SANITIZE_NUMBER_INT оставляет только цифры и знаки.
$clean_string = filter_var($input, FILTER_SANITIZE_SPECIAL_CHARS);
// превратится в <script>alert('xss')</script>
Php пароль (работа с паролями в php)
Важно: санитизация не заменяет валидацию. Если необходимо проверить формат, используйте валидационные фильтры после санитизации.
Ошибка: использование FILTER_SANITIZE_STRING может удалить полезные данные, например, кавычки в именах. Лучше применять контекстно-зависимые фильтры.
Как проверить корректность IP-адреса или URL с дополнительными параметрами?
Фильтры FILTER_VALIDATE_IP и FILTER_VALIDATE_URL поддерживают флаги для уточнения требований. Например, только IPv4 или разрешить только URL с определёнными протоколами.
$ip = filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
$url = filter_var($input, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED);
Tokens php (токены в php)
Проблема: фильтр FILTER_VALIDATE_URL не проверяет существование хоста, только синтаксис. Для проверки DNS необходимо использовать дополнительную функцию.
Как применить фильтр ко всем элементам массива?
Функции filter_var_array() и filter_input_array() позволяют определить фильтры для каждого ключа массива в виде ассоциативного массива или даже для всего массива целиком.
$filters = array(
'name' => FILTER_SANITIZE_SPECIAL_CHARS,
'age' => array('filter' => FILTER_VALIDATE_INT, 'options' => array('min_range' => 1)),
'email' => FILTER_VALIDATE_EMAIL
);
$result = filter_var_array($_POST, $filters);
Https load php (загрузка через https в php)
Ошибка: если массив содержит вложенные массивы, фильтрация не применяется рекурсивно. Нужно обрабатывать каждый уровень отдельно.
Как создать пользовательский фильтр?
Встроенные фильтры не покрывают всех потребностей. Можно использовать FILTER_CALLBACK с пользовательской функцией.
$validate_strength = function($value) {
return (strlen($value) >= 8 && preg_match('/[A-Z]/', $value)) ? $value : false;
};
$password = filter_var($input, FILTER_CALLBACK, array('options' => $validate_strength));
Важно: callback-функция должна возвращать отфильтрованное значение или false при ошибке. Не следует выбрасывать исключения, так как filter_var() их не ловит.
Типичные ошибки при работе с фильтрацией
- Путаница между валидацией и санитизацией: валидация проверяет формат, санитизация изменяет данные. Не следует санитизировать данные, которые потом будут проверяться на точное соответствие.
- Игнорирование возвращаемого значения false: если фильтр возвращает false, нужно обработать ошибку, а не продолжать использовать исходные данные.
- Использование устаревших фильтров: FILTER_SANITIZE_STRING помечен как устаревший, лучше применять htmlspecialchars() или FILTER_SANITIZE_SPECIAL_CHARS.
- Отсутствие проверки на null при использовании filter_input().
- Доверие к отфильтрованным данным как к полностью безопасным: фильтрация не защищает от SQL-инъекций - используйте PDO с подготовленными запросами.
Расширенные примеры фильтрации данных
Валидация email с проверкой наличия MX-записи
function validateEmailWithMX($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return false;
}
$domain = substr(strrchr($email, '@'), 1);
return checkdnsrr($domain, 'MX');
}
$test = 'user@example.com';
var_dump(validateEmailWithMX($test));
bool(true) // если MX-запись существует
Валидация URL с обязательным протоколом и проверкой доступности
$url = 'https://www.php.net';
$validated = filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED);
if ($validated) {
$headers = @get_headers($url);
$accessible = (strpos($headers[0], '200') !== false);
}
var_dump($validated, $accessible ?? false);
string(22) "https://www.php.net" bool(true)
Фильтрация целочисленного массива с диапазонами
$input = ['5', '12', 'abc', '0', '150'];
$filters = array(
'filter' => FILTER_VALIDATE_INT,
'flags' => FILTER_REQUIRE_ARRAY,
'options' => array('min_range' => 1, 'max_range' => 100)
);
$result = filter_var_array($input, $filters);
print_r($result);
Array
(
[0] => 5
[1] => 12
[2] => false
[3] => false
[4] => false
)
Санитизация многобайтовой строки без удаления кириллицы
$text = "Привет мир!";
$clean = filter_var($text, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
echo $clean;
Привет <script>alert('xss')</script> мир!
Пользовательский фильтр для проверки сложности пароля
$password = 'MyStr0ng!Pass';
$callback = function($value) {
if (strlen($value) < 8) return false;
if (!preg_match('/[A-Z]/', $value)) return false;
if (!preg_match('/[a-z]/', $value)) return false;
if (!preg_match('/[0-9]/', $value)) return false;
if (!preg_match('/[!@#$%^&*(),.?":{}|<>]/', $value)) return false;
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
};
$filtered = filter_var($password, FILTER_CALLBACK, array('options' => $callback));
var_dump($filtered);
string(16) "MyStr0ng!Pass"
Фильтрация входных данных с filter_input_array и проверка ошибок
$definition = array(
'username' => FILTER_SANITIZE_SPECIAL_CHARS,
'age' => array('filter' => FILTER_VALIDATE_INT, 'options' => array('min_range' => 0)),
'agree' => array('filter' => FILTER_VALIDATE_BOOLEAN, 'flags' => FILTER_NULL_ON_FAILURE)
);
$result = filter_input_array(INPUT_POST, $definition);
if ($result === null) {
echo 'Нет данных POST';
} else {
foreach ($result as $key => $value) {
if ($value === false) {
echo "Поле $key не прошло валидацию
";
}
}
}
Использование FILTER_SANITIZE_NUMBER_FLOAT для денежных значений
$input = '$1,234.56';
$clean = filter_var($input, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND);
echo $clean;
1234.56
Валидация IP-адреса с проверкой, не является ли он частным
$ip = '192.168.1.1';
$valid = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_IPV4);
var_dump($valid);
bool(false) // так как 192.168.0.0/16 является приватным диапазоном
Фильтрация данных из внешнего API с рекурсивной обработкой
function filterRecursive($data, $filter_definition) {
if (is_array($data)) {
return array_map(function($item) use ($filter_definition) {
return filterRecursive($item, $filter_definition);
}, $data);
}
return filter_var($data, $filter_definition);
}
$apiData = [
'users' => [
['name' => 'Alice', 'email' => 'alice@test.com'],
['name' => '', 'email' => 'bob@test.com']
]
];
$cleaned = filterRecursive($apiData, FILTER_SANITIZE_SPECIAL_CHARS);
print_r($cleaned);
Array
(
[users] => Array
(
[0] => Array
(
[name] => Alice
[email] => alice@test.com
)
[1] => Array
(
[name] => <Bob>
[email] => bob@test.com
)
)
)