В этой статье Вы найдете скрипт на языке программирования PHP, который позволяет пользователю зарегистрироваться и авторизоваться на сайте. Скрипт на 100% защищает от SQL-инжекций, поскольку использует PDO (система подготовленных запросов) и библиотеку RedBeanPHP, которая реализует ORM. Использовать RedBeanPHP мы будем только, чтобы присоединиться к базе данных и легко ей манипулировать, не используя стандартные команды в PHP, такие как mysql_connect и подобные, потому что они устаревшие и не очень эффективные.
Скрипт использует сессии ($_SESSION) и позволяет узнать авторизован сейчас человек или нет. Также в скрипте предусмотрена капча с рандомными вопросами, которая защищает сайт от надоедливого спама.
Скрипт состоит из следующих файлов:
Скачайте готовый скрипт и перенесите все файлы на свой хостинг или локальный сервер (Denwer, OpenServer). Для работы скрипта Вам потребуется версия PHP не ниже 5.6. Далее необходимо создать базу данных и подсоединиться к ней. Для этого потребуется поменять значения в файле db.php. Если с этим возникнут трудности, то Вы можете задавать свои вопросы в комментариях под статьей.
В файле login.php находится обработчик и сама форма авторизации, которая состоит из двух полей (логин, пароль). Значок @ (собачка) перед переменными служит в PHP для отключения ошибки, если такая возникнет.
Все переменные, которые возвращаются по методу POST - мы присваиваем переменной $data.
$data = $_POST; if ( isset($data['do_login']) ) { $user = R::findOne('users', 'login = ?', array($data['login'])); if ( $user ) { //логин существует if ( password_verify($data['password'], $user->password) ) { //если пароль совпадает, то нужно авторизовать пользователя $_SESSION['logged_user'] = $user; echo 'Вы авторизованы!
Можете перейти на главную страницу.
'; }else { $errors[] = 'Неверно введен пароль!'; } }else { $errors[] = 'Пользователь с таким логином не найден!'; } if ( ! empty($errors) ) { //выводим ошибки авторизации echo '' .array_shift($errors). '
'; } }
В файле signup.php находится обработчик и сама форма регистрации. Для таких форм рекомендуется использовать метод запроса POST, при котором веб-сервер принимает данные, заключённые в тело сообщения, для хранения.
$data = $_POST; function captcha_show(){ $questions = array( 1 => 'Столица России', 2 => 'Столица США', 3 => '2 + 3', 4 => '15 + 14', 5 => '45 - 10', 6 => '33 - 3' ); $num = mt_rand( 1, count($questions) ); $_SESSION['captcha'] = $num; echo $questions[$num]; } //если кликнули на button if ( isset($data['do_signup']) ) { // проверка формы на пустоту полей $errors = array(); if ( trim($data['login']) == '' ) { $errors[] = 'Введите логин'; } if ( trim($data['email']) == '' ) { $errors[] = 'Введите Email'; } if ( $data['password'] == '' ) { $errors[] = 'Введите пароль'; } if ( $data['password_2'] != $data['password'] ) { $errors[] = 'Повторный пароль введен не верно!'; } //проверка на существование одинакового логина if ( R::count('users', "login = ?", array($data['login'])) > 0) { $errors[] = 'Пользователь с таким логином уже существует!'; } //проверка на существование одинакового email if ( R::count('users', "email = ?", array($data['email'])) > 0) { $errors[] = 'Пользователь с таким Email уже существует!'; } //проверка капчи $answers = array( 1 => 'москва', 2 => 'вашингтон', 3 => '5', 4 => '29', 5 => '35', 6 => '30' ); if ( $_SESSION['captcha'] != array_search( mb_strtolower($_POST['captcha']), $answers ) ) { $errors[] = 'Ответ на вопрос указан не верно!'; } if ( empty($errors) ) { //ошибок нет, теперь регистрируем $user = R::dispense('users'); $user->login = $data['login']; $user->email = $data['email']; $user->password = password_hash($data['password'], PASSWORD_DEFAULT); //пароль нельзя хранить в открытом виде, //мы его шифруем при помощи функции password_hash для php > 5.6 R::store($user); echo 'Вы успешно зарегистрированы!
'; }else { echo '' .array_shift($errors). '
'; } }
Статья была написана на основе видеоурока Хауди Хо, который Вы можете посмотреть ниже. Скрипт из видео был немного доработан (добавлена капча function captcha_show).
Уже понял. Содержание страницы надо расположить между <?php if… и <?php else: ?>
<strong><!--?php captcha_show(); ?--></strong> <input type="text" name="captcha">
— ошибка в описании статьи: комментарии здесь не нужны2)
$errors[] = 'Ответ на вопрос указан не верно!'; var_dump($answers);
— опять же непонятно для чего тут в статье и в файле нуженvar_dump($answers);
С уважением,
Виталий
var_dump действительно не нужен, забыл удалить его после тестов. В архиве и статье исправил.
«ошибка в описании статьи: комментарии здесь не нужны» — комментарии создал плагин, убрать их статьи не получится, так как там симбиоз html и php кода. Люди, которые это читают, — смело качайте архив, там нет ничего лишнего. Всё исправно работает!
вот только как защитить его от перебора паролей, а самое главное как сделать чтоб на страницу которую входишь после авторизации можно бы было попасть только авторизованным а то иначе если ввесли в строке адрес то можно без труда туда попасть
а вот как с перебором бороться?
Воспользовался Вашим решением. Все работает отлично. Спасибо большое!
Но так как я темный лес в этом во всем, то никак не могу понять, что нужно прописать на ту или иную страницу сайта (они у меня в html), чтобы закрыть контент от незарегистрированных пользователей и их перекидывало бы на страницу авторизации.
Подскажите, пожалуйста, если не сложно.
Спасибо.
Содержание страницы надо расположить между конструкциями <?php if ( isset ($_SESSION['logged_user']) ): и <?php else: ?>. Это уже реализовано в файле index.php, можно там подглядеть. Если человек не авторизован, то увидит надпись «Вы не авторизованы». А если он авторизовался, то увидит надпись «Авторизован!». По аналогии можно поступить со своим контентом.
А чтобы определить авторизован человек или нет, — надо воспользоваться сессиями. session_start(); — стартует новую сессию, либо возобновляет существующую. В файле db.php это также реализовано.
Надеюсь, что помог, а не ещё больше запутал.
Нет, вроде бы Вы меня не запутали. Но… Когда я экспериментирую со страничкой index.php, то все получается отлично. Тестовый текст отображается только тогда, когда я авторизован.
Когда же я пытаюсь применить сие счастье на рабочей странице, то что-то идет не так. Вверху и внизу страницы одновременно отображается следующее:
Авторизован! Привет, login; ?>! Выйти
иВы не авторизованы Авторизация Регистрация
Уверен, что где-то допускаю глупую ошибку, скорее всего связанную с недостаточным пониманием логики работы кода. Пишу так:<?php require 'db.php'; ?> <?php if ( isset ($_SESSION['logged_user']) ) : ?> Авторизован! Привет, <?php echo $_SESSION['logged_user']->login; ?>! <a href="logout.php">Выйти</a> <!DOCTYPE html> <html lang="en"> <head> </head> <body> И тут внутренности страницы
Внизу страницы:</body> </html> <?php else : ?> Вы не авторизованы <a href="/login.php">Авторизация</a> <a href="/signup.php">Регистрация</a> <?php endif; ?>
Вроде бы все так делаю на мой взгляд…Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at C:\OSPanel\domains\localhost\index.php:1) in C:\OSPanel\domains\localhost\db.php on line 10
Если посмотреть на db.php, то там этоsession_start();
, а в index.php это<?php require 'db.php'; ?>
Алексей, спасибо Вам огромнейшее еще раз! Вы заставили мой мозг поработать)) И, конечно же, помогли в решении моей задачи. Особенно фраза «Это уже реализовано в файле index.php, можно там подглядеть» для меня стала решающей, так как начал с ней экспериментировать и все пошло в нужном направлении.
От всей души СПАСИБО!!!
P.S. Я вообще тёмный лес в этом вопросе.
В данном скрипте для работы с базой данных используется библиотека RedBean PHP. По этой ссылке можно подробнее про неё почитать и посмотреть примеры.
Например, тут $user = R::dispense('users'); используется метод dispense, в который передается название таблицы users.
<?php
require 'libs/rb.php';
R::setup( 'mysql:host=127.0.0.1;dbname=homework54','myuser, 'mypass' );
$user = R::dispense('users');
if ( !R::testconnection() )
{
exit ('Нет соединения с базой данных');
}
session_start();
?>
с учётом, того, что название таблицы: «users»
<?php
require 'libs/rb.php';
R::setup( 'mysql:host=127.0.0.1;dbname=redbeen','root', '' );
if ( !R::testconnection() )
{
exit ('Нет соединения с базой данных');
}
session_start();
?>
Тогда где параметры подключения указывать?
R::setup( 'mysql:host=127.0.0.1;dbname=имя_вашей_базы','ваш_логин_от_бд', 'ваш_пароль_от_бд' );
Вот в $_SESSION['logged_user'] я с горем пополам сделал чтобы заносилось только это
array(3) { [«auth»]=> string(5) «admin» [«captcha»]=> int(1) [«logged_user»]=> string(5) «admin» }
Вместо громадного массива. Теперь есть вопрос. Как достать оттуда значение «logged_user» или «auth» (они в моём случае равны admin)
<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
@session_start();
include 'config.php';
$login = $_SESSION[«logged_user»];
var_dump( $_SESSION);
$link = mysqli_connect(HOST, USERNAME, PASS, DBNAME);
mysqli_set_charset($link, «utf8mb4_unicode_ci»);
$login = strval($login);
$res=mysqli_query($link,«SELECT * FROM `users` WHERE `login` = '$login' „);
$row = mysqli_fetch_array($res);
echo $row;
if (!$row['usertype']) echo “Тут можно вывести форму входа»;
else if ($row['usertype'] === 2) echo «Admin-доступ»;
else if ($row['usertype'] === 1) echo «Вы модератор»;
else if ($row['usertype'] === 0) echo «Вы обычный пользователь»;
?>
array(3) { [«auth»]=> string(5) «admin» [«captcha»]=> int(1) [«logged_user»]=> string(5) «admin» }
Notice: Array to string conversion in /var/www/user290/data/www/engineer-school.space/test.php on line 14
ArrayТут можно вывести форму входа
Реализовал форму регистрации с шифрованием немного отличным от того что преподносится в уроке не стандартным php хешем, a sha1, теперь хотелось бы прикрутить функцию восстановления пароля к примеру Нажимаем восстановить пароль и данные отсылаются на почту указанную в при регистрации. Но что то не особо получается. Подскажите пожалуйста как правильно подцепить к своей форме данную возможность.
Спасибо.
Вас интересует алгоритм действий? Я бы ничего восстанавливать не стал, а создал новый рандомный пароль и отправил его на почту:
1. делаем форму восстановления
2. вводим в нее почту, на которую регистрировались
3. проверяем есть ли такая почта в базе
3.1. если нет, то предлагаем создать новый аккаунт
3.2. если есть, то генерируем пароль из N рандомных символов. Кодируем их, как хотим и сохраняем в базу для этой почты
4. шлем письмо с новым паролем
спасибо
на 69 строке var_dump так и весит=)))
везде обманывают=)))
сп за скрипт
действительно обманул :(
Если я правильно понял, ничего кроме файла bd менять не надо. Если ошибаюсь пожалуйста поправьте.
И ещё, так как я только-только начал вникать в такие дела, подскажите пожалуйста, куда и что прописать, чтоб в на страницу регистрации добавить текстовое поле Несколько слов о себе.
Заранее благодарен. Печенюшки от веб-мастера (если можно так назваться), с главной страницы. Регулярно при заходах
Если не ошибаюсь, ничего кроме файла bd менять не надо?
И ещё, так как я только-только начал вникать в эти дела, пожалуйста подскажите, что и куда прописать, чтоб на страницы регистрации добавить поле Немного о себе.
Печеньки к чаю от веб мастера (если можно так назваться), с Главной, регулярно при посещениях.
Чтобы авторизация заработала достаточно поменять значения в файле bd.
Добавить поле Немного о себе можно в файле signup, например, после самой формы — в самый конец файла
Извини братское сердце, снова нет больше. Но зато приятно )))
и как в форме добавления новых данных в бд сделать так, что бы там была запись, мол добавил данные Иван Иваныч (залогиневшийся пользователь)?
Да ещё вопросик. Зип распаковывается папкой authorization_php, в ней ещё одна папка authorization_php, а уж в ней каталог. Так и загружать, или достаточно одной authorization_php с каталогом?
загружать надо самую последнюю папку authorization_php
если еще остались вопросы, то можно ознакомиться с видео уроком www.youtube.com/watch?v=vvgOPJQA8Zk
В инструкции RedBean сказано:
RedBeanPHP не работает со строгим режимом MySQL. Чтобы отключить строгий режим, выполните следующий SQL-запрос:
SET @@global.sql_mode= '';
Попробовал выполнить, выдало
#1227 — В доступе отказано. Вам нужны привилегии SUPER для этой операции
А где их взять?
Или вообще не там копаю. Но в БД таблицы users нет.
На ошибки проверил не раз. И по видео и по коду в статье.
php5.6
Сайт на хостинге Бегет, но пока на бесплатном тарифе, техподдержки нет.
Скрипт очень нравится, но никак не даётся.
Теперь остался последний зихер: капча выдаёт Ответ на вопрос указан не верно! На все ответы.
Подскажите пожалуйста, в чём может быть дело.
капча выдаёт Ответ на вопрос указан не верно! На все ответы. — это странно. Капча рабочая, много раз лично тестировал. Если правильно написать ответ, то ошибку выдавать не должно.
Я думаю у вас не работает функция mb_strtolower с русскими буквами. Она находится в файле signup.php на 66 строчке. В ней я не указывал параметр encoding. А если он в явном виде не указан, то вместо него будет использовано значение внутренней кодировки. Вам скорее всего просто нужно в mb_strtolower указать кодировку UTF-8.
Если совсем беда, то просто удалите проверку капчи в файле signup.php и подключите обычную капчу от Google.
Вместо этого:
if ( $_SESSION['captcha'] != array_search( mb_strtolower($_POST['captcha']), $answers ) )
Напишите так:
if ( $_SESSION['captcha'] != array_search( mb_strtolower($_POST['captcha']), $answers, 'UTF-8' ) )
Надеюсь, что помог
Может кодировку указал неправильно. Вот так
if ( $_SESSION['captcha'] != array_search( mb_strtolower($_POST['captcha'], 'UTF-8'), $answers ) )
Да, и так со второго клика. Чудеса.
Последний вопросик: если добавить поля в форму регистрации, то в БД они появятся автоматически или надо добавлять вручную?
И спасибо за материал. Что ни говори, а благодаря вам есть отличный результат.
Если добавить поля по аналогии с другими полями, которые уже имеются в форме, то таблицы в БД должны автоматически создаваться. Библиотека RedBeanPHP сама всё сделает, главное внимательно прописать имена переменных и ничего не забыть.
RedBean должен поддерживаться любым хостингом. Если файл на хостинг не закачивается, то нужно обратиться к ним в службу поддержки.
Без ОРМ в интернете полно готовых скриптов. Основное преимущество данного скрипта это безопасность, что для формы авторизации критически важно.
А что хостинг ответил на прошлую проблему? Почему файл не хотел закачиваться?
Что сейчас происходит после регистрации? Появляется надпись – “Вы успешно зарегистрированы!”??
Еще можно попробовать включить вывод ошибок, добавив в начало нужного .php файла следующие строки:
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
После этого попробовать снова зарегаться и посмотреть какие ошибки всплывут. А пока слишком мало информации.
Вот можете глянуть, ничего не выводиться
у вас данные из формы не отправляются в обработчик (signup.php)
сейчас у формы прописан action=" reg.php ". Я не знаю есть такой файл на FTP или нет, но к нему в любом случае нельзя обратиться из-за редиректа. Скорее всего в htaccess файле прописано правило, которое удаляет у страниц .php
Посмотрите как в примере прописан action у формы и сделайте по аналогии. Убедитесь, что путь к обработчику прописан корректно и он открывается.
Fatal error: Uncaught [42000] — SQLSTATE[42000]: Syntax error or access violation: 1286 Unknown storage engine 'InnoDB' trace: #0 /profiles/p/pu/put/putishestvinik/putishestvinik.zzz.com.ua/rb.php(958): RedBeanPHP\Driver\RPDO->runQuery('CREATE TABLE `u...', Array) #1 /profiles/p/pu/put/putishestvinik/putishestvinik.zzz.com.ua/rb.php(3455):
Что делать, как быть, спасите
Fatal error: Call to a member function findOne() on a non-object in C:\OSPanel\domains\Carcolor.ru\libs\rb.php on line 10854
Fatal error: Uncaught [42S22] - SQLSTATE[42S22]: Column not found: 1054 Unknown column 'id' in 'field list' trace: #0 /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php(882): RedBeanPHP\Driver\RPDO->runQuery('INSERT INTO `us...', Array) #1 /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php(919): RedBeanPHP\Driver\RPDO->GetAll('INSERT INTO `us...', Array) #2 /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php(3547): RedBeanPHP\Driver\RPDO->GetOne('INSERT INTO `us...', Array) #3 /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php(4976): RedBeanPHP\Adapter\DBAdapter->getCell('INSERT INTO `us...', Array, 0) #4 /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php(5103): RedBeanPHP\QueryWriter\AQueryWriter->insertRecord('users', Array, Array) #5 /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php(7646): RedBeanPHP\QueryWriter\AQueryWriter->updateRecord('users', Array, 0) #6 /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php(7233): RedBeanPHP\Repository\Fluid->storeBean(Object(RedBeanPHP\OODBBean)) #7 /home/p522455/www/ in /home/p522455/www/p522455.ihc.xyz/admstr/libs/rb.php on line 720
Таки как сие победять?Вне зависимости от наличия как самой таблицы users так и столбцов id/login/password/email в ней
Fatal error: Uncaught [22001] — SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'password' at row 1 trace: #0 W:\domains\localhost\avtoriz\libs\rb.php(882): RedBeanPHP\Driver\RPDO->runQuery('INSERT INTO `us...', Array) #1 W:\domains\localhost\avtoriz\libs\rb.php(919): RedBeanPHP\Driver\RPDO->GetAll('INSERT INTO `us...', Array) #2 W:\domains\localhost\avtoriz\libs\rb.php(3547): RedBeanPHP\Driver\RPDO->GetOne('INSERT INTO `us...', Array) #3 W:\domains\localhost\avtoriz\libs\rb.php(4976): RedBeanPHP\Adapter\DBAdapter->getCell('INSERT INTO `us...', Array, 0) #4 W:\domains\localhost\avtoriz\libs\rb.php(5103): RedBeanPHP\QueryWriter\AQueryWriter->insertRecord('users', Array, Array) #5 W:\domains\localhost\avtoriz\libs\rb.php(7646): RedBeanPHP\QueryWriter\AQueryWriter->updateRecord('users', Array, 0) #6 W:\domains\localhost\avtoriz\libs\rb.php(7233): RedBeanPHP\Repository\Fluid->storeBean(Object(RedBeanPHP\OODBBean)) #7 W:\domains\localhost\avtoriz\libs\rb.php(8310): RedBeanPHP\Repository->store(Obje in W:\domains\localhost\avtoriz\libs\rb.php on line 720
если я правильно понимаю PHP выше 7 не хэширует пароль, когда я тестирую на локальном сервере. Алексей скажите пожалуйста, как это исправить может быть есть команды совместимости?
Идея такая, есть локальная сеть, нужно чтобы пользователи через веб интерфейс заходили по своему логину и паролю (учетные записи пользователей Windows) на определенные страницы.
Спасибо большое. Будет очень даже полезный опыт
Заранее благодарен
Warning: session_start(): Cannot send session cache limiter — headers already sent (output started at E:\OSPanel\domains\imysite.ru\index.php:6) in E:\OSPanel\domains\imysite.ru\db.php on line 10
ошибка связанная с session_start();
<form action="/signup.php" method="POST">
У меня вопрос… а как сделать чтобы разных пользователей перекинуло на разные страницы?
Спасибо
<?php require 'db.php';?> надо вставить отдельно в каждую страницу сверху перед <!doctype html>.
А $data = $_POST; и т.д. положить отдельно <?php ?>.
И уже вместе с формой в body — div id=container например.
if ( password_verify($data['password'], $user->password) ) { //если пароль совпадает, то нужно авторизовать пользователя $_SESSION['logged_user'] = $user; echo '<div style="color:dreen;">Вы авторизованы! Можете перейти на <a href="/">главную</a> страницу.</div><hr>'; }else { $errors[] = 'Неверно введен пароль!'; }
При правильном вводе своего пароля, у меня выходит «Неверно введен пароль!»The requested URL was not found on this server.
у меня такая ошибка когда нажал на регистрацию
Мне нужно форму разместить в модальном окне, но в файле и код формы и код подключения к bd.
Поэтому в модальном окне отображается весь код файла.
Как мне поступить, что бы в модальное окно разместить только форму с чистыми полями ввода. И если можно, то на почту — garinvladimir430@gmail.com
Сам я конечно не сделаю, масла мало в голове в моем возрасте, да и это мой первый сайт в жизни.
Заранее благодарен. Михаил Гагаркин.
я по поводу просьбы в комментарии.
<div class="login-list"> <div class="con-reg right-panel-active"> <!-- Зарегистрироваться --> <div class="con-reg__form con-reg--signup"> <form action="reg.html" class="form" id="form1" method="POST"> <h2 class="form__title">Зарегистрироваться</h2> <input type="text" placeholder="User" class="input" name="login" value="<?php echo @$data['login']; ?>"> <input type="email" placeholder="Email" class="input" name="email" value="<?php echo @$data['email']; ?>"> <input type="password" placeholder="Password" class="input" name="password" value="<?php echo @$data['password']; ?>"> <input type="password" placeholder="Password" class="input" name="password_2" value="<?php echo @$data['password_2']; ?>"> <strong><?php captcha_show(); ?></strong> <input type="text" name="captcha" > <button class="btn-reg" type="submit" name="do_signup">Зарегистрироваться</button> </form> </div> <!-- Войти --> <div class="con-reg__form con-reg--signin"> <form action="#" method="POST" class="form" id="form2"> <h2 class="form__title">Войти</h2> <input type="email" placeholder="Email" class="input" name="email" value="<?php echo @$data['email']; ?>"> <input type="password" placeholder="Password" class="input" name="password" value="<?php echo @$data['password']; ?>"> <a href="#" class="link">Забыли пароль:(?</a> <button class="btn-reg" type="submit" name="do_login">Войти</button> </form> </div> <!-- Оверлей --> <div class="con-reg__overlay"> <div class="overlay"> <div class="overlay__panel overlay--left"> <button class="btn-reg" id="signIn">Войти</button> </div> <div class="overlay__panel overlay--right"> <button class="btn-reg" id="signUp">Зарегистрироваться</button> </div> </div> </div> </div> </div>