Система регистрации и входа на PHP и MySQL

Регистрация на чистом PHP сводится к семи файлам и одной таблице. В этой статье вы соберете форму регистрации, вход, защищенную страницу и выход. Пароли хранятся через password_hash(), запросы идут через PDO, а сессии и формы защищены от типовых атак. Код рассчитан на актуальный PHP 8, каждый файл приведен целиком.

Вадим Дворниковавтор материала

Что получится и что понадобится

Получится рабочий каркас авторизации. Пользователь регистрируется по email, логину и паролю, входит, видит закрытую страницу и выходит. Ошибки появляются прямо в форме.

Что получится и что понадобится

Для работы понадобятся:

  • PHP 8.2 или новее, лучше 8.4 или 8.5. На сегодня php.net ведет активную поддержку только веток 8.4 и 8.5, у 8.2 и 8.3 остаются лишь исправления безопасности;
  • MySQL 8 или MariaDB;
  • локальный сервер: XAMPP, OpenServer или Docker;
  • базовое знание HTML и PHP.

Сроки поддержки веток PHP меняются. По данным php.net, исправления безопасности для 8.2 заканчиваются 31 декабря 2026 года, для 8.3 – 31 декабря 2027 года, а активная поддержка 8.4 – 31 декабря 2026 года.

XAMPP несет в комплекте MariaDB, а не MySQL. Для кода из статьи это не важно: запросы одинаково работают в обеих СУБД. Версия PHP в сборках XAMPP, OpenServer и образах Docker разная, поэтому после установки выполните php -v и убедитесь, что там 8.2 или новее. Если версия ниже, выберите в сборке другой модуль PHP или образ.

Старые руководства строят такую систему на функциях mysql_connect() и mysql_query().

Не копируйте их.

Расширение mysql удалено из PHP еще в версии 7.0, и на современном сервере такой код просто не запустится. Здесь работает PDO.

Внешний вид форм в статье не разбираем: стили не относятся к теме. Подключите свой CSS в шапке страниц.

Структура проекта

В веб-корне лежит только то, что должен открывать браузер. Конфиг с паролем к базе и общий код живут выше, вне доступа по URL. Если сервер откажет и PHP не выполнится, пароль от базы не утечет открытым текстом.

project/
├── config/
│   └── config.php      данные подключения к базе
├── src/
│   ├── bootstrap.php   сессия, CSRF, вспомогательные функции
│   └── db.php          подключение PDO
└── public/             веб-корень сервера
    ├── register.php
    ├── login.php
    ├── dashboard.php
    └── logout.php

Всего семь файлов: три служебных и четыре страницы. Направьте DocumentRoot сервера (или встроенный сервер PHP) на папку public. Для проверки хватит команды php -S localhost:8000 -t public из папки project.

Не кладите config.php в веб-корень. Иначе при сбое обработчика PHP браузер получит файл как текст вместе с паролем от базы.

Таблица пользователей в MySQL

Создайте базу и таблицу. Выполните код в phpMyAdmin или в консоли mysql.

CREATE DATABASE app_auth CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE app_auth;

