PHPBuilder - E-mail Verification in PHP

RSS Twitter

E-mail Verification in PHP

by: Voja Janjic
April 18, 2016

One of the most common security features during the user registration process is e-mail verification. It is important to create it according to industry best practices in order to avoid potential security risks. Let's discuss these best practices and see how to create e-mail verification in PHP.


We will start with the registration form:


<form method="post" action="">
	<fieldset class="form-group">
		<label for="fname">First Name:</label>
		<input type="text" name="fname" class="form-control" required />

    <fieldset class="form-group">
		<label for="lname">Last Name:</label>
		<input type="text" name="lname" class="form-control" required />

    <fieldset class="form-group">
		<label for="email">Last name:</label>
		<input type="email" name="email" class="form-control" required />

    <fieldset class="form-group">
		<label for="password">Password:</label>
		<input type="password" name="password" class="form-control" required />

    <fieldset class="form-group">
		<label for="cpassword">Confirm Password:</label>
		<input type="password" name="cpassword" class="form-control" required />

        <button type="submit" class="btn">Register</button>


And with the following database structure:


	`fname` VARCHAR(255) ,
	`lname` VARCHAR(255) ,
	`email` VARCHAR(50) ,
	`password` VARCHAR(50) ,
	`is_active` INT(1) DEFAULT '0',
	`verify_token` VARCHAR(255) ,
	`created_at` TIMESTAMP,
	`updated_at` TIMESTAMP,


Once the form has been submitted, we need to validate the input and create a new user:


// Validation rules
$rules = array(
    'fname' => 'required|max:255',
    'lname' => 'required|max:255',
	'email' => 'required',
	'password' => 'required|min:6|max:20',
	'cpassword' => 'same:password'

$validator = Validator::make(Input::all(), $rules);

// If input not valid, go back to registration page
if($validator->fails()) {
	return Redirect::to('registration')->with('error', $validator->messages()->first())->withInput();

$user = new User();
$user->fname = Input::get('fname');
$user->lname = Input::get('lname');
$user->password = Input::get('password');

// You will generate the verification code here and save it to the database

// Save user to the database
if(!$user->save()) {
	// If unable to write to database for any reason, show the error
	return Redirect::to('registration')->with('error', 'Unable to write to database at this time. Please try again later.')->withInput();

// User is created and saved to database
// Verification e-mail will be sent here

// Go back to registration page and show the success message
return Redirect::to('registration')->with('success', 'You have successfully created an account. The verification link has been sent to e-mail address you have provided. Please click on that link to activate your account.'); 


Upon registration, the user's account remains inactive until the e-mail has been verified. This feature confirms that the user is the owner of the entered e-mail address and helps prevent spam, unauthorized e-mail usage and information leaks.


The process is quite simple  —  when a new user is created, an e-mail containing the verification link is sent to the e-mail address entered during the registration process. The user will not be able to login and use the Web application until he/she clicks on the verification link and confirms the e-mail address.


There are a few things to note regarding the verification link. It should contain a randomly generated token that should be long enough and valid for a specific amount of time in order to make brute-force attacks infeasible. Also, the user identifier should be included, so that a potential attack could not brute-force across multiple accounts.


Let's see how to generate the verification link in practice:


// We will generate a random 32 alphanumeric string
// It is almost impossible to brute-force this key space
$code = str_random(32);
$user->confirmation_code = $code; 


Once is it generated and saved to the database, send it to the user:


Mail::send('', array('code' => $code, 'id' => $user->id), function($message)
$message->from('', '')->to($user->email, $user->fname . ' ' . $user->lname)->subject(' E-mail confirmation');


The content of verification e-mail:


<!DOCTYPE html>
<html lang="en-US">
		<meta charset="utf-8" />

		<p style="margin:0">
			Please confirm your e-mail address by clicking the following link:
			<a href="<?php echo $code; ?>&user=<?php echo $id; ?>"></a>


Now let's check to make sure it is valid:


$user = User::where('id', '=', Input::get('user'))
			->where('is_active', '=', 0)
			->where('verify_token', '=', Input::get('code'))
			->where('created_at', '>=', time() - (86400 * 2))

if($user) {
	$user->verify_token = null;
	$user->is_active = 1;

	if(!$user->save()) {
		// If unable to write to database for any reason, show the error
		return Redirect::to('verify')->with('error', 'Unable to connect to database at this time. Please try again later.');

	// Show the success message
	return Redirect::to('verify')->with('success', 'You account is now active. Thank you.');

// Code not valid, show error message
return Redirect::to('verify')->with('error', 'Verification code not valid.'); 



The code shown in this tutorial is for educational purposes and is not thoroughly tested. Please test it before using it in a live Web application. It is written in Laravel framework, but can be easily adjusted to any other PHP framework. Also, the verification code has a time limit of 48 hours and after that it will expire. It would be good to implement a cron job that will remove inactive users with expired verification codes from time to time.



Comment and Contribute

Your comment has been submitted and is pending approval.

Voja Janjic



(Maximum characters: 1200). You have characters left.