J'ai déjà rédigé un article de blog sur la création d'un système complet d'enregistrement et de connexion des utilisateurs à l'aide de PHP et MySQL, mais je n'ai pas inclus la vérification des e-mails.
Ce tutoriel est un peu comme une mise à jour du tutoriel précédent. En plus de pouvoir s'inscrire, se connecter et se déconnecter de son compte, un utilisateur recevra également un e-mail de vérification à son adresse e-mail avec un lien sur lequel il pourra cliquer et faire vérifier son adresse e-mail.
Sur la plupart des applications que vous allez créer, il est important d'ajouter une fonctionnalité de vérification des e-mails pour de nombreuses raisons :vous souhaiterez peut-être envoyer un e-mail plus tard à l'utilisateur et vous assurer qu'il le verra ; ou l'utilisateur peut oublier son mot de passe et avoir besoin de le réinitialiser, et pour ce faire, nous devrons lui envoyer par e-mail un lien de réinitialisation du mot de passe ; il y a beaucoup d'autres raisons mais vous avez compris.
Dans ce système que nous construisons aujourd'hui, les utilisateurs qui n'ont pas vérifié leur adresse e-mail ne pourront pas effectuer certaines actions (je vais juste utiliser une démonstration simple comme l'affichage d'un bouton. Seuls les utilisateurs vérifiés pourront voir ce bouton).
Pour commencer, créez un nouveau projet PHP nommé verify-user et dans ce dossier, créez deux fichiers :signup.php et login.php.
inscription.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>
C'est juste un simple fichier HTML/CSS. La seule chose à noter est que nous utilisons le framework CSS Bootstrap 4 pour styliser notre page. Vous pouvez utiliser n'importe quel autre cadre de style de votre choix ou écrire votre propre CSS si vous le souhaitez.
Immédiatement après le Bootstrap CSS, nous incluons un fichier main.css pour un style personnalisé. Créons ce fichier maintenant. Dans le dossier racine de l'application, créez un fichier appelé main.css.
principal.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;
}
Sur la première ligne de ce fichier, nous importons et utilisons des polices Google pour rendre nos polices plus belles.
Maintenant, tournez-vous vers le fichier login.php et faites la même chose.
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>
Sur votre navigateur, allez sur http://localhost/cwa/verify-user/signup.php vous verrez un beau formulaire d'inscription (idem pour la connexion). Ignorez les erreurs dans les champs de saisie, nous corrigerons cela bientôt.
Pour l'instant, configurons la base de données. Créez une base de données appelée verify-user et dans cette base de données, créez une table d'utilisateurs avec les attributs suivants :
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`)
)
Rien d'inhabituel sauf, peut-être, le jeton et les champs vérifiés, que j'expliquerai dans un instant.
Nous commençons maintenant avec la logique d'inscription proprement dite. J'aime généralement faire référence à la partie logique de mon application en tant que contrôleurs et c'est ce que je vais faire ici. Dans le dossier racine du projet, créez un dossier appelé controllers et inside controllers, créez un fichier appelé 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";
}
}
}
Si vous avez suivi mes tutoriels précédents, rien dans ce fichier ne devrait être nouveau pour vous. Mais pour le bien des débutants, je vais donner quelques explications.
La première chose est que nous commençons la session en utilisant session_start() car nous devrons stocker les informations de l'utilisateur connecté dans la session. Après le démarrage de la session, nous initialisons les variables $username et $email que nous utilisons dans nos formulaires, ainsi que le tableau $errors qui contiendra nos erreurs de validation de formulaire.
Ensuite, nous nous connectons à la base de données. Les deux instructions if suivantes qui suivent sont respectivement le code qui est exécuté lorsque l'utilisateur clique sur les boutons d'inscription ou de connexion. En cas d'inscription, nous vérifions que tous les champs obligatoires ont été remplis correctement et ce n'est qu'ensuite que nous procédons à l'enregistrement de l'utilisateur dans la base de données. Nous générons également un jeton (une chaîne unique et aléatoire) et l'enregistrons avec l'utilisateur en tant qu'attribut. Cela sera utilisé pour vérifier l'e-mail de l'utilisateur. Plus d'informations plus tard.
Étant donné que notre fichier authController.php est responsable de l'inscription et de la connexion, nous devons l'inclure tout en haut des pages signup.php et login.php car c'est là que les données du formulaire sont soumises. Comme ceci :
signup.php et login.php (tout en haut) :
<?php include 'controllers/authController.php' ?>
S'il y a des messages d'erreur dans le tableau $errors, nous devons les afficher sur le formulaire. Pour ce faire, ajoutez cette déclaration if dans votre formulaire directement sous le titre du formulaire pour les pages d'inscription et de connexion.
<!-- 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;?>
S'il n'y a pas d'erreurs, notre script procédera à l'enregistrement de l'utilisateur dans la base de données. Après avoir enregistré l'utilisateur dans la base de données, nous le connectons immédiatement. Dans notre cas, connecter un utilisateur signifie stocker ses données dans la session et c'est ce que nous venons de faire.
À ce stade, vous pouvez déjà vous inscrire et même vous connecter à un utilisateur. Mais après vous être connecté, vous serez redirigé vers la page index.php qui n'existe pas. Nous le créerons bientôt.
Dans authController.php, nous stockons les variables de message et de type dans la session à afficher dès que l'utilisateur s'est connecté. message est le texte réel du message tandis que le type est la classe de style Bootstrap qui formatera le message avec les couleurs en fonction de la valeur du type.
Ce message s'affiche une fois que l'utilisateur s'est connecté et il est affiché sur le fichier index.php. Créons maintenant ce fichier dans le dossier racine de notre projet.
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>
Cette page est destinée à être accessible uniquement aux utilisateurs connectés. C'est pourquoi, dans la partie supérieure du fichier, nous redirigeons l'utilisateur vers la page de connexion s'il n'est pas connecté. Quelque part au centre de la page, nous affichons le message. Après avoir affiché le message, nous désactivons le message et les variables de type car nous ne voulons pas qu'il reste sur la page même après que l'utilisateur a actualisé la page.
Enfin, au centre de la page, nous effectuons une vérification pour voir si l'utilisateur connecté a validé son adresse e-mail ou non. N'oubliez pas que nous avons ajouté la variable vérifiée dans la session lorsque nous avons connecté l'utilisateur. Si l'utilisateur a été vérifié, nous affichons le message "Je suis vérifié !!!" bouton pour qu'ils voient. S'ils ne sont pas vérifiés, nous leur informons du lien de vérification que nous avons envoyé à leur adresse e-mail et nous leur demandons de cliquer sur ce lien pour vérifier leur adresse e-mail.
Vérifier l'e-mail
Dans le fichier authController.php, nous avons utilisé un commentaire pour indiquer où nous enverrions l'e-mail de vérification à l'utilisateur en appelant la méthode sendVerificationEmail(). Allez dans le fichier authController.php et décommentez l'appel de fonction ainsi :
// TO DO: send verification email to user
sendVerificationEmail($email, $token);
Nous définirons cette fonction dans un autre fichier et inclurons ce fichier dans authController.php. Dans le dossier des contrôleurs, créez un fichier nommé sendEmails.php.
Avant d'ajouter du code dans ce fichier, permettez-moi de parler un peu de PHP SwiftMailer, la bibliothèque populaire pour l'envoi d'e-mails en PHP que nous allons utiliser dans ce projet pour envoyer des e-mails depuis localhost.
SwiftMailer est une bibliothèque populaire riche en fonctionnalités pour l'envoi d'e-mails dans des applications PHP.
Pour utiliser Swiftmailer, vous devez d'abord installer Composer. Une fois que vous avez installé composer, ouvrez votre terminal ou votre ligne de commande et accédez au dossier racine du projet et exécutez la commande suivante pour ajouter la bibliothèque Swift Mailer avec tous ses fichiers à notre projet :
composer require "swiftmailer/swiftmailer:^6.0"
Cela crée un dossier fournisseur à la racine de notre application contenant tout le code (classes) requis pour envoyer un e-mail et cela crée également un fichier composer.json à la racine de l'application qui ressemble à ceci :
{
"require": {
"swiftmailer/swiftmailer": "^6.0"
}
}
Ouvrez maintenant le fichier sendEmails.php que nous avons créé précédemment et écrivons la fonction 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;
}
}
La première instruction nécessite le fichier autoload.php dans ce fichier. Ce fichier autoload.php inclura automatiquement toutes les classes de la bibliothèque Swift Mailer dans le dossier du fournisseur que nous utilisons dans ce fichier.
Nous utilisons Gmail dans cet exemple. Vous pouvez donc remplacer SENDER_EMAIL et SENDER_PASSWORD par l'adresse et le mot de passe Gmail que vous souhaitez utiliser comme adresse e-mail de l'expéditeur. (L'adresse e-mail du destinataire est celle soumise via le formulaire).
Normalement, pour envoyer un e-mail à quelqu'un, vous devez vous connecter à votre compte Gmail avant de composer le courrier et de l'envoyer. C'est la même chose que la bibliothèque Swift Mailer. Ainsi, lorsque le destinataire ($userEmail) reçoit l'e-mail, c'est votre adresse Gmail (SENDER_EMAIL) qu'il verra comme e-mail d'envoi.
Nous appelons maintenant la fonction sendVerificationEmail() dans notre fichier authController.php mais nous avons défini la fonction dans le fichier sendEmails.php. Incluons le fichier sendEmails.php dans notre authController.php afin de rendre cette fonction disponible dans le fichier. En haut de authController.php, juste avant session_start(), ajoutez la ligne suivante :
require_once 'sendEmails.php';
C'est tout ce dont nous avons besoin, messieurs (et mesdames) pour envoyer un e-mail à notre utilisateur avec un lien de vérification d'e-mail. Mais nous travaillons sur localhost et Gmail bloquera toute tentative de connexion de Swift Mailer s'exécutant sur localhost.
Envoi d'e-mails depuis localhost
Si vous souhaitez que cela s'exécute sur localhost, vous devrez configurer votre compte Gmail pour accepter la connexion à partir d'applications moins sécurisées. Bien sûr, cela peut poser une certaine vulnérabilité sur votre compte Gmail, mais vous ne pouvez le faire que pendant la courte période dont vous avez besoin pour tester cette application sur localhost. Après le test, vous pouvez annuler le paramètre sur votre compte Gmail. Une fois votre application hébergée sur internet, vous travaillerez. Nous faisons cela uniquement parce que nous sommes sur localhost.
Vous pouvez être encore plus prudent et créer un autre compte Gmail uniquement à ces fins.
Connectez-vous donc à votre compte Gmail sur votre navigateur, accédez à https://myaccount.google.com/security#connectedapps et définissez la valeur "Autoriser les applications moins sécurisées" sur ON.
Vous pouvez désactiver cette option une fois que vous avez terminé de tester le projet sur localhost.
Avec cela, vous pourrez envoyer un e-mail depuis localhost avec un lien de vérification une fois que l'utilisateur s'est inscrit. Maintenant, regardez à nouveau la méthode sendVerificationEmail() et vous remarquerez que dans le corps de l'e-mail que nous envoyons à l'utilisateur, le jeton que nous avons généré pour cet utilisateur particulier (le jeton est unique) a été défini comme paramètre sur le lien de sorte que lorsque l'utilisateur clique sur le lien dans l'e-mail, il soit dirigé vers notre application sur une page appelée verify_email.php avec ce jeton dans l'URL. Comme ceci :
<a href="http://localhost/cwa/verify-user/verify_email.php?token=0a150966418fa3a694bcb3ab8fcacd2063a096accc0ee33c3e8c863538ee825c0b52f2e1535d0e1377558c378ba5fc3106eb">Verify Email!</a>
Nous pouvons donc obtenir ce jeton dans notre fichier verify_email.php comme ceci (calmez-vous, nous créerons bientôt ce fichier verify_email.php) :
$token = $_GET['token'];
Nous pouvons maintenant utiliser ce jeton pour récupérer l'utilisateur qui a ce jeton particulier (rappelez-vous que le jeton est unique) et si nous obtenons cet utilisateur, nous mettons à jour son enregistrement en changeant l'attribut vérifié en vrai dans la base de données. Ensuite, nous pouvons dire avec fierté que nous avons vérifié l'adresse e-mail de cet utilisateur.
Créons ce fichier verify_email.php dans le dossier racine de notre projet :
verification_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!";
}
Notez que définir la valeur de la valeur vérifiée sur 1 revient à la définir sur true, car dans la base de données MySQL, le type booléen est interprété comme tinyint.
Désormais, lorsque l'utilisateur clique sur le lien dans son e-mail et qu'il accède à cette page, il met à jour le statut vérifié de cet utilisateur sur vrai, le connecte et le redirige vers la page index.php. Dans la page d'index, après avoir vérifié l'utilisateur, vous remarquerez que le message d'avertissement conseillant à l'utilisateur de vérifier son adresse e-mail a maintenant disparu et à sa place, nous avons le "Je suis vérifié !!!" bouton qui n'est visible que pour les utilisateurs vérifiés.
Une toute dernière chose, sur la page index.php après la connexion de l'utilisateur, il y a un lien de déconnexion qui pointe vers un fichier logout.php censé déconnecter l'utilisateur. Créons ce fichier à la racine de notre application :
logout.php :
<?php
session_destroy();
unset($_SESSION['id']);
unset($_SESSION['username']);
unset($_SESSION['email']);
unset($_SESSION['verify']);
header("location: login.php");
Ainsi, en plus de pouvoir s'inscrire, vérifier ses e-mails, se connecter, l'utilisateur peut désormais également se déconnecter.
Conclusion
C'est à peu près tout avec l'enregistrement de l'utilisateur et la vérification des e-mails. Si vous avez des commentaires, des questions ou des mots d'encouragement, veuillez les laisser dans le commentaire ci-dessous. Et s'il vous plaît, n'oubliez pas de partager ce message ou de recommander ce site à vos amis si vous l'avez trouvé utile. ça m'encourage beaucoup !
Bonne journée !