CREATE TABLE users (
    id            INT UNSIGNED NOT NULL AUTO_INCREMENT,
    email         VARCHAR(254) NOT NULL,
    username      VARCHAR(20)  NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    created_at    TIMESTAMP    NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uq_users_email (email),
    UNIQUE KEY uq_users_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Почему поле под хеш – VARCHAR(255)

Старые статьи делают поле на 32 символа, столько занимает md5-хеш. Хеш от password_hash() длиннее: сегодня это bcrypt на 60 символов. Документация PHP советует брать колонку, которая расширяется за 60 байт, и называет 255 хорошим выбором. Алгоритм по умолчанию может смениться, а с ним и длина.

Что дает UNIQUE и кодировка

Ограничения UNIQUE на email и логин остаются последним рубежом от дублей. Проверка в PHP может пропустить двух пользователей, которые регистрируются одновременно, а индекс базы не пропустит. Сравнение utf8mb4_unicode_ci не различает регистр, поэтому «Ivan» и «ivan» считаются одним логином. Движок InnoDB нужен из-за транзакций и надежности.

Заведите для приложения отдельного пользователя базы с правами только на эту базу. Учетную запись root в коде не используйте.

Подключение к базе через PDO

Файл config/config.php возвращает массив настроек. Подставьте свои значения.

<?php
// config/config.php
return [
    'host' => 'localhost',
    'name' => 'app_auth',
    'user' => 'app_user',
    'pass' => 'замените-на-свой-пароль',
];

Файл src/db.php открывает соединение один раз и отдает его всем.

<?php
// src/db.php
declare(strict_types=1);

function db(): PDO
{
    static $pdo = null;
    if ($pdo === null) {
        $c = require __DIR__ . '/../config/config.php';
        $dsn = "mysql:host={$c['host']};dbname={$c['name']};charset=utf8mb4";
        $pdo = new PDO($dsn, $c['user'], $c['pass'], [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false,
        ]);
    }
    return $pdo;
}

Три настройки здесь нужны по делу. charset=utf8mb4 в DSN согласует кодировку соединения с таблицей. ERRMODE_EXCEPTION превращает ошибки SQL в исключения, и вы их не пропустите. Отключенная эмуляция заставляет MySQL готовить запрос по-настоящему, поэтому данные никогда не смешиваются с SQL.

Общий файл для сессии, CSRF и вывода

Файл src/bootstrap.php подключается первой строкой каждой страницы. Он настраивает cookie сессии, запускает сессию и держит мелкие функции.

<?php
// src/bootstrap.php
declare(strict_types=1);

session_set_cookie_params([
    'lifetime' => 0,
    'path'     => '/',
    'secure'   => !empty($_SERVER['HTTPS']),
    'httponly' => true,
    'samesite' => 'Lax',
]);
session_start();

require __DIR__ . '/db.php';

// Экранирование при выводе в HTML
function e(string $s): string
{
    return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

function csrf_token(): string
{
    if (empty($_SESSION['csrf'])) {
        $_SESSION['csrf'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf'];
}

function csrf_check(mixed $token): bool
{
    return isset($_SESSION['csrf'])
        && is_string($token)
        && hash_equals($_SESSION['csrf'], $token);
}

function flash(string $message): void
{
    $_SESSION['flash'] = $message;
}

function take_flash(): ?string
{
    $m = $_SESSION['flash'] ?? null;
    unset($_SESSION['flash']);
    return $m;
}

function redirect(string $to): never
{
    header('Location: ' . $to);
    exit;
}

В файле стоит обратить внимание на четыре места:

  • session_start() вызывается до любого вывода. Если до нее браузер получил хоть байт, PHP не сможет отправить заголовки, а заодно cookie сессии;
  • httponly закрывает cookie от чтения из JavaScript, secure отправляет ее только по HTTPS, samesite не дает браузеру слать cookie с чужих сайтов при большинстве переходов. Массив параметров поддерживается с PHP 7.3;
  • hash_equals() сравнивает токены за постоянное время;
  • redirect() завершает скрипт через exit. Без него код после header() продолжит выполняться, и закрытая страница отдаст содержимое даже тем, кого вы перенаправили.

Шпаргалка OWASP по сессиям требует задать SameSite явно: Strict предпочтителен, Lax допустим. Оба значения соответствуют стандарту, поэтому Lax в bootstrap.php укладывается в рекомендацию. При Strict пользователь, пришедший по ссылке из письма, окажется без сессии. Если в кабинет не ходят по внешним ссылкам, например в панели администратора, ставьте Strict.

Форма и обработчик регистрации

Файл public/register.php показывает форму, проверяет данные на сервере и пишет пользователя в базу.

<?php
// public/register.php
declare(strict_types=1);
require __DIR__ . '/../src/bootstrap.php';

if (!empty($_SESSION['user_id'])) {
    redirect('dashboard.php');
}

$errors = [];
$old = ['email' => '', 'username' => ''];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!csrf_check($_POST['csrf'] ?? null)) {
        $errors[] = 'Форма устарела. Обновите страницу и повторите.';
    } else {
        $email    = trim((string) ($_POST['email'] ?? ''));
        $username = trim((string) ($_POST['username'] ?? ''));
        $password = (string) ($_POST['password'] ?? '');
        $old = ['email' => $email, 'username' => $username];

        if (!filter_var($email, FILTER_VALIDATE_EMAIL) || strlen($email) > 254) {
            $errors[] = 'Введите корректный email.';
        }
        if (!preg_match('/^[A-Za-z0-9_]{3,20}$/', $username)) {
            $errors[] = 'Логин: от 3 до 20 символов, латиница, цифры и «_».';
        }
        if (mb_strlen($password, 'UTF-8') < 8) {
            $errors[] = 'Пароль короче 8 символов.';
        }
        if (strlen($password) > 72) {
            $errors[] = 'Пароль длиннее 72 байт.';
        }

        if (!$errors) {
            $st = db()->prepare(
                'SELECT 1 FROM users WHERE email = :email OR username = :username LIMIT 1'
            );
            $st->execute(['email' => $email, 'username' => $username]);
            if ($st->fetch()) {
                $errors[] = 'Такой email или логин уже занят.';
            }
        }

        if (!$errors) {
            try {
                $st = db()->prepare(
                    'INSERT INTO users (email, username, password_hash)
                     VALUES (:email, :username, :hash)'
                );
                $st->execute([
                    'email'    => $email,
                    'username' => $username,
                    'hash'     => password_hash($password, PASSWORD_DEFAULT),
                ]);
                flash('Аккаунт создан. Теперь войдите.');
                redirect('login.php');
            } catch (PDOException $ex) {
                // 1062 – нарушение UNIQUE: параллельный запрос успел раньше
                if (($ex->errorInfo[1] ?? 0) === 1062) {
                    $errors[] = 'Такой email или логин уже занят.';
                } else {
                    throw $ex;
                }
            }
        }
    }
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Регистрация</title>
</head>
<body>
    <h1>Регистрация</h1>
    <?php foreach ($errors as $err): ?>
        <p class="error"><?= e($err) ?></p>
    <?php endforeach; ?>
    <form method="post" action="register.php">
        <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
        <p><label>Email<br>
            <input type="email" name="email" value="<?= e($old['email']) ?>" required></label></p>
        <p><label>Логин<br>
            <input type="text" name="username" value="<?= e($old['username']) ?>" required></label></p>
        <p><label>Пароль<br>
            <input type="password" name="password" required></label></p>
        <p><button type="submit">Зарегистрироваться</button></p>
    </form>
    <p>Уже есть аккаунт? <a href="login.php">Войти</a></p>
</body>
</html>

Как работает валидация

Браузерные атрибуты вроде required и type="email" помогают пользователю, но защиты не дают: запрос можно отправить и без формы. Поэтому сервер проверяет все сам.

Email проверяет filter_var() с флагом FILTER_VALIDATE_EMAIL. Логин ограничен регулярным выражением: только латиница, цифры и подчеркивание. Пароль проверяется по длине.

Нижняя граница считается в символах через mb_strlen(), чтобы сообщение об ошибке совпадало с проверкой. Функция входит в расширение mbstring, которое включено в большинстве сборок PHP.

Верхний предел в 72 байта связан с bcrypt: OWASP пишет, что у большинства реализаций bcrypt максимальная длина входа – 72 байта, и советует ограничить длину пароля. Здесь нужен именно счет байтов, поэтому для верхней границы подходит strlen(), в том числе для кириллицы.

Пароль и Post/Redirect/Get

Функция password_hash() с PASSWORD_DEFAULT сама подмешивает соль и выбирает алгоритм, сейчас это bcrypt. Сравнивать хеши вручную не нужно, для этого есть password_verify().

MD5, SHA-1 и пароль открытым текстом недопустимы: первые два считаются слишком быстро, и подбор идет миллиардами попыток в секунду.

После успешной записи скрипт перенаправляет на login.php и не выводит страницу сам. Этот прием называется Post/Redirect/Get. Если пользователь обновит страницу входа, браузер не пошлет форму регистрации повторно. При ошибках PRG не нужен: форма показывается сразу вместе с сообщениями и введенными значениями, кроме пароля.

Форма и обработчик входа

Файл public/login.php принимает логин или email и пароль.

<?php
// public/login.php
declare(strict_types=1);
require __DIR__ . '/../src/bootstrap.php';

if (!empty($_SESSION['user_id'])) {
    redirect('dashboard.php');
}

$error = null;
$notice = take_flash();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!csrf_check($_POST['csrf'] ?? null)) {
        $error = 'Форма устарела. Обновите страницу и повторите.';
    } else {
        $login    = trim((string) ($_POST['login'] ?? ''));
        $password = (string) ($_POST['password'] ?? '');

        $st = db()->prepare(
            'SELECT id, username, password_hash FROM users
             WHERE username = :username OR email = :email LIMIT 1'
        );
        $st->execute(['username' => $login, 'email' => $login]);
        $user = $st->fetch();

        if ($user && password_verify($password, $user['password_hash'])) {
            // Новый идентификатор сессии, старый удаляется
            session_regenerate_id(true);
            $_SESSION['user_id']  = (int) $user['id'];
            $_SESSION['username'] = $user['username'];

            // Алгоритм по умолчанию мог смениться – обновим хеш
            if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT)) {
                $up = db()->prepare('UPDATE users SET password_hash = :hash WHERE id = :id');
                $up->execute([
                    'hash' => password_hash($password, PASSWORD_DEFAULT),
                    'id'   => $user['id'],
                ]);
            }
            redirect('dashboard.php');
        }
        // Одно сообщение на все случаи
        $error = 'Неверный логин или пароль.';
    }
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Вход</title>
</head>
<body>
    <h1>Вход</h1>
    <?php if ($notice): ?><p><?= e($notice) ?></p><?php endif; ?>
    <?php if ($error): ?><p class="error"><?= e($error) ?></p><?php endif; ?>
    <form method="post" action="login.php">
        <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
        <p><label>Логин или email<br>
            <input type="text" name="login" required></label></p>
        <p><label>Пароль<br>
            <input type="password" name="password" required></label></p>
        <p><button type="submit">Войти</button></p>
    </form>
    <p>Нет аккаунта? <a href="register.php">Зарегистрироваться</a></p>
