PHP registration form is an essential part for most WebApps such as student system, and any kind of member system. However, to prevent registration attempts from fake emails, some systems often ask for providing emails to be verified.
Whole solution about registration can include several stages. First, data validation is must. Next, we introduce CRUD operations on MySQL in some stages. Finally, you will learn what data in email the system sends and how account activation is processed.
All codes here are not complicated, so you can easily understand even though you are still students in school. To benefit your learning, we will provide you download link to a zip file thus you can get all source codes for future usage.
Estimated reading time: 10 minutes
EXPLORE THIS ARTICLE
TABLE OF CONTENTS
BONUS
Source Code Download
We have released it under the MIT license, so feel free to use it in your own project or your school homework.
Download Guideline
- Prepare HTTP server such as XAMPP or WAMP in your windows environment.
- Download and unzip into a folder that http server can access.
STAGE 1
Client-Site Validation
A few portion in the beginning tell us that what data fields HTML and CSS generate help to get user data. Subsequently, routine functions validate on these data to make sure data format, and even email format. If having errors, PHP registration form stops sending messages, thus reduces transmission traffic load.
Basic HTML & CSS
<?php
require "config.php";
?>
<!DOCTYPE html>
<html>
<head>
<?php head(); ?>
</head>
<body>
<div> </div>
<div class="container">
<div class="user-title">
<h4>Simple REGISTER System</h4>
</div>
<div class="user-data">
<label>Name:</label>
<input id="name" type="text" required value="tim" />
<label>Email:</label>
<input id="email" type="email" required value="tim@abc.com" />
<label>Password:</label>
<input id="pass" type="password" required value="123456" />
<label>Confirm Password:</label>
<input id="cpass" type="password" required value="123456" />
<input id="send-register" type="submit" value="Register"/>
</div>
<div class="alter">
<div> </div>
<input id="login" type="submit" value="Login"/>
<div>Already <br>have account</div>
</div>
</div>
<div> </div>
</body>
</html>
<script>
$(document).ready(function() {
$('input#send-register').on("click", function() {
data = {
name:$('input#name').val(),
email:$('input#email').val(),
pass:$('input#pass').val(),
cpass:$('input#cpass').val(),
};
if(verify(data)) sendout("signUp", data);
});
$('input#login').on("click", function() {
window.location.href="login.php";
});
});
</script>
Each input field is generated with one of 3 types – text, email and password. Defining type="email"
basically checks if @ exists, while verify(data)
validates more features. Another type definition type="password"
hides each character user entered.
At upper part, you can see the <?php head(); ?>
with which a set of header includings is replaced. This is a good coding skill as WordPress used. To inspect it, you can find function head()
in func.php.
The lower part contains jQuery codes reading data from input fields, and sending them out after validation. For the CSS part not shown here, please refer to style.css, which is written with RWD (Responsive Web Design).
Validate Data & Email Format
function verify(d) {
error="";
// name
if (d.name=="") error += "Your name is required\n";
// email
if (d.email!=undefined) {
var pattern = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (!pattern.test(d.email.toLowerCase()))
error += "Please enter a valid email\n";
}
// password
if (d.cpass!=undefined)
if (d.pass.length<6) error += "Passwords must be at least 6 characters\n";
else if (d.pass.length<6 || d.cpass.length<6)
error += "Passwords must be at least 6 characters\n";
else if (d.pass != d.cpass)
error += "Passwords do not match\n";
// report errors
if (error!="") { console.log(error); alert(error); return false; }
else return true;
}
Client-site validation blocks message transmission to server site if exception happens in order to reduce traffic load. For example, below shows some kinds of validation.
d.name
: majorly checking if non-empty.d.email
: validation for more email features.d.pass
,d.cpass
: validation about length and consistance.
STAGE 2
Server-Site Validation
PHP registration form at client site had already validated data, but why is it necessary for server site to do it again? If unfortunately, hacked client-site codes attacks with fake messages, the assumed more secure server-site PHP codes can defend and reject all ill intent. Suppose PHP scripts are more safe in general.
AJAX Controller
function actionRegister ($d) {
global $dbconfig, $tblname;
$error = "";
/* server-side verify */
// name
if ($d['name']=="") {
$error .= "svr-Please provide a valid name".PHP_EOL;
}
// email
if (!filter_var($d['email'], FILTER_VALIDATE_EMAIL)) {
$error .= "svr-Please provide a valid email".PHP_EOL;
}
// password
if (strlen($d['pass'])<6 || strlen($d['cpass'])<6) {
$error .= "svr-Password must be at least 6 characters".PHP_EOL;
} else if ($d['pass'] != $d['cpass']) {
$error .= "svr-Passwords do not match".PHP_EOL;
}
.....
Registration is started by an AJAX form with jQuery script $.post(...)
at client site, so server site will get the $d
equal to $_POST['data']
transmitted by method of HTTP POST.
Besides checking non-emtpy name and length of password, a PHP function filter_var($d['email'], FILTER_VALIDATE_EMAIL)
can validate email format directly.
STAGE 3
Already Existed?
We don’t allow to accept registration with the same email or name. To access database for checking this, we use a PHP CRUD class here. In the stage, you will learn only the READ operation at first.
PHP CRUD Class
<?php
/* A Simple DB Class
e.g.
$conf=array(
'host' => 'localhost',
'dbname' => 'mydb',
'username' => 'myuser',
'password' => '12345678',
'charset' => 'utf8',
);
*/
class DB {
private $conn = null;
public $error = "";
public $rowCount;
function __construct($conf) {
// initiate by connect to db
try {
$str = "mysql:host=" . $conf['host'] . ";dbname=" . $conf['dbname'] . ";charset=" . $conf['charset'];
$this->conn = new PDO($str, $conf['username'], $conf['password'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]);
return true;
}
catch (Exception $ex) {
print_r($ex);
die();
}
}
function execute($sql, $params=null) {
// insert or update or delete
try {
$stmt = $this->conn->prepare($sql);
$stmt->execute($params);
$this->rowCount = $stmt->rowCount();
return true;
}
catch (Exception $ex) {
$this->error = $ex->getMessage();
return false;
}
}
function fetchAll($sql, $params=null, $all=true) {
// select
try {
$stmt = $this->conn->prepare($sql);
$stmt->execute($params);
$this->rowCount = $stmt->rowCount();
if ($all)
return $stmt->fetchAll();
else
return $stmt->fetch();
}
catch (Exception $ex) {
$this->error = $ex->getMessage();
return false;
}
}
function fetch($sql, $params=null) {
// select
return $this->fetchAll($sql, $params, false);
}
} // DB class
?>
This class utilizes PDO, instead of MySQLi, to link to MySQL. Both PDO class and PDOStatement class in PHP act as important roles in the class. To read more about its complete usage, please refer to another article Small PHP CRUD Class for OOP using MySQL.
CRUD Operation – READ
.....
/* database */
if ($error=="") {
$db = new DB($dbconfig);
$sql = "SELECT * FROM {$tblname} WHERE name=? OR email=? ";
$stmt = $db->fetch($sql, [$d['name'], $d['email']] );
if (!$stmt) {
.....
} else {
$error .= "The name or email already registered".PHP_EOL;
}
if ($db->error != "") $error .= $db->error . PHP_EOL;
}
.....
This class give a method $stmt = $db->fetch(...)
to get only one record as result. Once it returns TRUE, meaning that this name or email has already existed in the registration database. We are listing table schema as below for clarification.
Table Schema
CREATE TABLE `users` (
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`pass` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
`emailchk` varchar(10) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Y or N',
`vcode` varchar(10) COLLATE utf8_unicode_ci NOT NULL COMMENT 'verification code',
`register` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`login` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`logout` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `users`
ADD PRIMARY KEY `name` (`name`),
ADD KEY `email` (`email`);
field | description |
---|---|
name | user name or identification |
user email address | |
pass | user password |
emailchk | “Y” means user email is verified, otherwise “N” |
vcode | verification code in the sending email |
register | date and time of registration |
login | date and time of login |
logout | date and time of logout |
STAGE 4
Add New User
So as to activate account by email confirmaton, it needs to create a record with not only name, but with verification code also. Keep a check flag and verification code in database, we can make sure whether the message from email is right or not.
Create New Record with Verification Code
.....
$stmt = $db->fetch($sql, [$d['name'], $d['email']] );
if (!$stmt) {
$sql = "INSERT INTO {$tblname} (name, email, pass, emailchk, vcode) VALUES (?, ?, ?, ?, ?)";
$verify_code = rand(100000, 999999);
$params = array($d['name'], $d['email'], $d['pass'], 'N', $verify_code);
$db->execute($sql, $params);
} else {
$error .= "The name or email already registered".PHP_EOL;
}
.....
Beside saving name, email, pass
as a record in database, we generate $verify_code
to set vcode
, and as well let emailchk
be 'N'
by default. Eventually, $db->execute($sql, $params)
insert a row into database through PHP CRUD class.
STAGE 5
Send Email
While writing email content, make sure to include critical verification code, and MD5 hash of a string within the provided URL for clicking. Thus incoming checking will be refered as success. Most importantly, SMTP setting had better direct to more stable servers.
Send Email with Verification Code
if ($error=="") {
$url = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?action=emailConfirm&name='.
$d['name'].'&code='.$verify_code.'&key='.md5($d['name']);
$to = $d['email'];
$subject = 'Please Confirm Account of Our Sample System';
$message = 'Welcome, '.$d['name']. PHP_EOL .
'You have created an account on our sample system:' . PHP_EOL .
PHP_EOL .
'User Name: '.$d['name']. PHP_EOL .
'Email: '.$d['email']. PHP_EOL .
'Please activate your account by clicking this URL.' . PHP_EOL .
$url . PHP_EOL;
$headers = 'From: webmaster@example.com' . PHP_EOL .
'To: ' . $d['email'] . PHP_EOL;
mail($to, $subject, $message, $headers); // Note that SMTP=ms10.hinet.net in php.ini
$notice="The confirmation email has been sent.\nPlease click the link to activate this account.";
}
From the very first beginning, be careful about the important PHP Predefined Variables $_SERVER['HTTP_HOST']
and $_SERVER['PHP_SELF']
. They help locate the URL to which email confirmation can go back.
In addition to code=$verify_code
, by calculating MD5 hash of a string, key=md5($d['name'])
play key role for verification at next stage. At the time of sending email out, if you did it but got SMTP exception, next paragraph might help.
SMTP Setting on Windows
[mail function]
; For Win32 only.
; http://php.net/smtp
SMTP=ms10.hinet.net
; http://php.net/smtp-port
smtp_port=25
In case that sending email failed on Windows, you may forget specifying a SMTP server in php.ini. Following the example as above, finish it and then restart HTTP service to resume your testing.
STAGE 6
Email Confirmation
So far, PHP registration form has accepted a user request, but not yet activate it. Once user clicking on the URL in email, afterwards, verification result will update some fields in database so as to allow user’s login.
Check Verification Code
function actionEmailConfirm() {
// Email correct, enable this account
global $dbconfig, $tblname;
$db = new DB($dbconfig);
$sql = "SELECT * FROM {$tblname} WHERE name=?";
$stmt = $db->fetch($sql, [$_GET['name']] );
if ($stmt)
if (($stmt['vcode'] == $_GET['code']) and (md5($_GET['name']) == $_GET['key']) ) {
$sql = "UPDATE {$tblname} SET emailchk=? WHERE name=? ";
$db->execute($sql, ['Y', $_GET['name']]);
echo 'Thanks for Your Confirmation';
return;
}
echo 'Confirmation Not Successful';
}
Above all, make a query with incoming $_GET['name']
to search for a record. Next, calculate MD5 hash of $_GET['name']
, and compare it with incoming $_GET['key']
. At last, compare the $stmt['vcode']
from database with the incoming $_GET['code']
.
If all are valid, we will activate this account by updating a flag emailchk
in the record to be 'Y'
, meaning that email confirmation is done. Look at SQL statement $sql
and a method of PHP CRUD class $db->execute()
, you will see how easily the UPDATE operation is performed.
FINAL
Conclusion
Notice that the registration form in PHP will direct to a dummy login form in this example. In fact, login form should be combined with after you also read another article of 5 Steps to AJAX Login Form with Small PHP DB Class. Thank you for reading, and we have suggested more helpful articles here. If you want to share anything, please feel free to comment below. Good luck and happy coding!
Suggested Reading
- 5 Steps to AJAX Login Form with Small PHP DB Class
- Loop Multidimensional Array in PHP by 3 Recursive Demos
TRY IT
Quick Experience
That’s all for this project, and here is the link that let you experience the program. Please kindly leave your comments for our enhancement.
Try It Yourself
Click here to execute the source code, thus before studying the downloaded codes, you can check whether it is worthy.
Analyst
Hope this helps.