Регистрация в PHP: пошаговая инструкция с примерами

Раздел: Веб-разработка на PHP -> Регистрация и вход пользователей

Основное решение: регистрация с подготовленными запросами PDO и password_hash

Безопасная регистрация пользователя начинается с правильного хеширования пароля и использования подготовленных запросов для предотвращения SQL-инъекций.

Создадим таблицу users в MySQL:

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(50) UNIQUE NOT NULL,
  email VARCHAR(100) UNIQUE NOT NULL,
  password_hash VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Register user php (регистрация пользователя в php)

Форма регистрации (register_form.html):

<form method="post" action="register.php">
  <input type="text" name="username" required placeholder="Имя пользователя">
  <input type="email" name="email" required placeholder="Email">
  <input type="password" name="password" required placeholder="Пароль">
  <input type="submit" value="Зарегистрироваться">
</form>

Обработчик register.php:

<?php
require_once 'config.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = trim($_POST['username']);
    $email = trim($_POST['email']);
    $password = $_POST['password'];
    
    // Валидация
    if (empty($username) || empty($email) || empty($password)) {
        die('Заполните все поля');
    }
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        die('Некорректный email');
    }
    if (strlen($password) < 6) {
        die('Пароль должен быть не менее 6 символов');
    }
    
    // Хеширование пароля
    $password_hash = password_hash($password, PASSWORD_DEFAULT);
    
    // Подключение к БД
    try {
        $pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        // Проверка на существующего пользователя
        $stmt = $pdo->prepare('SELECT id FROM users WHERE username = :username OR email = :email');
        $stmt->execute([':username' => $username, ':email' => $email]);
        if ($stmt->fetch()) {
            die('Пользователь с таким именем или email уже существует');
        }
        
        // Вставка нового пользователя
        $stmt = $pdo->prepare('INSERT INTO users (username, email, password_hash) VALUES (:username, :email, :password_hash)');
        $stmt->execute([':username' => $username, ':email' => $email, ':password_hash' => $password_hash]);
        
        // Перенаправление на страницу успеха
        header('Location: success.php');
        exit;
    } catch (PDOException $e) {
        die('Ошибка базы данных: ' . $e->getMessage());
    }
}
?>

В файле config.php размещаются параметры подключения.

Этот код обеспечивает базовую безопасность: пароль хешируется, запросы подготовлены, данные фильтруются.

Как реализовать регистрацию с использованием MySQLi вместо PDO?

MySQLi также поддерживает подготовленные запросы. Пример аналогичного обработчика:

<?php
$mysqli = new mysqli('localhost', 'root', '', 'test');
if ($mysqli->connect_error) {
    die('Ошибка подключения: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)');
$stmt->bind_param('sss', $username, $email, $password_hash);
$stmt->execute();
?>

Отличие в синтаксисе привязки параметров.

Как добавить подтверждение email?

Для подтверждения email нужно добавить поле verification_token и verified_at. После регистрации генерируется токен и отправляется письмо с ссылкой. При переходе по ссылке токен проверяется и пользователь активируется.

// Генерация токена
$token = bin2hex(random_bytes(16));
// Сохранение в БД
$stmt = $pdo->prepare('INSERT INTO users (..., verification_token) VALUES (..., :token)');
// Отправка письма
$link = 'http://example.com/verify.php?token=' . $token;
mail($email, 'Подтверждение регистрации', 'Перейдите по ссылке: ' . $link);

verify.php:

<?php
$token = $_GET['token'] ?? '';
$stmt = $pdo->prepare('UPDATE users SET verified_at = NOW(), verification_token = NULL WHERE verification_token = :token');
$stmt->execute([':token' => $token]);
if ($stmt->rowCount()) {
    echo 'Email подтвержден';
} else {
    echo 'Неверный токен';
}
?>

Как защитить форму от CSRF-атак?

CSRF-токены предотвращают подделку межсайтовых запросов. При загрузке формы генерируется случайный токен и сохраняется в сессии. При отправке формы токен проверяется.

// На странице формы
session_start();
$csrf_token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $csrf_token;
// В форме: <input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">

// В обработчике
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die('Ошибка CSRF');
}
unset($_SESSION['csrf_token']); // после проверки удалить

Типичные ошибки

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

Расширенные примеры регистрации пользователя

Полный файл register.php с расширенной валидацией и обработкой ошибок.

Пример
<?php
session_start();
require_once 'config.php';

