Jeg har allerede skrevet et blogindlæg om oprettelse af et komplet brugerregistrering og login-system ved hjælp af PHP og MySQL, men jeg inkluderede ikke e-mailbekræftelse.
Denne tutorial er lidt ligesom en opdatering af den forrige tutorial. Ud over at være i stand til at registrere, logge ind og logge ud af sin konto, vil en bruger også få tilsendt en bekræftelses-e-mail til sin e-mailadresse med et link, hvor de kan klikke på og få sin e-mailadresse bekræftet.
På de fleste applikationer, du skal bygge, er det vigtigt at tilføje en e-mail-bekræftelsesfunktion af mange årsager:du vil måske sende en e-mail senere til brugeren og vil være sikker på, at de vil se den; eller brugeren glemmer muligvis sin adgangskode og skal nulstille den, og for at gøre dette skal vi sende dem et link til nulstilling af adgangskode via e-mail; der er mange andre grunde, men du forstår pointen.
I dette system, vi bygger i dag, vil brugere, der ikke har bekræftet deres e-mail, ikke være i stand til at udføre visse handlinger (jeg vil bare bruge en simpel demonstration, såsom at se en knap. Kun verificerede brugere vil kunne se den knap).
For at begynde skal du oprette et nyt PHP-projekt med navnet verify-user, og i denne mappe skal du oprette to filer:signup.php og 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>
Det er bare en simpel HTML/CSS-fil. Det eneste, der er værd at bemærke, er, at vi bruger Bootstrap 4 CSS-rammeværket til at style vores side. Du kan bruge enhver anden stylingramme efter eget valg eller skrive din egen CSS, hvis du vil.
Umiddelbart efter Bootstrap CSS inkluderer vi en main.css-fil til tilpasset styling. Lad os oprette den fil nu. I programmets rodmapp skal du oprette en fil kaldet 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;
}
På den første linje i denne fil importerer og bruger vi nogle Google-skrifttyper for at få vores skrifttyper til at se smukkere ud.
Vend nu til filen login.php og gør en lignende ting.
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>
På din browser, gå til http://localhost/cwa/verify-user/signup.php, du vil se en smuk tilmeldingsformular (samme for login). Ignorer fejlene i indtastningsfelterne, det ordner vi snart.
Indtil videre, lad os sætte databasen op. Opret en database kaldet verify-user, og i denne database skal du oprette en brugertabel med attributter som følger:
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`)
)
Intet usædvanligt undtagen måske tokenet og de verificerede felter, som jeg vil forklare om et øjeblik.
Nu begynder vi med selve tilmeldingslogikken. Jeg plejer at henvise til den logiske del af min applikation som controllerne, og det er, hvad jeg vil gøre her. I projektets rodmapp skal du oprette en mappe kaldet controllere og inde i controllere, oprette en fil kaldet authController.php.
controllere/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";
}
}
}
Hvis du har fulgt mine tidligere tutorials, så burde intet i denne fil være nyt for dig. Men af hensyn til nybegyndere, skal jeg forklare noget.
Den første ting er, at vi starter sessionen med session_start(), da vi bliver nødt til at gemme loggede brugeroplysninger i sessionen. Efter at have startet sessionen initialiserer vi variablerne $username og $email, som vi bruger i vores formularer, og også $errors-arrayet, som vil indeholde vores formularvalideringsfejl.
Dernæst opretter vi forbindelse til databasen. De næste to if-sætninger, der følger, er henholdsvis den kode, der bliver udført, når brugeren klikker på tilmeldings- eller login-knapperne. I tilfælde af tilmelding kontrollerer vi, at alle påkrævede felter er udfyldt korrekt, og først derefter fortsætter vi med at gemme brugeren i databasen. Vi genererer også et token (en unik, tilfældig streng) og gemmer den med bruger som en attribut. Dette vil blive brugt til at bekræfte brugerens e-mail. Mere om det senere.
Da vores authController.php-fil er ansvarlig for tilmelding og login, er vi nødt til at inkludere den helt øverst på signup.php- og login.php-siderne, fordi det er der, formulardataene sendes til. Sådan:
signup.php og login.php (helt øverst):
<?php include 'controllers/authController.php' ?>
Hvis der er nogen fejlmeddelelser i $errors-arrayet, skal vi vise dem på formularen. For at gøre det skal du tilføje denne if-erklæring i din formular direkte under formulartitlen for både tilmeldings- og loginsider.
<!-- 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;?>
Hvis der ikke er nogen fejl, vil vores script fortsætte med at gemme bruger i databasen. Efter at have gemt brugeren i databasen, logger vi dem ind med det samme. I vores tilfælde betyder det at logge en bruger på at gemme deres data i sessionen, og det er det, vi lige har gjort.
På dette tidspunkt kan du allerede registrere og endda logge på en bruger. Men efter at have logget ind, vil du blive omdirigeret til siden index.php, som ikke eksisterer. Vi laver det snart.
I authController.php gemmer vi meddelelses- og typevariabler i sessionen for at blive vist, så snart brugeren er logget ind. meddelelsen er den faktiske tekst i meddelelsen, mens typen er Bootstrap-stylingklassen, der vil formatere meddelelsen med passende farver afhængigt af typeværdien.
Denne besked vises, efter at brugeren er logget ind, og den vises på filen index.php. Lad os oprette den fil nu i rodmappen i vores projekt.
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>
Denne side er beregnet til kun at være tilgængelig for loggede brugere. Derfor omdirigerer vi i den øverste del af filen brugeren til login-siden, hvis de ikke er logget ind. Et sted i midten af siden viser vi beskeden. Efter at have vist meddelelsen, deaktiverer vi meddelelsen og skriver variabler, fordi vi ikke ønsker, at den skal forblive der på siden, selv efter at brugeren har opdateret siden.
Til sidst udfører vi i midten af siden en kontrol for at se, om den loggede bruger har verificeret sin e-mailadresse eller ej. Husk, at vi tilføjede den verificerede variabel i sessionen, da vi loggede brugeren ind. Hvis brugeren er blevet bekræftet, viser vi "Jeg er bekræftet!!!" knap for dem at se. Hvis de ikke er bekræftet, fortæller vi dem om det bekræftelseslink, vi sendte til deres e-mailadresse, og vi beder dem om at klikke på det link for at bekræfte deres e-mail.
Bekræft e-mail
I authController.php-filen brugte vi en kommentar til at angive, hvor vi ville sende bekræftelses-e-mailen til brugeren ved at ringe til sendVerificationEmail(). Gå til filen authController.php, og fjern kommentaren til funktionskaldet således:
// TO DO: send verification email to user
sendVerificationEmail($email, $token);
Vi vil definere denne funktion i en anden fil og inkludere den fil i authController.php. Opret en fil med navnet sendEmails.php.
i mappen controllereFør vi tilføjer nogen kode i denne fil, lad mig sige lidt om PHP SwiftMailer, det populære bibliotek til at sende e-mails i PHP, som vi vil bruge i dette projekt til at sende e-mails fra localhost.
SwiftMailer er et populært funktionsrigt bibliotek til at sende e-mails i PHP-applikationer.
For at bruge Swiftmailer skal du først installere Composer. Når du har installeret composer, skal du åbne din terminal eller kommandolinje og navigere til rodmappen for projektet og køre følgende kommando for at tilføje Swift Mailer-biblioteket med alle dets filer til vores projekt:
composer require "swiftmailer/swiftmailer:^6.0"
Dette opretter en leverandørmappe i roden af vores applikation, der indeholder al den kode (klasser), der kræves for at sende en e-mail, og den opretter også en composer.json-fil i applikationens rod, der ser sådan ud:
{
"require": {
"swiftmailer/swiftmailer": "^6.0"
}
}
Åbn nu sendEmails.php-filen, vi oprettede tidligere, og lad os skrive funktionen 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;
}
}
Den første sætning kræver autoload.php-filen i denne fil. Denne autoload.php-fil vil automatisk inkludere alle klasserne fra Swift Mailer-biblioteket i leverandørmappen, som vi bruger i denne fil.
Vi bruger Gmail i dette eksempel. Så du kan erstatte SENDER_EMAIL og SENDER_PASSWORD med din Gmail-adresse og adgangskode, som du vil bruge som afsenderens e-mailadresse. (Modtagerens e-mailadresse er den, der er indsendt via formularen).
Normalt, for at sende en e-mail til nogen, skal du logge ind på din Gmail-konto, før du skriver e-mailen og sender. Det er den samme slags, som Swift Mailer-biblioteket gør. Så når modtageren ($userEmail) modtager e-mailen, er det din Gmail-adresse (SENDER_EMAIL), de vil se som den afsendende e-mail.
Nu kalder vi sendVerificationEmail()-funktionen i vores authController.php-fil, men vi definerede funktionen inde i filen sendEmails.php. Lad os inkludere sendEmails.php-filen i vores authController.php for at gøre denne funktion tilgængelig i filen. Øverst i authController.php, lige før session_start(), tilføj følgende linje:
require_once 'sendEmails.php';
Det er alt, vi har brug for, mine herrer (og mine damer) for at sende en e-mail til vores bruger med et e-mailbekræftelseslink. Men vi arbejder på localhost, og Gmail vil blokere alle loginforsøg fra Swift Mailer, der kører på localhost.
Sender e-mail fra localhost
Hvis du vil have dette til at køre på localhost, skal du konfigurere din Gmail-konto til at acceptere login fra mindre sikre apps. Selvfølgelig kan dette udgøre en vis sårbarhed på din Gmail-konto, men du kan kun gøre det i den korte tid, du har brug for for at teste denne applikation på localhost. Efter test kan du fortryde indstillingen på din Gmail-konto. Når din ansøgning er blevet hostet på internettet, vil du arbejde. Vi gør kun dette, fordi vi er på localhost.
Du kan være endnu mere forsigtig og kun oprette en anden Gmail-konto til sådanne formål som disse.
Så log ind på din Gmail i din browser, gå til https://myaccount.google.com/security#connectedapps og skift værdien 'Tillad mindre sikre apps' til TIL.
Du kan slå dette fra, når du er færdig med at teste projektet på localhost.
Med dette vil du være i stand til at sende en e-mail fra localhost med bekræftelseslink, når brugeren tilmelder sig. Se nu på sendVerificationEmail()-metoden igen, og du vil bemærke, at i brødteksten af den e-mail, vi sender til brugeren, er det token, vi genererede for den pågældende bruger (tokenet er unikt) blevet sat som en parameter på linket så når brugeren klikker på linket i e-mailen, vil de blive dirigeret til vores applikation på en side kaldet verify_email.php med det token på webadressen. Sådan:
<a href="http://localhost/cwa/verify-user/verify_email.php?token=0a150966418fa3a694bcb3ab8fcacd2063a096accc0ee33c3e8c863538ee825c0b52f2e1535d0e1377558c378ba5fc3106eb">Verify Email!</a>
Så vi kan få dette token i vores verify_email.php sådan her (rolig, vi opretter snart denne verify_email.php):
$token = $_GET['token'];
Vi kan nu bruge dette token til at hente den bruger, der har dette særlige token (husk, at tokenet er unikt), og hvis vi får den bruger, opdaterer vi deres registrering og ændrer den verificerede attribut til sand i databasen. Så kan vi stolt sige, at vi har bekræftet brugerens e-mailadresse.
Lad os oprette denne verify_email.php-fil i rodmappen i vores projekt:
verify_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!";
}
Bemærk, at indstilling af værdien for verificeret værdi til 1 er det samme som at sætte den til sand, da i MySQL-databasetypen fortolkes Boolean som lillebitte.
Når brugeren nu klikker på linket i deres e-mail, og den fører dem til denne side, opdaterer den brugerens verificerede status til sand, logger dem ind og omdirigerer dem til siden index.php. På indekssiden, efter at have bekræftet brugeren, vil du bemærke, at advarselsmeddelelsen, der råder brugeren til at bekræfte deres e-mail-adresse, nu er væk, og i stedet har vi "Jeg er bekræftet!!!" knap, der kun er synlig for bekræftede brugere.
En allersidste ting, på index.php-siden efter at have logget bruger ind, er der et logout-link, som peger på en logout.php-fil, som skal logge brugeren ud. Lad os oprette den fil i roden af vores applikation:
logout.php:
<?php
session_destroy();
unset($_SESSION['id']);
unset($_SESSION['username']);
unset($_SESSION['email']);
unset($_SESSION['verify']);
header("location: login.php");
Så udover at kunne tilmelde sig, bekræfte e-mail, logge på, kan brugeren nu også logge ud.
Konklusion
Så det handler om det med brugerregistrering og e-mailbekræftelse. Hvis du har kommentarer, spørgsmål eller opmuntrende ord, bedes du efterlade dem i kommentaren nedenfor. Og husk venligst at dele dette opslag eller anbefale dette websted til dine venner, hvis du fandt det nyttigt. Det opmuntrer mig meget!
Hav en god dag!