Welcome to a tutorial on how to create a user registration form with email verification, using PHP and MySQL. So you have decided to open up your website for user registration?
A simplified user registration system consists of the following basic components:
- A database to store registered users.
- A PHP library to deal with the registration process.
- An HTML registration form and the confirmation page itself.
Let us walk through the exact details on how to do all of these in this guide – Read on!
TABLE OF CONTENTS
USER REGISTRATION WITH EMAIL VERIFICATION
All right, let us now get into the steps of creating a simple user registration system with email verification.
PAR 1) USERS DATABASE TABLE
CREATE TABLE `users` (
`user_id` bigint(20) NOT NULL,
`user_email` varchar(255) NOT NULL,
`user_password` varchar(255) NOT NULL,
`user_activate` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `users`
ADD PRIMARY KEY (`user_id`),
ADD UNIQUE KEY `user_email` (`user_email`);
ALTER TABLE `users` MODIFY `user_id` bigint(20) NOT NULL AUTO_INCREMENT;
Field | Description |
user_id |
Primary key, auto-increment. |
user_email |
The user’s email address. Unique field to prevent multiple registrations. |
user_password |
The password. |
user_activate |
Used to hold the “activation key”. If this field is null, then the account is already activated. |
Just a simple table with 4 fields, feel free to add more of your own as required – Name, address, etc…
P.S. If you have an existing user table, it will probably make sense to just add a user_activate
field.
PART 2) PHP USER LIBRARY
<?php
class Users {
// (A) CONSTRUCTOR - CONNECT DATABASE
private $pdo = null;
private $stmt = null;
public $error = null;
function __construct () {
$this->pdo = new PDO(
"mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET,
DB_USER, DB_PASSWORD, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
}
// (B) DESTRUCTOR - CLOSE CONNECTION
function __destruct () {
if ($this->stmt !== null) { $this->stmt = null; }
if ($this->pdo !== null) { $this->pdo = null; }
}
// (C) HELPER - RUN SQL QUERY
function query ($sql, $data=null) : void {
$this->stmt = $this->pdo->prepare($sql);
$this->stmt->execute($data);
}
// (D) GET USER BY ID OR EMAIL
function get ($id) {
$this->query(
sprintf("SELECT * FROM `users` WHERE `user_%s`=?", is_numeric($id)?"id":"email"),
[$id]
);
return $this->stmt->fetch();
}
// (E) REGISTER NEW USER
function register ($email, $pass) {
// (E1) CHECK IF USER REGISTERED
// @TODO - WHAT TO DO IF THERE IS AN EXISTING ACTIVATION?
// ALLOW USER TO GENERATE NEW TOKEN & EMAIL AFTER SOME TIME?
// MANUAL CONTACT ADMIN?
$check = $this->get($email);
if (is_array($check)) {
$this->error = isset($check["user_activate"])
? "$email already has a pending activation."
: "$email is already registered." ;
return false;
}
// (E2) INSERT INTO DATABASE
$token = md5(date("YmdHis") . $email);
$this->query(
"INSERT INTO `users` (`user_email`, `user_password`, `user_activate`) VALUES (?,?,?)",
[$email, password_hash($pass, PASSWORD_DEFAULT), $token]
);
$this->lastID = $this->pdo->lastInsertId();
// (E3) SEND CONFIRMATION EMAIL
// @TODO - CHANGE TO YOUR OWN MESSAGE + URL!
$subject = "Confirm your email";
$msg = sprintf(
"Visit this <a href='http://localhost/3b-confirm.php?i=%u&h=%s'>link</a> to complete your registration.",
$this->lastID, $token
);
$head = implode("\r\n", ["MIME-Version: 1.0", "Content-type: text/html; charset=utf-8"]);
if (@mail($email, $subject, $msg, $head)) { return true; }
else {
$this->error = "Error sending out email";
return false;
}
}
// (F) VERIFY REGISTRATION
function verify ($id, $hash) {
// (F1) GET + CHECK THE USER
$user = $this->get($id);
if ($user === false) {
$this->error = "User not found.";
return false;
}
if (!isset($user["user_activate"])) {
$this->error = "Account already activated.";
return false;
}
if ($user["user_activate"] != $hash) {
$this->error = "Invalid token.";
return false;
}
// (F2) ACTIVATE ACCOUNT IF OK
$this->query(
"UPDATE `users` SET `user_activate`=NULL WHERE `user_id`=?",
[$id]
);
// (F3) SEND WELCOME MESSAGE IF YOU WANT
// mail ($user["user_email"], "WELCOME!", "Welcome message here.");
return true;
}
}
// (G) DATABASE SETTINGS - CHANGE TO YOUR OWN!
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHARSET", "utf8mb4");
define("DB_USER", "root");
define("DB_PASSWORD", "");
// (H) NEW USER OBJECT
$USR = new Users();
Holy cow. That is a lot of code, but keep calm and look closely.
- (A, B, H) When
$USR = new Users()
is created, the constructor will connect to the database. The destructor closes the connection. - (C)
query()
Helper function to run an SQL query. - (D, E, F) There are only 3 functions for user registration!
get()
Get user by ID or email.register()
Step 1 of the registration process. Generates a random “activation key”, then sends the activation link to the user email.verify()
Step 2 of the registration process. After the user clicks on the link in the email, we verify the “activation key” and complete the registration process.
- (G) Database settings. Remember to change to your own.
PART 3) HTML PAGES
3A) REGISTRATION FORM
<!-- (A) REGISTRATION FORM -->
<form method="post">
<input type="email" name="email" placeholder="Email" required>
<input type="password" name="pass" placeholder="Password" required>
<input type="password" name="cpass" placeholder="Confirm Password" required>
<input type="submit" value="Register!">
</form>
<?php
// (B) PROCESS SUBMITTED REGISTRATION FORM
if (isset($_POST["email"])) {
require "2-lib-user.php";
echo "<div class='note'>";
echo $USR->register($_POST["email"], $_POST["pass"], $_POST["cpass"])
? "Check your email and click on the activation link"
: $USR->error ;
echo "</div>";
}
?>
This page is pretty self-explanatory. The user fills in the registration form, we use register()
to process and send out the activation link.
STEP 3B) CONFIRMATION PAGE
<div class="note"><?php
require "2-lib-user.php";
echo $USR->verify($_GET["i"], $_GET["h"])
? "Thank you! Account has been activated."
: $USR->error ;
?></div>
Once again, this page is self-explanatory. The user accesses the activation link and lands on this page – We verify the activation key and complete the process.
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
SUPPORT
600+ free tutorials & projects on Code Boxx and still growing. I insist on not turning Code Boxx into a "paid scripts and courses" business, so every little bit of support helps.
Buy Me A Meal Code Boxx eBooks
EXAMPLE CODE DOWNLOAD
Click here for the source code on GitHub gist, just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
EXTRA BITS & LINKS
That’s it for this tutorial. Here are a few small extras and links that may help with your project.
BAREBONES START
Before the angry ugly troll things start to spit acid, this is but a barebones example. Some work still needs to be done before it is worthy of a production system.
- A proper login page (links below).
- An option to resend the confirmation email should the first one fails.
- Maybe an auto-timeout mechanism, so users can request another confirmation after some time.
LINKS & REFERENCES
- Password hash and Password verify – PHP
- How To Import SQL Files – Code Boxx
- How To Create a Login Page – Code Boxx
- Problems Sending Out Emails? – Code Boxx
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you with your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!
is it possible with PHPMailer in php? I don’t have access to the php.ini to put my smpt server, could you show me how to change the code for phpmailer?
https://code-boxx.com/send-email-php/
Thank you so much, very useful!
Thanks so much. But i encounter a little problem, a confirmation email has been sent after registration but there’s no link to click and verify pls help
Small update to 2-user-core.php, E5 – Added HTML mail headers.
thank you . how to avoid sending to junk mail this script
Nothing to do with the script, it’s the spam filter. It is also common for most shared hosting to have a low reputation (marked as a possible email spambot).
This is really helpful! Thanks a lot.
ps. also your replies to some of the comments is very funny 🙂
Glad it helped. Credits to the people who asked funny questions.
Many thanks ! Amazing blog