</body>
</html>

Почему сообщение одно

Фраза «Пользователь не найден» подсказывает атакующему, какие логины существуют. Фраза «Неверный пароль» подтверждает, что логин верный. Отвечайте одинаково в обоих случаях и не раскрывайте, что именно не подошло.

Смена идентификатора и обновление хеша

После входа вызывайте session_regenerate_id(true). OWASP требует обновлять идентификатор после любого изменения уровня привилегий, а вход именно его меняет. Так злоумышленник, подсунувший пользователю известный ему идентификатор, остается ни с чем. Параметр true удаляет старую сессию.

Вызов password_needs_rehash() сравнивает параметры старого хеша с текущими. Если PHP сменил алгоритм по умолчанию или вы подняли стоимость, хеш обновится при следующем входе, ведь именно тогда пароль у вас есть в открытом виде.

Защищенная страница и выход

Файл public/dashboard.php пускает только вошедших.

<?php
// public/dashboard.php
declare(strict_types=1);
require __DIR__ . '/../src/bootstrap.php';

if (empty($_SESSION['user_id'])) {
    redirect('login.php');
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Личный кабинет</title>
</head>
<body>
    <h1>Добро пожаловать, <?= e($_SESSION['username']) ?>!</h1>
    <form method="post" action="logout.php">
        <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
        <button type="submit">Выйти</button>
    </form>
</body>
</html>

Проверку входа копируйте в начало каждой закрытой страницы. Когда страниц станет много, вынесите ее в функцию require_login() в bootstrap.php.

Файл public/logout.php завершает сессию полностью.

<?php
// public/logout.php
declare(strict_types=1);
require __DIR__ . '/../src/bootstrap.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_check($_POST['csrf'] ?? null)) {
    $_SESSION = [];

    if (ini_get('session.use_cookies')) {
        $p = session_get_cookie_params();
        setcookie(session_name(), '', [
            'expires'  => time() - 42000,
            'path'     => $p['path'],
            'domain'   => $p['domain'],
            'secure'   => $p['secure'],
            'httponly' => $p['httponly'],
            'samesite' => $p['samesite'],
        ]);
    }
    session_destroy();
}
redirect('login.php');

