Обработка запросов и данных в PHP: варианты реализации
Основные подходы к обработке данных в PHP
Одним из наиболее эффективных решений для безопасной обработки входящих данных является использование встроенных функций фильтрации filter_input() и filter_var(). Они позволяют одновременно проверять тип данных, очищать от нежелательных символов и валидировать значения без написания лишнего кода.
Пример получения и проверки email через GET-параметр:
$email = filter_input(INPUT_GET, 'user_email', FILTER_VALIDATE_EMAIL);
if ($email === false) {
// обработка ошибки
die('Некорректный email');
}
Если требуется целое число из POST:
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 120)));
if ($age === false) {
// значение отсутствует или не проходит валидацию
}
Цель данного подхода – минимизировать риски XSS и SQL-инъекций на этапе получения данных, а также сократить объём кода.
Типичные ошибки: использование фильтра без проверки результата (filter_input возвращает null для отсутствующего ключа, false при невалидном значении).
Проблема: если не проверить isset() до фильтрации, можно получить false и принять его за пустое значение. Решение: сначала проверять существование ключа через isset() или использовать фильтр с флагом FILTER_NULL_ON_FAILURE.
Как получить данные из суперглобальных массивов без фильтрации?
Прямое обращение к $_GET, $_POST, $_SERVER допускается, но опасно. Данные могут содержать вредоносный код. Пример:
$name = $_POST['username'];
Такое использование оправдано только при немедленном экранировании перед выводом или записью в БД. Цель – быстрый доступ, если данные заведомо безопасны (например, внутренние параметры).
Главная проблема: нет автоматической защиты от XSS и SQL-инъекций. Ошибка: забыть обработать данные перед использованием. Решение: всегда применять htmlspecialchars() для вывода в HTML и подготовленные запросы для БД.
Как экранировать строки для SQL-запросов?
Функция mysqli_real_escape_string() экранирует спецсимволы для использования в составленном SQL-запросе.
$safe_name = mysqli_real_escape_string($connection, $_POST['name']);
$sql = "SELECT * FROM users WHERE name = '$safe_name'";
Цель – предотвратить вставку произвольного SQL-кода, но лучше использовать подготовленные запросы. Применяется в легаси-проектах.
Ошибка: забыть экранировать даже один параметр. Проблема: функция зависит от активного соединения с БД. Решение: переходить на PDO.
Как защититься от SQL-инъекций современным способом?
Подготовленные запросы в PDO отделяют код от данных. Пример с именованными плейсхолдерами:
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $_POST['email']]);
$user = $stmt->fetch();
Цель – полная защита от инъекций, автоматическое экранирование PDO. Этот вариант считается наиболее эффективным для работы с базами данных.
Проблема: неправильное использование (например, эмуляция подготовленных запросов или отключение эмуляции) может снизить защиту. Решение: использовать PDO::ATTR_EMULATE_PREPARES в false и реальные подготовленные запросы.
Как обрабатывать данные с использованием filter_var для одиночных переменных?
Функция filter_var() принимает значение, а не суперглобальный массив. Подходит, когда данные уже извлечены:
$input = 'some@email.com';
$clean_email = filter_var($input, FILTER_SANITIZE_EMAIL);
$valid_email = filter_var($clean_email, FILTER_VALIDATE_EMAIL);
Цель – гибкая фильтрация и валидация любой строки. Используется для данных из файлов, API и т.д.
Ошибка: перепутать санитизацию и валидацию. Санитизация удаляет недопустимые символы, валидация проверяет формат. Решение: сначала санитизировать, потом валидировать.
Расширенные примеры обработки данных
Пример 1: Обработка формы регистрации с полной валидацией и вставкой в БД
Форма содержит поля: имя (строка), email, пароль, возраст (int). Используем filter_input для каждого поля, хешируем пароль через password_hash, вставляем через PDO.
<?
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 120]]);
$password = $_POST['password'] ?? '';
if (!$name || !$email || !$age || strlen($password) < 8) {
die('Неверные данные');
}
$hash = password_hash($password, PASSWORD_DEFAULT);
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$stmt = $pdo->prepare('INSERT INTO users (name, email, age, password) VALUES (:n, :e, :a, :p)');
$stmt->execute(['n' => $name, 'e' => $email, 'a' => $age, 'p' => $hash]);
echo 'Пользователь добавлен';
?>
При успешной вставке: Пользователь добавлен При ошибке валидации: Неверные данные
Пример 2: Загрузка файла с проверкой типа и размера
Проверяем расширение, MIME-тип и размер. Перемещаем загруженный файл в безопасную директорию.
<?
$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
$max_size = 2 * 1024 * 1024; // 2MB
$upload_dir = __DIR__ . '/uploads/';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
die('Ошибка загрузки');
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, $allowed_types)) {
die('Недопустимый тип файла');
}
if ($file['size'] > $max_size) {
die('Файл слишком большой');
}
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$new_name = uniqid() . '.' . $ext;
if (move_uploaded_file($file['tmp_name'], $upload_dir . $new_name)) {
echo 'Файл сохранён: ' . $new_name;
} else {
echo 'Ошибка перемещения';
}
}
?>
При загрузке PNG 1.5 МБ: Файл сохранён: 65a1f8e2c3d45.png При попытке загрузить скрипт: Недопустимый тип файла
Пример 3: Обработка JSON из тела запроса (API)
Получаем JSON через php://input, декодируем, валидируем каждое поле.
<?
$json = file_get_contents('php://input');
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(400);
echo json_encode(['error' => 'Некорректный JSON']);
exit;
}
$name = filter_var($data['name'] ?? '', FILTER_SANITIZE_STRING);
$email = filter_var($data['email'] ?? '', FILTER_VALIDATE_EMAIL);
if (!$name || !$email) {
http_response_code(422);
echo json_encode(['error' => 'Отсутствуют обязательные поля или неверный формат']);
exit;
}
echo json_encode(['status' => 'ok', 'name' => $name, 'email' => $email]);
?>
Запрос: {"name":"Иван", "email":"ivan@example.com"}
Ответ: {"status":"ok","name":"Иван","email":"ivan@example.com"}
Запрос: {"name":"Петр"}
Ответ: {"error":"Отсутствуют обязательные поля или неверный формат"}