Создание формы регистрации на PHP: инструкции и код

Раздел: Веб-разработка на PHP -> Формы регистрации и авторизации

Основные принципы регистрации на PHP

Наиболее эффективное решение: регистрация с использованием PDO, password_hash и CSRF-защиты

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


<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $token = $_POST['csrf_token'] ?? '';
    if (!hash_equals($_SESSION['csrf_token'], $token)) {
        die('CSRF token validation failed');
    }
    $db = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
    $name = trim($_POST['name'] ?? '');
    $email = filter_var(trim($_POST['email'] ?? ''), FILTER_VALIDATE_EMAIL);
    $password = $_POST['password'] ?? '';
    $confirm = $_POST['confirm'] ?? '';
    if (!$email || strlen($name) < 2 || strlen($password) < 8 || $password !== $confirm) {
        die('Invalid input');
    }
    $stmt = $db->prepare('SELECT id FROM users WHERE email = ?');
    $stmt->execute([$email]);
    if ($stmt->fetch()) {
        die('Email already exists');
    }
    $hash = password_hash($password, PASSWORD_DEFAULT);
    $stmt = $db->prepare('INSERT INTO users (name, email, password) VALUES (?, ?, ?)');
    $stmt->execute([$name, $email, $hash]);
    echo 'Registration successful';
}
?>

форма регистрации на php (форма регистрации на php)

Пояснение: сессия хранит CSRF-токен, форма должна отправлять его скрытым полем. PDO с подготовленными выражениями предотвращает SQL-инъекции. Функция password_hash создаёт безопасный хеш. Проверка на существующий email исключает дубликаты.

Типичные ошибки и способы решения

  • Ошибка "Call to undefined function hash_equals" – функция доступна с PHP 5.6, для старых версий используйте сравнение через timing-safe функцию.
  • PDOException 'SQLSTATE[23000]' при дублировании email – обработайте через try-catch или проверку перед вставкой.
  • CSRF-токен не совпадает – убедитесь, что session_start() вызван до генерации токена, и токен передаётся в форме.

Как сделать регистрацию с подтверждением по email?

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


<?php
// после вставки пользователя в БД
$token = bin2hex(random_bytes(32));
$stmt = $db->prepare('UPDATE users SET verification_token = ?, verified = 0 WHERE email = ?');
$stmt->execute([$token, $email]);
$link = "https://example.com/verify?token=$token";
mail($email, 'Verify your email', "Click: $link");
?>

Пользователь переходит по ссылке, скрипт проверяет токен и устанавливает verified = 1.

Проблема: письма попадают в спам. Решение – настроить SPF/DKIM, использовать почтовый сервис вроде SendGrid. Ошибка: токен истекает – добавьте поле expires_at и проверяйте дату.

Как добавить капчу (reCAPTCHA) в форму регистрации?

Цель: защита от автоматических регистраций (ботов).


<?php
$recaptcha_secret = '6L...';
$response = $_POST['g-recaptcha-response'];
$verify = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$recaptcha_secret&response=$response");
$captcha_success = json_decode($verify);
if (!$captcha_success->success) {
    die('Captcha failed');
}
// продолжение регистрации
?>

В форме необходимо разместить тег

.

Ошибка: reCAPTCHA не отображается из-за отсутствия ключей – получите ключи на сайте Google. Если ключи не работают, проверьте домен и тип капчи (v2/v3).

Как реализовать регистрацию без базы данных (файловая система)?

Цель: прототип или очень маленький проект без MySQL. Данные хранятся в JSON-файле.


<?php
$users = json_decode(file_get_contents('users.json'), true) ?? [];
foreach ($users as $u) {
    if ($u['email'] === $email) {
        die('User exists');
    }
}
$users[] = [
    'name' => $name,
    'email' => $email,
    'password' => password_hash($password, PASSWORD_DEFAULT),
];
file_put_contents('users.json', json_encode($users, JSON_PRETTY_PRINT));
?>

Важно: при конкурентном доступе возможна потеря данных. Для продакшена не подходит.

Проблема: файл блокируется – используйте flock() или переходите на БД. Ошибка: пустой JSON после записи – проверьте права на запись в файл.

Как сделать регистрацию с проверкой сложности пароля?

Цель: требовать минимум одну заглавную букву, цифру и спецсимвол.


<?php
$password = $_POST['password'];
if (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z\d]).{8,}$/', $password)) {
    die('Password must contain uppercase, lowercase, digit and special character');
}
?>

Регулярное выражение проверяет все требования одновременно.

Ошибка: некорректное регулярное выражение – тестируйте на сервисах вроде regex101. Проблема: пользователи не могут придумать такой пароль – добавьте подсказку или кнопку генерации.

Дополнительные примеры с пояснениями