Одного session_destroy() мало.

Он удаляет данные на сервере, но массив $_SESSION остается в памяти до конца скрипта, а cookie остается в браузере. Обнулите массив, попросите браузер удалить cookie и только потом уничтожайте сессию.

Выход принимает только POST с токеном. Будь это обычная ссылка, любая чужая страница могла бы вставить картинку с адресом logout.php и выбросить пользователя из системы.

Что обязательно для безопасности

Подготовленные выражения против SQL-инъекции

Старый код склеивал SQL из введенных данных: "... WHERE username='" . $_POST['username'] . "'". Если пользователь введет ' OR '1'='1, условие станет истинным, и запрос вернет первую строку таблицы.

Вход без пароля готов.

Подготовленное выражение отправляет базе шаблон и значения отдельно. Значение остается значением, что бы в нем ни лежало. Код статьи использует его во всех запросах.

Почему htmlspecialchars не спасает от инъекции

Функция htmlspecialchars() работает с HTML: она заменяет символы < > & и кавычки. В SQL важны иные символы, например обратная косая черта, и обход зависит от контекста и параметров. Считайте эту функцию инструментом для вывода, а для базы берите только параметры запроса.

Когда экранировать данные

В базу пишется исходное значение. Экранирование делается при выводе через функцию e(). Тогда одни и те же данные безопасно попадают и в HTML, и в JSON, и в письмо. Если экранировать при записи, в базе окажутся куски &amp;, а поиск и сравнение сломаются.

