Урок 17: Проверка данных из форм через PHP (валидация и защита от SQL-инъекций)

В этом уроке мы поговорим о важной теме — проверке данных, которые пользователи вводят в формы на вашем сайте. Это не только поможет вам сделать ваши приложения более надежными, но и защитит их от потенциальных угроз, таких как SQL-инъекции.

Представьте, что вы создали форму регистрации. Пользователь вводит email, пароль и имя. Если не проверить эти данные, злоумышленник может:

  • Отправить пустые поля, сломав логику вашего приложения.
  • Ввести вредоносный код, который выполнится на сервере.
  • Взломать базу данных через SQL-инъекции.

Валидация это процесс проверки данных на соответствие правилам. Ее нужно делать на стороне сервера, даже если вы проверяете данные через JavaScript на клиенте. Клиентскую валидацию можно обойти, отключив JS в браузере.

Основы валидации данных

1. Проверка на пустоту

Самый простой, но критически важный шаг. Используйте функции empty() и isset().

if (empty($_POST['username'])) {
    $errors[] = "Поле 'Имя пользователя' обязательно для заполнения.";
}

2. Фильтрация данных

Функция filter_var() помогает проверить email, URL, числа и другие типы данных.

$email = $_POST['email'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = "Некорректный email.";
}

3. Проверка через регулярные выражения

Для сложных правил, например, проверки пароля на надежность, используйте preg_match().

$password = $_POST['password'];
if (!preg_match("/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/", $password)) {
    $errors[] = "Пароль должен содержать минимум 8 символов, одну заглавную букву и цифру.";
}

Защита от SQL-инъекций

SQL-инъекция это внедрение вредоносного кода в SQL-запрос. Например, злоумышленник может ввести ' OR 1=1 -- в поле логина, чтобы обойти аутентификацию.

Как защититься?

1. Используйте подготовленные запросы (PDO или MySQLi)
Подготовленные запросы разделяют данные и SQL-код, предотвращая инъекции.

Пример с PDO:

$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
$stmt = $pdo->prepare("INSERT INTO users (username, email) VALUES (:username, :email)");
$stmt->execute([
    ':username' => $_POST['username'],
    ':email' => $_POST['email']
]);

Пример с MySQLi:

$mysqli = new mysqli("localhost", "user", "password", "test");
$stmt = $mysqli->prepare("INSERT INTO users (username, email) VALUES (?, ?)");
$stmt->bind_param("ss", $_POST['username'], $_POST['email']);
$stmt->execute();

2. Экранируйте специальные символы
Если по каким-то причинам подготовленные запросы недоступны, используйте mysqli_real_escape_string().

$username = mysqli_real_escape_string($mysqli, $_POST['username']);
$query = "SELECT * FROM users WHERE username = '$username'";

Практические примеры

Задача 1: Валидация формы регистрации

Создайте форму с полями:

  • Имя пользователя (обязательное, только буквы и цифры).
  • Email (обязательное, валидный формат).
  • Пароль (минимум 8 символов, заглавные и строчные буквы, цифра).

Пример обработки:

$errors = [];
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = trim($_POST['password']);

// Проверка имени
if (empty($username)) {
    $errors[] = "Введите имя пользователя.";
} elseif (!preg_match("/^[a-zA-Z0-9]+$/", $username)) {
    $errors[] = "Имя может содержать только буквы и цифры.";
}

// Проверка email
if (empty($email)) {
    $errors[] = "Введите email.";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = "Некорректный email.";
}

// Проверка пароля
if (empty($password)) {
    $errors[] = "Введите пароль.";
} elseif (!preg_match("/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/", $password)) {
    $errors[] = "Пароль слишком слабый.";
}

if (empty($errors)) {
    // Сохранение данных в БД через подготовленный запрос
    // ...
    echo "Регистрация успешна!";
} else {
    foreach ($errors as $error) {
        echo "<p>$error</p>";
    }
}

Задача 2: Защита от SQL-инъекций

Дана уязвимая форма входа:

$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($mysqli, $query);

Задание: Перепишите код с использованием подготовленных запросов.

Решение:

$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $_POST['username'], $_POST['password']);
$stmt->execute();
$result = $stmt->get_result();

Что запомнить из 17-го урока?

  • Всегда проверяйте данные на сервере.
  • Используйте подготовленные запросы для работы с БД.
  • Не доверяйте данным от пользователя, даже случайно они могут сломать ваше приложение.

Хотите узнать больше? Полный курс по PHP для начинающих. В нем 40 уроков теории, практики и практических примеров.

Уверен, теперь вы сможете создавать безопасные веб-приложения! Если остались вопросы, пишите в комментариях к уроку.