Пример 1: Регистрация с использованием хеширования bcrypt и солью (автоматически)

Пример

<?php
$password = 'User@123';
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
echo $hash;
// Результат: $2y$12$... (60 символов)
if (password_verify('User@123', $hash)) {
    echo 'Password verified';
}
?>
$2y$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36PQm4sEPhMNPfFhp3dI0eO
Password verified

Параметр cost увеличивает время хеширования, защищая от брутфорса. PASSWORD_DEFAULT автоматически выбирает алгоритм.

Пример 2: Регистрация с проверкой email через DNS (проверка существования домена)

Пример

<?php
$email = 'user@example.com';
$domain = substr(strrchr($email, '@'), 1);
if (checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A')) {
    echo 'Domain exists';
} else {
    echo 'Domain not found';
}
?>
Domain exists (если example.com настроен)

Эта проверка не гарантирует, что адрес реальный, но отсеивает несуществующие домены. Может замедлить регистрацию.

Пример 3: Регистрация с AJAX-валидацией (без перезагрузки страницы)

Пример

// JavaScript (jQuery)
jQuery('#reg-form').on('submit', function(e) {
    e.preventDefault();
    jQuery.ajax({
        url: 'register.php',
        method: 'POST',
        data: jQuery(this).serialize(),
        success: function(response) {
            if (response.success) {
                alert('Успешно');
            } else {
                alert('Ошибка: ' + response.message);
            }
        },
        error: function() { alert('Сетевая ошибка'); }
    });
});
Выводит alert с результатом от сервера.
Пример

// PHP: register.php (возвращает JSON)
header('Content-Type: application/json');
$errors = [];
if (empty($_POST['name'])) $errors[] = 'Name required';
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) $errors[] = 'Invalid email';
if (empty($errors)) {
    // ... регистрация
    echo json_encode(['success' => true]);
} else {
    echo json_encode(['success' => false, 'message' => implode(', ', $errors)]);
}

Пример 4: Регистрация с использованием готового класса (например, Laravel-style)

Пример

<?php
class Registration {
    private $db;
    public function __construct(PDO $db) { $this->db = $db; }
    public function register($name, $email, $password) {
        $stmt = $this->db->prepare('INSERT INTO users (name, email, password) VALUES (?, ?, ?)');
        return $stmt->execute([$name, $email, password_hash($password, PASSWORD_DEFAULT)]);
    }
}
$reg = new Registration($pdo);
$reg->register('John', 'john@example.com', 'secret123');
?>

Результат: запись в БД. Преимущество – инкапсуляция, легко тестировать.

Пример 5: Регистрация с генерацией случайного пароля и отправкой по email

Пример

<?php
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()';
$temp_password = substr(str_shuffle($chars), 0, 12);
// хешируем и сохраняем в БД
$hash = password_hash($temp_password, PASSWORD_DEFAULT);
// отправляем письмо с паролем
mail($email, 'Ваш временный пароль', "Пароль: $temp_password");
?>
Пользователь получает email с паролем, который нужно сменить после первого входа.

Пример 6: Регистрация с двухфакторной аутентификацией (2FA) через TOTP

Пример

<?php
// Используем библиотеку PHPGangsta/GoogleAuthenticator
require_once 'vendor/autoload.php';
$ga = new PHPGangsta_GoogleAuthenticator();
$secret = $ga->createSecret();
$qrCodeUrl = $ga->getQRCodeGoogleUrl('MyApp', $email, $secret);
// Сохраняем $secret в БД вместе с пользователем
// На странице подтверждения выводим $qrCodeUrl для сканирования
?>

После регистрации пользователь сканирует QR-код в приложении (Google Authenticator) и вводит одноразовый код для завершения регистрации.

Пример 7: Регистрация с ограничением частоты (rate limiting) через файл

Пример

<?php
$ip = $_SERVER['REMOTE_ADDR'];
$attempts = @file_get_contents("attempts_$ip.txt");
if ($attempts && (int)$attempts > 5) {
    die('Too many attempts. Try later.');
}
file_put_contents("attempts_$ip.txt", ((int)$attempts) + 1);
// после успешной регистрации удалите файл
?>

Пример 8: Регистрация с логированием всех попыток

Пример

<?php
$log = date('Y-m-d H:i:s') . ' | ' . $_SERVER['REMOTE_ADDR'] . ' | ' . ($email ?? '') . ' | ' . ($success ? 'SUCCESS' : 'FAILED') . "\n";
file_put_contents('registration.log', $log, FILE_APPEND);
?>
Содержимое registration.log:
2025-03-20 14:30:00 | 192.168.1.1 | test@test.com | FAILED
2025-03-20 14:31:00 | 192.168.1.1 | test@test.com | SUCCESS

Форма регистрации на PHP - comments

En
форма регистрации на php (php)