С PHP 8.1 флаги htmlspecialchars по умолчанию включают ENT_QUOTES, то есть одинарные кавычки тоже экранируются. Флаги все равно лучше задавать явно, тогда код не зависит от версии.

CSRF-токен

Атака CSRF заставляет браузер вошедшего пользователя отправить запрос на ваш сайт со страницы злоумышленника. Cookie сессии уйдет вместе с запросом. От этого защищает случайный токен, который лежит в сессии и в скрытом поле формы.

Чужая страница токена не знает.

Каждый обработчик формы в статье сверяет его через csrf_check(). Шпаргалка OWASP по CSRF описывает такую схему: токен генерируется на сервере и сверяется с токеном сессии.

Боевой сервер: HTTPS и cookie

Флаги cookie вы уже выставили в bootstrap.php, но на боевом сайте они работают только вместе с HTTPS. Подключите сертификат до запуска.

Не отключайте флаг secure на боевом сервере. Без него браузер отправит cookie сессии и по незащищенному HTTP, а перехваченную сессию используют как логин.

Пароль и ограничение попыток

Шпаргалка OWASP по хранению паролей ставит на первое место Argon2id. Bcrypt она оставляет для устаревших систем, где недоступны ни Argon2, ни scrypt, и советует стоимость не ниже 10. Для начала PASSWORD_DEFAULT хватает, но знайте об этом выборе. В PHP есть и PASSWORD_ARGON2ID, если ваша сборка его поддерживает.

Ограничения числа попыток входа в коде статьи нет. Без него пароль можно подбирать без остановки. Добавьте счетчик неудачных попыток по логину и IP с временной блокировкой или растущей задержкой.

