Система регистрации и входа на PHP и MySQL
Регистрация на чистом PHP сводится к семи файлам и одной таблице. В этой статье вы соберете форму регистрации, вход, защищенную страницу и выход. Пароли хранятся через password_hash(), запросы идут через PDO, а сессии и формы защищены от типовых атак. Код рассчитан на актуальный PHP 8, каждый файл приведен целиком.
- Что получится и что понадобится
- Структура проекта
- Таблица пользователей в MySQL
- Подключение к базе через PDO
- Общий файл для сессии, CSRF и вывода
- Форма и обработчик регистрации
- Форма и обработчик входа
- Защищенная страница и выход
- Что обязательно для безопасности
- Частые ошибки и как их отладить
- Что добавить дальше
Что получится и что понадобится
Получится рабочий каркас авторизации. Пользователь регистрируется по 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, и в письмо. Если экранировать при записи, в базе окажутся куски &, а поиск и сравнение сломаются.
С 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 и другие уже содержат готовую и проверенную авторизацию. Собирать ее самому стоит ради понимания или для очень маленьких задач.
Запустите сначала семь файлов из статьи как есть, затем вносите изменения по одному и проверяйте вход после каждого.
Комментарии
пришлось покапать чтобы заработало, вот моя редакция кода:
обработчик 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
Объясните новичку, как работает система донатов на сайте, как её создать и подключить к базе данных, и как менять цену на игровую валюту, буду очень благодарен!
скрипты полностью рабочие до версии php 5.5
а улучшить напиши функцию для удаление нежелательных тегов типа <??> и <a></a> и экранирование если проскочили для начала
для поля user_login
и пару проверок смысл пихать полностью голый код народ приходит правит в итоге проЁ пароли от мыл и на главной странице (_!_) если комедию русскою смотрел по хоттабыча то в курсе и писать надо что какая функция делает а не пихать от болды if($numrows==0) //проверяем равна она нулю или нет если не равна идем дальше если равна значит пустая выводим ошибку
где есть подключение к бд или работа с бд надо добавить букву i
например
mysql_query устаревшая
новая mysqli_query
читаем тут https://www.php.net/manual/ru/
валидатор https://phpcodechecker.com
Объясните пожалуйста шаг 4. Зачем заменять на header.php? А в footer.php только копирайт.
пожауйста скиньте исходник. не могу разобраться с кодом!
В коде несколько ошибок. Так что тупое копирование- не поможет
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
Помогите. При авторизации пишет, что не правильный логин или пароль, хотя все как в бд.
хорошая статья. четко и грамотно