$errors = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = trim($_POST['username'] ?? '');
    $email = trim($_POST['email'] ?? '');
    $password = $_POST['password'] ?? '';
    $confirm_password = $_POST['confirm_password'] ?? '';
    $csrf_token = $_POST['csrf_token'] ?? '';
    
    // CSRF проверка
    if (!isset($_SESSION['csrf_token']) || $csrf_token !== $_SESSION['csrf_token']) {
        $errors[] = 'Ошибка безопасности. Попробуйте снова.';
    }
    unset($_SESSION['csrf_token']);
    
    // Валидация username
    if (empty($username)) {
        $errors[] = 'Имя пользователя обязательно.';
    } elseif (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
        $errors[] = 'Имя пользователя должно содержать от 3 до 20 символов (буквы, цифры, подчеркивание).';
    }
    
    // Валидация email
    if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors[] = 'Введите корректный email.';
    }
    
    // Валидация пароля
    if (strlen($password) < 8) {
        $errors[] = 'Пароль должен быть не менее 8 символов.';
    }
    if ($password !== $confirm_password) {
        $errors[] = 'Пароли не совпадают.';
    }
    
    // Если ошибок нет, работаем с БД
    if (empty($errors)) {
        try {
            $pdo = getPDO(); // функция из config.php
            
            // Проверка существующего пользователя
            $stmt = $pdo->prepare('SELECT id FROM users WHERE username = :username OR email = :email');
            $stmt->execute([':username' => $username, ':email' => $email]);
            if ($stmt->fetch()) {
                $errors[] = 'Пользователь с таким именем или email уже зарегистрирован.';
            } else {
                // Хеширование пароля
                $password_hash = password_hash($password, PASSWORD_ARGON2ID); // используем Argon2id
                
                // Генерация токена подтверждения email
                $verification_token = bin2hex(random_bytes(32));
                
                // Вставка пользователя
                $stmt = $pdo->prepare('INSERT INTO users (username, email, password_hash, verification_token) VALUES (:username, :email, :password_hash, :verification_token)');
                $stmt->execute([
                    ':username' => $username,
                    ':email' => $email,
                    ':password_hash' => $password_hash,
                    ':verification_token' => $verification_token
                ]);
                
                // Отправка письма с подтверждением (пример с PHPMailer)
                // require_once 'PHPMailer/PHPMailer.php';
                // ... настройка и отправка
                
                $_SESSION['success_message'] = 'Регистрация прошла успешно. Проверьте email для подтверждения.';
                header('Location: login.php');
                exit;
            }
        } catch (PDOException $e) {
            // Логирование ошибки в файл
            error_log('Registration error: ' . $e->getMessage());
            $errors[] = 'Ошибка сервера. Попробуйте позже.';
        }
    }
    
    // Сохраняем ошибки в сессии для отображения на форме
    $_SESSION['errors'] = $errors;
    header('Location: register.php');
    exit;
}

// Вывод формы с ошибками
$errors = $_SESSION['errors'] ?? [];
unset($_SESSION['errors']);
?>
<!DOCTYPE html>
<html>
<head><title>Регистрация</title></head>
<body>
  <?php if (!empty($errors)): ?>
    <div class="errors">
      <ul><?php foreach ($errors as $error): ?><li><?= htmlspecialchars($error) ?></li><?php endforeach; ?></ul>
    </div>
  <?php endif; ?>
  <form method="post">
    <?php $csrf = bin2hex(random_bytes(32)); $_SESSION['csrf_token'] = $csrf; ?>
    <input type="hidden" name="csrf_token" value="<?= $csrf ?>">
    <input type="text" name="username" placeholder="Имя пользователя" value="<?= htmlspecialchars($_POST['username'] ?? '') ?>"><br>
    <input type="email" name="email" placeholder="Email" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>"><br>
    <input type="password" name="password" placeholder="Пароль"><br>
    <input type="password" name="confirm_password" placeholder="Подтвердите пароль"><br>
    <input type="submit" value="Зарегистрироваться">
  </form>
</body>
</html>

Пример вывода (при ошибке):

Ошибки:
- Пароль должен быть не менее 8 символов.
- Пароли не совпадают.

Пример вывода (успех): перенаправление на login.php с сообщение в сессии.

Также можно добавить проверку сложности пароля: наличие заглавных, строчных букв, цифр, спецсимволов.

Пример
if (!preg_match('/[A-Z]/', $password) || !preg_match('/[a-z]/', $password) || !preg_match('/[0-9]/', $password)) {
    $errors[] = 'Пароль должен содержать заглавные, строчные буквы и цифры.';
}

Регистрация с использованием парольных политик и капчи (Google reCAPTCHA):

Пример
// После проверки полей
$recaptcha_response = $_POST['g-recaptcha-response'];
$secret = 'your_secret_key';
$verify = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$recaptcha_response}");
$captcha_success = json_decode($verify);
if (!$captcha_success->success) {
    $errors[] = 'Пожалуйста, пройдите проверку reCAPTCHA.';
}

Результат: форма с reCAPTCHA отклоняет ботов.

Регистрация пользователя в PHP - comments

En
Register user php (php)