Již jsem napsal blogový příspěvek o vytvoření kompletního systému registrace a přihlášení uživatele pomocí PHP a MySQL, ale nezahrnul jsem ověření e-mailu.
Tento tutoriál je trochu jako aktualizace předchozího návodu. Kromě toho, že se uživatel bude moci zaregistrovat, přihlásit a odhlásit ze svého účtu, bude také zaslán ověřovací e-mail na jeho e-mailovou adresu s odkazem, na který může kliknout a nechat si ověřit svou e-mailovou adresu.
U většiny aplikací, které se chystáte vytvořit, je důležité přidat funkci ověřování e-mailu z mnoha důvodů:možná budete chtít uživateli poslat e-mail později a chcete se ujistit, že jej uvidí; nebo uživatel může zapomenout své heslo a potřebuje ho resetovat, a abychom to mohli udělat, budeme mu muset poslat e-mail s odkazem na resetování hesla; existuje mnoho dalších důvodů, ale rozumíte tomu.
V tomto systému, který dnes budujeme, uživatelé, kteří neověřili svůj e-mail, nebudou moci provádět určité akce (použiji pouze jednoduchou ukázku, jako je zobrazení tlačítka. Toto tlačítko uvidí pouze ověření uživatelé).
Chcete-li začít, vytvořte nový projekt PHP s názvem ověřit-uživatel a v této složce vytvořte dva soubory:signup.php a login.php.
signup.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="main.css">
<title>User verification system PHP</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4 form-wrapper auth">
<h3 class="text-center form-title">Register</h3>
<form action="signup.php" method="post">
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
</div>
<div class="form-group">
<label>Email</label>
<input type="text" name="email" class="form-control form-control-lg" value="<?php echo $email; ?>">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control form-control-lg">
</div>
<div class="form-group">
<label>Password Confirm</label>
<input type="password" name="passwordConf" class="form-control form-control-lg">
</div>
<div class="form-group">
<button type="submit" name="signup-btn" class="btn btn-lg btn-block">Sign Up</button>
</div>
</form>
<p>Already have an account? <a href="login.php">Login</a></p>
</div>
</div>
</div>
</body>
</html>
Je to jen jednoduchý soubor HTML/CSS. Jediná věc, která stojí za zmínku, je, že ke stylování naší stránky používáme framework Bootstrap 4 CSS. Můžete použít jakýkoli jiný stylingový rámec podle svého výběru nebo si napsat vlastní CSS, pokud chcete.
Ihned po Bootstrap CSS přidáváme soubor main.css pro vlastní styling. Nyní vytvoříme tento soubor. V kořenové složce aplikace vytvořte soubor s názvem main.css.
main.css:
@import url('https://fonts.googleapis.com/css?family=Lora');
li { list-style-type: none; }
.form-wrapper {
margin: 50px auto 50px;
font-family: 'Lora', serif;
font-size: 1.09em;
}
.form-wrapper.login { margin-top: 120px; }
.form-wrapper p { font-size: .8em; text-align: center; }
.form-control:focus { box-shadow: none; }
.form-wrapper {
border: 1px solid #80CED7;
border-radius: 5px;
padding: 25px 15px 0px 15px;
}
.form-wrapper.auth .form-title { color: #007EA7; }
.home-wrapper button,
.form-wrapper.auth button {
background: #007EA7;
color: white;
}
.home-wrapper {
margin-top: 150px;
border-radius: 5px;
padding: 10px;
border: 1px solid #80CED7;
}
Na prvním řádku tohoto souboru importujeme a používáme některá písma Google, aby naše písma vypadala krásněji.
Nyní přejděte na soubor login.php a proveďte podobnou věc.
login.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="main.css">
<title>User verification system PHP - Login</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4 form-wrapper auth login">
<h3 class="text-center form-title">Login</h3>
<form action="login.php" method="post">
<div class="form-group">
<label>Username or Email</label>
<input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control form-control-lg">
</div>
<div class="form-group">
<button type="submit" name="login-btn" class="btn btn-lg btn-block">Login</button>
</div>
</form>
<p>Don't yet have an account? <a href="signup.php">Sign up</a></p>
</div>
</div>
</div>
</body>
</html>
Ve svém prohlížeči přejděte na http://localhost/cwa/verify-user/signup.php a uvidíte krásný přihlašovací formulář (stejný pro přihlášení). Ignorujte chyby ve vstupních polích, brzy to napravíme.
Prozatím si nastavíme databázi. Vytvořte databázi s názvem ověřit-uživatel a v této databázi vytvořte tabulku uživatelů s následujícími atributy:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
`verified` tinyint(1) NOT NULL DEFAULT '0',
`token` varchar(255) DEFAULT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
Nic neobvyklého, snad kromě tokenu a ověřených polí, která za chvíli vysvětlím.
Nyní začneme se skutečnou logikou registrace. Obvykle rád označuji logickou část své aplikace jako ovladače a to je to, co zde udělám. V kořenové složce projektu vytvořte složku s názvem controllers a uvnitř controllers vytvořte soubor s názvem authController.php.
controllers/authController.php:
<?php
session_start();
$username = "";
$email = "";
$errors = [];
$conn = new mysqli('localhost', 'root', '', 'verify-user');
// SIGN UP USER
if (isset($_POST['signup-btn'])) {
if (empty($_POST['username'])) {
$errors['username'] = 'Username required';
}
if (empty($_POST['email'])) {
$errors['email'] = 'Email required';
}
if (empty($_POST['password'])) {
$errors['password'] = 'Password required';
}
if (isset($_POST['password']) && $_POST['password'] !== $_POST['passwordConf']) {
$errors['passwordConf'] = 'The two passwords do not match';
}
$username = $_POST['username'];
$email = $_POST['email'];
$token = bin2hex(random_bytes(50)); // generate unique token
$password = password_hash($_POST['password'], PASSWORD_DEFAULT); //encrypt password
// Check if email already exists
$sql = "SELECT * FROM users WHERE email='$email' LIMIT 1";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
$errors['email'] = "Email already exists";
}
if (count($errors) === 0) {
$query = "INSERT INTO users SET username=?, email=?, token=?, password=?";
$stmt = $conn->prepare($query);
$stmt->bind_param('ssss', $username, $email, $token, $password);
$result = $stmt->execute();
if ($result) {
$user_id = $stmt->insert_id;
$stmt->close();
// TO DO: send verification email to user
// sendVerificationEmail($email, $token);
$_SESSION['id'] = $user_id;
$_SESSION['username'] = $username;
$_SESSION['email'] = $email;
$_SESSION['verified'] = false;
$_SESSION['message'] = 'You are logged in!';
$_SESSION['type'] = 'alert-success';
header('location: index.php');
} else {
$_SESSION['error_msg'] = "Database error: Could not register user";
}
}
}
// LOGIN
if (isset($_POST['login-btn'])) {
if (empty($_POST['username'])) {
$errors['username'] = 'Username or email required';
}
if (empty($_POST['password'])) {
$errors['password'] = 'Password required';
}
$username = $_POST['username'];
$password = $_POST['password'];
if (count($errors) === 0) {
$query = "SELECT * FROM users WHERE username=? OR email=? LIMIT 1";
$stmt = $conn->prepare($query);
$stmt->bind_param('ss', $username, $password);
if ($stmt->execute()) {
$result = $stmt->get_result();
$user = $result->fetch_assoc();
if (password_verify($password, $user['password'])) { // if password matches
$stmt->close();
$_SESSION['id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['email'] = $user['email'];
$_SESSION['verified'] = $user['verified'];
$_SESSION['message'] = 'You are logged in!';
$_SESSION['type'] = 'alert-success';
header('location: index.php');
exit(0);
} else { // if password does not match
$errors['login_fail'] = "Wrong username / password";
}
} else {
$_SESSION['message'] = "Database error. Login failed!";
$_SESSION['type'] = "alert-danger";
}
}
}
Pokud jste postupovali podle mých předchozích návodů, pak by pro vás nic v tomto souboru nemělo být nové. Ale pro začátečníky vám to trochu vysvětlím.
První věcí je, že relaci spouštíme pomocí session_start(), protože v relaci budeme muset uložit informace o přihlášeném uživateli. Po zahájení relace inicializujeme proměnné $username a $email, které používáme v našich formulářích, a také pole $errors, které bude obsahovat naše chyby ověření formuláře.
Dále se připojíme k databázi. Další dva příkazy if, které následují, jsou v tomto pořadí kód, který se spustí, když uživatel klikne na tlačítko přihlášení nebo přihlášení. V případě přihlášení zkontrolujeme, zda jsou všechna povinná pole správně vyplněna a teprve poté přistoupíme k uložení uživatele do databáze. Také generujeme token (jedinečný, náhodný řetězec) a ukládáme jej s uživatelem jako atribut. Toto bude použito k ověření uživatelského e-mailu. Více o tom později.
Vzhledem k tomu, že náš soubor authController.php je zodpovědný za registraci a přihlášení, musíme jej zahrnout úplně nahoře na stránkách signup.php a login.php, protože tam se odesílají data formuláře. Asi takhle:
signup.php a login.php (úplně nahoře):
<?php include 'controllers/authController.php' ?>
Pokud jsou v poli $errors nějaké chybové zprávy, musíme je zobrazit ve formuláři. Chcete-li to provést, přidejte tento příkaz if do formuláře přímo pod nadpis formuláře pro přihlašovací i přihlašovací stránky.
<!-- form title -->
<h3 class="text-center form-title">Register</h3> <!-- or Login -->
<?php if (count($errors) > 0): ?>
<div class="alert alert-danger">
<?php foreach ($errors as $error): ?>
<li>
<?php echo $error; ?>
</li>
<?php endforeach;?>
</div>
<?php endif;?>
Pokud nejsou žádné chyby, náš skript bude pokračovat v uložení uživatele do databáze. Po uložení uživatele do databáze jej ihned přihlásíme. V našem případě přihlášení uživatele znamená uložení jeho dat v relaci a to jsme právě udělali.
V tuto chvíli se již můžete zaregistrovat a dokonce i přihlásit uživatele. Ale po přihlášení budete přesměrováni na stránku index.php, která neexistuje. Brzy jej vytvoříme.
V authController.php ukládáme proměnné zprávy a typu v relaci, které se zobrazí, jakmile se uživatel přihlásí. message je skutečný text zprávy, zatímco typem je stylová třída Bootstrap, která zprávu naformátuje do vhodného barvy v závislosti na hodnotě typu.
Tato zpráva se zobrazí po přihlášení uživatele a zobrazí se v souboru index.php. Vytvořme tento soubor nyní v kořenové složce našeho projektu.
index.php:
<?php include 'controllers/authController.php'?>
<?php
// redirect user to login page if they're not logged in
if (empty($_SESSION['id'])) {
header('location: login.php');
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="main.css">
<title>User verification system PHP</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4 home-wrapper">
<!-- Display messages -->
<?php if (isset($_SESSION['message'])): ?>
<div class="alert <?php echo $_SESSION['type'] ?>">
<?php
echo $_SESSION['message'];
unset($_SESSION['message']);
unset($_SESSION['type']);
?>
</div>
<?php endif;?>
<h4>Welcome, <?php echo $_SESSION['username']; ?></h4>
<a href="logout.php" style="color: red">Logout</a>
<?php if (!$_SESSION['verified']): ?>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
You need to verify your email address!
Sign into your email account and click
on the verification link we just emailed you
at
<strong><?php echo $_SESSION['email']; ?></strong>
</div>
<?php else: ?>
<button class="btn btn-lg btn-primary btn-block">I'm verified!!!</button>
<?php endif;?>
</div>
</div>
</div>
</body>
</html>
Tato stránka má být přístupná pouze přihlášeným uživatelům. Proto v horní části souboru přesměrováváme uživatele, pokud není přihlášen, na přihlašovací stránku. Někde uprostřed stránky zobrazujeme zprávu. Po zobrazení zprávy zrušíme nastavení proměnných zprávy a typu, protože nechceme, aby tam zůstaly na stránce i poté, co uživatel stránku obnoví.
Nakonec uprostřed stránky zkontrolujeme, zda přihlášený uživatel ověřil svou e-mailovou adresu, či nikoli. Nezapomeňte, že jsme do relace přidali ověřenou proměnnou, když jsme uživatele přihlásili. Pokud byl uživatel ověřen, zobrazí se zpráva „Jsem ověřen!!!“ tlačítko, aby viděli. Pokud nejsou ověřeni, informujeme je o ověřovacím odkazu, který jsme jim zaslali na jejich e-mailovou adresu, a požádáme je, aby na tento odkaz klikli a ověřili svůj e-mail.
Ověřte e-mail
V souboru authController.php jsme pomocí komentáře uvedli, kam uživateli pošleme ověřovací e-mail voláním sendVerificationEmail(). Přejděte do souboru authController.php a odkomentujte volání funkce takto:
// TO DO: send verification email to user
sendVerificationEmail($email, $token);
Tuto funkci nadefinujeme v jiném souboru a zahrneme tento soubor do authController.php. Ve složce controllers vytvořte soubor s názvem sendEmails.php.
Než do tohoto souboru přidáme jakýkoli kód, dovolte mi říci něco o PHP SwiftMailer, oblíbené knihovně pro odesílání e-mailů v PHP, kterou budeme v tomto projektu používat k odesílání e-mailů z localhost.
SwiftMailer je oblíbená knihovna s bohatými funkcemi pro odesílání e-mailů v aplikacích PHP.
Chcete-li používat Swiftmailer, musíte nejprve nainstalovat Composer. Jakmile nainstalujete skladatel, otevřete terminál nebo příkazový řádek a přejděte do kořenové složky projektu a spusťte následující příkaz pro přidání knihovny Swift Mailer se všemi jejími soubory do našeho projektu:
composer require "swiftmailer/swiftmailer:^6.0"
Tím se v kořenovém adresáři naší aplikace vytvoří složka dodavatele obsahující veškerý kód (třídy) potřebné pro odeslání e-mailu a také se v kořenovém adresáři aplikace vytvoří soubor skladatel.json, který vypadá takto:
{
"require": {
"swiftmailer/swiftmailer": "^6.0"
}
}
Nyní otevřete soubor sendEmails.php, který jsme vytvořili dříve, a napišme funkci sendVerificationEmail():
<?php
require_once './vendor/autoload.php';
// Create the Transport
$transport = (new Swift_SmtpTransport('smtp.gmail.com', 465, 'ssl'))
->setUsername(SENDER_EMAIL)
->setPassword(SENDER_PASSWORD);
// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transport);
function sendVerificationEmail($userEmail, $token)
{
global $mailer;
$body = '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test mail</title>
<style>
.wrapper {
padding: 20px;
color: #444;
font-size: 1.3em;
}
a {
background: #592f80;
text-decoration: none;
padding: 8px 15px;
border-radius: 5px;
color: #fff;
}
</style>
</head>
<body>
<div class="wrapper">
<p>Thank you for signing up on our site. Please click on the link below to verify your account:.</p>
<a href="http://localhost/cwa/verify-user/verify_email.php?token=' . $token . '">Verify Email!</a>
</div>
</body>
</html>';
// Create a message
$message = (new Swift_Message('Verify your email'))
->setFrom(SENDER_EMAIL)
->setTo($userEmail)
->setBody($body, 'text/html');
// Send the message
$result = $mailer->send($message);
if ($result > 0) {
return true;
} else {
return false;
}
}
První příkaz vyžaduje do tohoto souboru soubor autoload.php. Tento soubor autoload.php automaticky zahrne všechny třídy z knihovny Swift Mailer ve složce dodavatele, kterou v tomto souboru používáme.
V tomto příkladu používáme Gmail. Můžete tedy nahradit SENDER_EMAIL a SENDER_PASSWORD svou adresou Gmailu a heslem, které chcete použít jako e-mailovou adresu odesílatele. (E-mailová adresa příjemce je adresa odeslaná prostřednictvím formuláře).
Za normálních okolností, abyste mohli někomu poslat e-mail, musíte se před vytvořením e-mailu a odesláním přihlásit ke svému účtu Gmail. Je to stejné, jako knihovna Swift Mailer. Takže když příjemce ($userEmail) obdrží e-mail, bude to vaše adresa Gmailu (SENDER_EMAIL), kterou uvidí jako odesílající e-mail.
Nyní voláme funkci sendVerificationEmail() v našem souboru authController.php, ale definovali jsme funkci uvnitř souboru sendEmails.php. Pojďme zahrnout soubor sendEmails.php do našeho authController.php, aby byla tato funkce v souboru dostupná. Na začátek souboru authController.php, těsně před session_start(), přidejte následující řádek:
require_once 'sendEmails.php';
To je vše, co potřebujeme, pánové (a dámy), abychom našemu uživateli poslali e-mail s odkazem pro ověření e-mailu. Ale pracujeme na localhost a Gmail bude blokovat všechny pokusy o přihlášení ze Swift Mailer běžícího na localhost.
Odesílání e-mailů z localhost
Pokud chcete, aby to běželo na localhost, budete muset nakonfigurovat svůj účet Gmail tak, aby přijímal přihlášení z méně bezpečných aplikací. Samozřejmě to může představovat určitou zranitelnost na vašem účtu Gmail, ale můžete to udělat pouze na krátkou dobu, kdy potřebujete tuto aplikaci otestovat na localhost. Po otestování můžete nastavení na svém účtu Gmail vrátit zpět. Jakmile bude vaše aplikace hostována na internetu, budete pracovat. Děláme to jen proto, že jsme na localhost.
Můžete být ještě opatrnější a vytvořit si další účet Gmail pouze pro takové účely.
Přihlaste se tedy do svého Gmailu v prohlížeči, přejděte na https://myaccount.google.com/security#connectedapps a změňte hodnotu „Povolit méně bezpečné aplikace“ na ZAPNUTO.
Toto můžete vypnout, jakmile dokončíte testování projektu na localhost.
Díky tomu budete moci odeslat e-mail z localhost s ověřovacím odkazem, jakmile se uživatel zaregistruje. Nyní se znovu podívejte na metodu sendVerificationEmail() a všimnete si, že v těle e-mailu, který posíláme uživateli, byl jako parametr odkazu nastaven token, který jsme pro tohoto konkrétního uživatele vygenerovali (token je jedinečný). takže když uživatel klikne na odkaz v e-mailu, bude přesměrován do naší aplikace na stránce s názvem verify_email.php s tímto tokenem na adrese URL. Takhle:
<a href="http://localhost/cwa/verify-user/verify_email.php?token=0a150966418fa3a694bcb3ab8fcacd2063a096accc0ee33c3e8c863538ee825c0b52f2e1535d0e1377558c378ba5fc3106eb">Verify Email!</a>
Tento token tedy můžeme získat do našeho souboru verifikovat_email.php takto (uklidněte se, brzy vytvoříme tento e-mailový e-mail):
$token = $_GET['token'];
Nyní můžeme tento token použít k načtení uživatele, který má tento konkrétní token (nezapomeňte, že token je jedinečný) a pokud tohoto uživatele získáme, aktualizujeme jeho záznam změnou ověřeného atributu na hodnotu true v databázi. Potom můžeme hrdě prohlásit, že jsme ověřili e-mailovou adresu tohoto uživatele.
Vytvořme tento soubor authentic_email.php v kořenové složce našeho projektu:
ověřit_email.php:
<?php
session_start();
$conn = new mysqli('localhost', 'root', '', 'verify-user');
if (isset($_GET['token'])) {
$token = $_GET['token'];
$sql = "SELECT * FROM users WHERE token='$token' LIMIT 1";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
$user = mysqli_fetch_assoc($result);
$query = "UPDATE users SET verified=1 WHERE token='$token'";
if (mysqli_query($conn, $query)) {
$_SESSION['id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['email'] = $user['email'];
$_SESSION['verified'] = true;
$_SESSION['message'] = "Your email address has been verified successfully";
$_SESSION['type'] = 'alert-success';
header('location: index.php');
exit(0);
}
} else {
echo "User not found!";
}
} else {
echo "No token provided!";
}
Všimněte si, že nastavení hodnoty ověřené hodnoty na 1 je stejné jako nastavení na hodnotu true, protože v databázi MySQL je typ Boolean interpretován jako tinyint.
Když nyní uživatel klikne na odkaz ve svém e-mailu a přesměruje ho na tuto stránku, aktualizuje ověřený stav tohoto uživatele na true, přihlásí ho a přesměruje na stránku index.php. Na indexové stránce si po ověření uživatele všimnete, že varovná zpráva doporučující uživateli ověřit svou e-mailovou adresu je nyní pryč a místo ní máme „Jsem ověřen!!!“ tlačítko, které je viditelné pouze pro ověřené uživatele.
Ještě poslední věc, na stránce index.php po přihlášení uživatele je odkaz pro odhlášení, který ukazuje na soubor logout.php, který má uživatele odhlásit. Vytvořme tento soubor v kořenovém adresáři naší aplikace:
logout.php:
<?php
session_destroy();
unset($_SESSION['id']);
unset($_SESSION['username']);
unset($_SESSION['email']);
unset($_SESSION['verify']);
header("location: login.php");
Kromě toho, že se uživatel může přihlásit, ověřit e-mail, přihlásit se, se nyní může také odhlásit.
Závěr
Takže to je asi tak s registrací uživatele a ověřením emailu. Pokud máte nějaké připomínky, otázky nebo slova povzbuzení, zanechte je prosím v komentáři níže. A prosím, nezapomeňte sdílet tento příspěvek nebo doporučit tuto stránku svým přátelům, pokud vám to pomohlo. Moc mě to povzbuzuje!
Krásný den!