php регистрация пользователей, проверка уникальности значений
Делаю регистрацию пользователя для своего сайта, php учу не так давно.
Данные получаю с формы -> далее проверяю их корректность, если все хорошо отправляю в БД.
Это функция у меня в отельном файле я ей передаю только значения.
function regUser($v1,$v2,$v3,$v4){
$mysqli = @new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if($mysqli->connect_errno)exit('Ошибка соединения с БД');
$mysqli->set_charset('utf8');
$result = $mysqli->query("INSERT INTO `users`(`login`, `password`, `mail`, `date_reg`) VALUES
('$v1','$v2','$v3','$v4')");
$mysqli->close();
return $result;
}
В БД поля логин и mail уникальные, и на сайте я хочу оповещать пользователя о том что если он ввел не уникальное значение, то что именно ему надо исправить логин или mail, подскажите как это можно сделать, у меня был вариант с разбитием запроса на части и потом смотреть что вернет query для каких данных.
Если у кого есть примеры из практики и код, как лучше сегодня делать регистрацию пользователей буду очень благодарен.
Ответы (2 шт):
Чтобы проверить существование пользователя, надо выполнить обычный SELECT запрос. Поэтому сначала научимся как выполнять SELECT запрос правильно.
Чтобы выполнить SELECT запрос с использованием переменных, надо сделать следующее:
- Написать запрос, в котором все переменные заменить на знаки вопроса
- Подготовить запрос к выполнению
- Привязать переменные к запросу
- Выполнить
В итоге получится такой код:
// создаем запрос SQL в котором все переменные заменены на знак вопроса
$sql = "SELECT * FROM users WHERE login=?";
// подготоваливаем запрос
$stmt = $conn->prepare($sql);
// привязываем переменные к запросу
// указывая тип для каждой переменной. для простоты всегда можно использовать тип "s"
$stmt->bind_param("s", $login);
// выполняем запроc
$stmt->execute();
// получаем результат
$result = $stmt->get_result();
// из результата получаем строку
$user = $result->fetch_assoc();
// и дальше уже можем проверить, вернула БД данные или нет
if ($user) {
echo "OK";
} else {
echo "error";
}
при таком способе у нас никогда не будет ошибок синтаксиса, не говоря уже об sql инъекциях.
что такое sql инъекция? в данном случае это дыра в заборе рядом с железными воротами. Какой бы надежной авторизация не была, если переменные пишутся прямо в запрос, а не передаются отдельно, то кто угодно сможет авторизоваться под кем угодно, даже не зная пароля - просто дописав в логин кусок SQL запроса. Или даже угнать к себе всю базу данных пользователей с логинами и паролями целиком.
То же самое касается и регистрации пользователя, или выполнения запроса INSERT:
// создаем запрос SQL в котором все переменные заменены на знак вопроса
$sql = "INSERT INTO `users` (`login`, `password`, `mail`, `date_reg`) VALUES(?,?,?, NOW())";
// подготоваливаем запрос
$stmt = $mysqli->prepare($sql);
// привязываем переменные к запросу
// указывая тип для каждой переменной. для простоты всегда можно использовать тип "s"
$stmt->bind_param("sss", $login, $password, $mail);
// выполняем запроc
$stmt->execute();
Кроме того, пароль никогда не пишется в БД в открытом виде. Пароль надо хэшировать. Чтобы даже если у нас и угонят БД, то пароли все равно остались неизвестными.
Кроме того, соединяться с БД надо только один раз, и в дальнейшем везде использовать одну и ту же переменную с созданным соединением. Сначала смотрим как правильно подключаться к mysqli
В итоге твой код может выглядеть так:
function checkUserExists($mysqli, $login, $email)
{
$stmt = $conn->prepare("SELECT * FROM users WHERE login=? or email=?");
$stmt->bind_param("s", $login, $email);
$stmt->execute();
$result = $stmt->get_result();
return $result->fetch_assoc();
}
function regUser($mysqli, $login, $password, $email)
{
$password = password_hash($password, PASSWORD_DEFAULT);
$sql = "INSERT INTO `users` (`login`, `password`, `mail`, `date_reg`) VALUES(?,?,?, NOW())";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("sss", $login, $password, $mail);
$stmt->execute();
}
И дальше же используем эти функции.
<?php
require 'mysqli.php';
$errors = [];
// другие проверки
// которые заполняют массив $errors
$user = checkUserExists($mysqli, $_POST['login']);
if ($user) {
if ($user['login'] == $_POST['login']) {
$errors[] = "логин занят";
elseif ($user['email'] == $_POST['email']) {
$errors[] = "email занят";
}
}
if (!$errors) {
regUser($mysqli, $_POST['login'], $_POST['password'], $_POST['email'])
}
Здесь мы запрашиваем из бд пользователя, у которого либо логин, либо емейл уже есть в БД. Если пользователь находится то сравниваем значения из БД с в введенными данными и выводим сообщение. Если свопадений нет - регистрируем.
Огромное спасибо за помощь, пришлось еще с PDO подключением поковыряться, но сейчас все работает
Вот что получилось в итоге(в коде нет подключения к БД, оно в отдельном файле)
<?php
include 'connect.php'; // Подключение к бд с помощью PDO
$regexp_valid = "/[^a-zA-Z0-9.,@а-яА-Я -]+/"; // регулярка для проверка входных данных
// Избовляюсь от нотисов в HTML, т.к. поля после неверного заполения таблицы не стираются и не надо вводить все данные заново
$result = '';
$login = '';
$mail = '';
$msg = "Поля могут содержать цифры, буквы, сивол - @";
// Если отправилась форма методом POST начинаем проверку данных и заносим в БД. Форма на этой же странице.
// Если заходить на страницу просто по адресу а не отправкой формы то мы на нее поподаем методом GET
if($_SERVER['REQUEST_METHOD'] == 'POST' && count($_POST) > 0){
// Обработка данных из массива POST
$login = strtolower(trim($_POST['login']));
$mail = strtolower(trim($_POST['mail']));
$password = trim($_POST['password']);
$today = date("Ymd");;
// проверка на корректность
if(((bool)preg_match($regexp_valid, $login)) || $login == '' ){
$msg = "Ошибка, логин $login - не кооректный";
}elseif(((bool)preg_match($regexp_valid, $mail)) || $mail == ''){
$msg = "Ошибка, mail $mail - не кооректный";
}elseif(((bool)preg_match($regexp_valid, $password)) || strlen($password) < 8 || $password == ''){
$msg = "Ошибка, пароль не кооректный";
}else{
// Проверка на идентичность с БД (что бы пользователь с одими и теми же данными не зарестрировался два раза)
// Проверка логина
$check_login = $pdo->prepare('SELECT count(*) FROM`users` WHERE `login`=:login ');
$check_login->execute(['login' => $login]); // отправка подготовленого запроса вернет true если запрос сработал
$res_check_login = $check_login->fetchColumn();// смотрим результат по колонке если select ничего не нашел будет пусто
// Проверка почты
$check_mail = $pdo->prepare('SELECT count(*) FROM`users` WHERE `mail`= :email ');
$check_mail->execute(['email' => $mail]);// отправка подготовленого запроса вернет true если запрос сработал
$res_check_mail = $check_mail->fetchColumn();// смотрим результат по колонке если select ничего не нашел будет пусто
// Проверяем что пришло из БД и если все в норме выполнится блок else где данные нового пользователся занесутся в БД
if($res_check_login){
$msg = "Пользователь с таким именем уже существует";
}elseif($res_check_mail){
$msg = "Пользователь с таким e-mail уже существует";
}else{
// Выполняем insert в БД
$reg_user= $pdo->prepare('INSERT INTO `users`(`login`, `password`,
`mail`, `date_reg`) VALUES (:login,:password,:mail,:date)');
$check_reg_yser = $reg_user->execute(['login' => $login, 'password'
=> $password, 'mail'=> $mail, 'date' => $today ]);
if($check_reg_yser){
$msg = "Регистрация успешно завершена";
}else{
$msg = "Регистрация временно недоступна, приносим извенения";
}
}
}
}
?>