Частые ошибки и как их отладить

Включите показ ошибок на локальной машине: display_errors=On и error_reporting=E_ALL в php.ini. На боевом сервере выключите вывод и пишите ошибки в журнал. Тогда текст исключения PDO не увидит посторонний.

СимптомПричинаЧто делать
Headers already sentВывод до header() или session_start(): пробел или BOM перед <?phpУберите лишнее до открывающего тега, сохраняйте файлы как UTF-8 без BOM
Вход проходит, но страница снова просит войтиCookie сессии не сохраняется: флаг secure на HTTPПроверьте условие с $_SERVER['HTTPS'] и откройте сайт по тому протоколу, что настроен
Access denied for userНеверные данные в config.php или у пользователя нет правПроверьте логин, пароль и GRANT на базу
Table 'app_auth.users' doesn't existТаблица не создана или выбрана другая базаВыполните SQL из раздела про таблицу
Вместо кириллицы «????»Разные кодировки страницы, соединения и таблицыutf8mb4 в DSN и таблице, charset="utf-8" в HTML
Форма устарела при каждой отправкеsession_start() не вызывается или cookie не доходитПодключайте bootstrap.php первой строкой

Если неясно, что вернул запрос, временно выведите результат через var_dump(). Не оставляйте такой вывод в готовом коде.

Что добавить дальше

Каркас закрывает основу. Для реального сайта добавьте четыре вещи:

  • Подтверждение email. Храните флаг подтверждения и случайный одноразовый токен со сроком жизни, пускайте в кабинет только подтвержденных;
  • Сброс пароля. Отправляйте на почту одноразовую ссылку. В базе храните хеш токена, а не сам токен, и после смены пароля закрывайте все сессии;
  • «Запомнить меня». Заведите отдельный долгоживущий токен в отдельной таблице. Срок жизни самой сессии при этом остается прежним;
  • Ограничение попыток входа. Счетчик неудачных попыток по логину и IP с блокировкой на время.

Если проект растет, переходите на фреймворк: Laravel, Symfony и другие уже содержат готовую и проверенную авторизацию. Собирать ее самому стоит ради понимания или для очень маленьких задач.

Запустите сначала семь файлов из статьи как есть, затем вносите изменения по одному и проверяйте вход после каждого.

Комментарии

Оставьте свой комментарий
S
SEOgun

пришлось покапать чтобы заработало, вот моя редакция кода:
обработчик register.php
if(isset($_POST["register"])){
if(!empty($_POST['full_name']) && !empty($_POST['email']) && !empty($_POST['username']) && !empty($_POST['password'])) {
$full_name= htmlspecialchars($_POST['full_name']);
$email=htmlspecialchars($_POST['email']);
$username=htmlspecialchars($_POST['username']);
$password=htmlspecialchars($_POST['password']);
$query=mysql_query("SELECT * FROM user WHEREusername='".$username."'");
$numrows=mysql_num_rows($query);
if($numrows==0)
{
$sql="INSERT INTO user
(full_name, email, username,password)
VALUES('".$full_name."','".$email."', '".$username."', '".$password."')";
$result=mysql_query($sql);
if($result){
$message = "Account Successfully Created";
}
else {
$message = "Failed to insert data information! SQL query:".$sql;

}
}
else {
$message = "That username already exists! Please try another one!";
}
}
else {
$message = "All fields are required!";
}
}
?>

<?php if (!empty($message)) {echo "<p class='error'>" . "MESSAGE: ". $message . "</p>";} ?>

обработчик login.php
<?php
session_start();
if(isset($_SESSION["session_username"])){
header("location:index.php");
}

?>

