Регистрация в 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 отклоняет ботов.