<?php
require_once("includes/bd.php");
?>
<?php
if(isset($_POST["login"])){
if(empty($_POST['username']) or empty($_POST['password'])) {
echo "All fields are required!";
}
else {
$username=htmlspecialchars($_POST['username']);
$password=htmlspecialchars($_POST['password']);
$query =mysql_query("SELECT * FROM user WHERE username='".$username."' AND password='".$password."'");
$numrows=mysql_num_rows($query);
if($numrows!=0)
{
$_SESSION['session_username']=$username;
/* Перенаправление браузера */
if(isset($_SESSION["session_username"])){
echo '<meta http-equiv="refresh" content="0;URL=/index.php">';

}
else {
echo "Invalid username or password!";
}
}
}
}
?>

И
Иван

md5 шифрование так и не нашел в коде 🙁

ЕК
Евгений К.

Как добавить $hashed_password

BS
Bastiras S.

Объясните новичку, как работает система донатов на сайте, как её создать и подключить к базе данных, и как менять цену на игровую валюту, буду очень благодарен!

GG
Gollum G.

скрипты полностью рабочие до версии php 5.5
а улучшить напиши функцию для удаление нежелательных тегов типа <??> и <a></a> и экранирование если проскочили для начала
для поля user_login
и пару проверок смысл пихать полностью голый код народ приходит правит в итоге проЁ пароли от мыл и на главной странице (_!_) если комедию русскою смотрел по хоттабыча то в курсе и писать надо что какая функция делает а не пихать от болды if($numrows==0) //проверяем равна она нулю или нет если не равна идем дальше если равна значит пустая выводим ошибку

GG
Gollum G.

где есть подключение к бд или работа с бд надо добавить букву i
например
mysql_query устаревшая
новая mysqli_query
читаем тут https://www.php.net/manual/ru/
валидатор https://phpcodechecker.com

NA
Nurtore A.

Объясните пожалуйста шаг 4. Зачем заменять на header.php? А в footer.php только копирайт.

ДЛ
Дима Л.

пожауйста скиньте исходник. не могу разобраться с кодом!

A
anon

В коде несколько ошибок. Так что тупое копирование- не поможет
1. Прошло несколько лет, поэтому у некоторых выйдет ошибка про mysql.
решение: меняйте в файлах mysql_.... на mysqli_
2. Синтаксические ошибки: в файлах login.php и register.php написан код, вот кусок "WHEREusername="
решение: поставьте пробел после WHERE
3. В файле register.php , в последней строке нет экранирования.
решение: вместо class="error" пишите class="error"
4. У некоторых отключена регистрация пользователя root в базу mysql.
Решение: создать пользователя и пароль для работы с базой и указать его в файле constants.php, заодно поменять содержимое на такое:
<?php
$host = "localhost";
$username = "my_user";
$password = "my_password";
$db_name = "userlistdb";
?>
и поменять содержимое файла includes/connection.php на такое (в коде я уже поменял mysql_... на mysqli_ .... имейте это ввиду и поправьте если что):
<?php
require("constants.php");
$link = mysqli_connect("$host", "$username", "$password")or die("cannot connect server ");
mysqli_select_db($link,"$db_name")or die("cannot select DB");
?>
5. У меня не происходило коннекта с базой данных, поэтому выходила ошибка.
Для теста явно указал данные для входа в mysql и все заработало. Надо подправить как включить файл connection.php в файлы.
Тестовое решение, в файле login.php перед $query прописать так:
$n1=mysqli_connect("localhost","my_user","my_password","userlistdb");
$query =mysqli_query($n1, "SELECT * FROM usertbl WHERE username='".$username."' AND password='".$password."'");
А в файле register:
также перед $query добавить строчку
$n1=mysqli_connect("localhost","my_user","my_password","userlistdb");
и далее, поправить на следующий код:
$numrows=mysqli_num_rows($n1,$query);
$result=mysqli_query($n1, $sql);

И только после этого всё заработало, как автор писал в статье:

Актуальность информации на 29.09.2018) Linux. Если нужна помощь, то пишите на почту infodr@ya.ru

Дарья К.
➞ anon

Помогите. При авторизации пишет, что не правильный логин или пароль, хотя все как в бд.

А
айнур

хорошая статья. четко и грамотно

Загрузить еще