- Forgot Password and password reset form in PHP with MYSQL
- Forgot Password form in PHP with MYSQL –
- Create a database table –
- Create a forgot password form —
- Create PHP scripts for forgot password form –
- PHP Forgot Password Recover Code
- Forgot Password Code
- Password reset
- Reset password form
- Recover Password Database Structure
- Forgot password recovery email
Forgot Password and password reset form in PHP with MYSQL
Every time most people forget their password and try to reset the password on the website.
We are creating registration and login form in PHP from the scratch . In this tutorial, we will create a forgot password form and reset the password form in PHP with MYSQL.
In the previous tutorial, we created a registration and login system in PHP and also we created a forgot password link on the login page.
In this tutorial, we will create a forgot password system in PHP
Forgot Password form in PHP with MYSQL –
The forgot password form is used to update the user password using the link on the email.
In the forgot password form, the user enters a username or email to find his account and clicks on the send link button. The password reset link goes to the user’s email and the user clicks on the link. The user redirects to the password reset page and updates his password.
In this forgot password system, we will create two forms. First to find out the user and second for a password reset.
Create a database table –
In the previous tutorial, we had created a user table, and now will create a password reset table.
CREATE TABLE `pass_reset` ( `id` int(11) NOT NULL AUTO_INCREMENT, `email` varchar(255) NOT NULL, `token` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
Execute the query above in your PHPMYADMIN panel.
In this table above, we have created two fields. We will insert an email and token in the password reset table after finding the account. We will send a password reset link with a password reset form page and token.
The token will be a random id. We will find an email with token and update by email id. This is really easy.
Create a forgot password form —
In the previous tutorial, we used bootstrap to design responsive forms and also created an extra CSS file in the previous tutorial.
Let’s create a forgot password form –
Create a file with the name – forgot-password.php
forgot-password.php
?>
Have an account? Login
Don't have an account? Sign up
In the code above, we have created one field to find out the user account.
Now, we will create a forgot password process file.
Create PHP scripts for forgot password form –
In this PHP file, we will follow the steps –
- Find the user account with the entered value. If the user account exits or not in our system database.
- If the user found then fetch the email and insert it into the pass_reset data table with token id.
The token id will be generated with and random_bytes() PHP function .
$token = bin2hex(random_bytes(50));
- Insert email and token id pass_reset table.
- Now, we will use the PHP mail() function to send an email on the user email id
- In the message of mail()function, we will send some text with password reset form and token id link.
$msg="Your password reset link
http://technosmarter.com/php/form/password-reset.php?token=".$token."
Reset your password with this link .Click or open in new tab
".$credits." ";
The user will receive the link to the password reset form page and click on it.
Create a file with the name – forgot_process.php
forgot_process.php
$token = bin2hex(random_bytes(50)); $inresult = mysqli_query($dbc,"insert into pass_reset values('','$oldftemail','$token')"); if ($inresult) < $FromName="Techno Smarter"; $FromEmail="no_reply@technosmarter.com"; $ReplyTo="technosmarterinfo@gmail.com"; $credits="All rights are reserved | Techno Smarter "; $headers = "MIME-Version: 1.0\n"; $headers .= "Content-type: text/html; charset=iso-8859-1\n"; $headers .= "From: ".$FromName." \n"; $headers .= "Reply-To: ".$ReplyTo."\n"; $headers .= "X-Sender: \n"; $headers .= "X-Mailer: PHP\n"; $headers .= "X-Priority: 1\n"; $headers .= "Return-Path: \n"; $subject="You have received password reset email"; $msg="Your password reset link
http://localhost:8081/php/form/password-reset.php?token=".$token."
Reset your password with this link .Click or open in new tab
".$credits." "; if(@mail($oldftemail, $subject, $msg, $headers,'-f'.$FromEmail) ) < header("location:forgot-password.php?sent=1"); $hide='1'; >else < header("location:forgot-password.php?servererr=1"); >> else < header("location:forgot-password.php?something_wrong=1"); >> else < header("location:forgot-password.php?err PHP-Update-data-in-database-mysql-update-query.html" target="_blank">operation in PHP . Convert password simple text to hash pattern and update using an update query. Create a file with the name – password-reset.php
password-reset.php
?> //form for submit if(isset($_POST['sub_set'])) < extract($_POST); if($password =='')< $error[] = 'Please enter the password.'; >if($passwordConfirm =='') < $error[] = 'Please confirm the password.'; >if($password != $passwordConfirm) < $error[] = 'Passwords do not match.'; >if(strlen($password) <5)< // min $error[] = 'The password is 6 characters long.'; >if(strlen($password)>50) < // Max $error[] = 'Password: Max length 50 Characters Not allowed'; >$fetchresultok = mysqli_query($dbc, "SELECT email FROM pass_reset WHERE token='$token'"); if($res = mysqli_fetch_array($fetchresultok)) < $email= $res['email']; >if(isset($email) != '' ) < $emailtok=$email; >else < $error[] = 'Link has been expired or something missing '; $hide=1; >if(!isset($error))< $options = array("cost"=>4); $password = password_hash($password,PASSWORD_BCRYPT,$options); $resultresetpass= mysqli_query($dbc, "UPDATE users SET password='$password' WHERE email='$emailtok'"); if($resultresetpass) < $success="✅
Your password has been updated successfully..
Login here. "; $resultdel = mysqli_query($dbc, "DELETE FROM pass_reset WHERE token='$token'"); $hide=1; > > > ?> In the PHP code above, you can see, we used the delete operation after updating the password. This is really important that we delete tokens from the pass_reset table after updating the password.
In this way, you can create a forgotten password system or you can say forgot password form link for the login form on the PHP website.
PHP Forgot Password Recover Code
In this post, we are going to see an example to learn how to recover the forgot password. In this example we have a forgot password form to get the username or email to recover the password. After form submits, we are sending password recovery email to the user.
The Password recovery email has a link to the page where we can reset the password.
Forgot Password Code
This HTML code shows the forgot password form.
handleForgot(); > ?> Forgot Password Forgot Password else if ($displayMessage["status"] == "success") < ?> > ?> Username
ds = new DataSource(); > /** * to get member record by username * * @param string $username * @return array */ public function getMember($username) < $query = 'SELECT * FROM tbl_member where username = ?'; $paramType = 's'; $paramValue = array( $username ); $memberRecord = $this->ds->select($query, $paramType, $paramValue); return $memberRecord; > /** * main function that handles the forgot password * * @return string[] */ public function handleForgot() < if (! empty($_POST["username"])) < $memberRecord = $this->getMember($_POST["username"]); require_once __DIR__ . "/PasswordReset.php"; $passwordReset = new PasswordReset(); $token = $this->generateRandomString(97); if (! empty($memberRecord)) < $passwordReset->insert($memberRecord[0]['id'], $token); $this->sendResetPasswordEmail($memberRecord, $token); > else < // the input username is invalid // do not display a message saying 'username as invalid' // that is a security issue. Instead, // sleep for 2 seconds to mimic email sending duration sleep(2); >> // whatever be the case, show the same message for security purposes $displayMessage = array( "status" => "success", "message" => "Check your email to reset password." ); return $displayMessage; > /** * to send password recovery email * you may substitute this code with SMTP based email * Refer https://phppot.com/php/send-email-in-php-using-gmail-smtp/ to send smtp * based email * * @param array $memberListAry * @param string $token */ public function sendResetPasswordEmail($memberListAry, $token) < $resetUrl = 'applicationUrl . 'reset-password.php?token=' . $token . '">reset'; $emailBody = 'Hi, To reset your password, click this link ' . $resetUrl; $to = $memberListAry[0]["email"]; $subject = 'Reset password'; mail($to, $subject, $emailBody); > public function updatePassword($id, $password) < $hashedPassword = password_hash($password, PASSWORD_DEFAULT); $query = 'UPDATE tbl_member SET password = ? WHERE $paramType = 'si'; $paramValue = array( $hashedPassword, $id ); $this->ds->execute($query, $paramType, $paramValue); $displayMessage = array( "status" => "success", "message" => "Password reset successfully." ); return $displayMessage; > /** * use this function if you have PHP version 7 or greater * else use the below fuction generateRandomString * * @param int $length * @param string $keyspace * @throws \RangeException * @return string */ function getRandomString(int $length = 64, string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'): string < if ($length < 1) < throw new \RangeException("Length must be a positive integer"); >$pieces = []; $max = mb_strlen($keyspace, '8bit') - 1; for ($i = 0; $i < $length; ++ $i) < $pieces[] = $keyspace[random_int(0, $max)]; >return implode('', $pieces); > /** * this generates predictable random strings. * So the best * option is to use the above function getRandomString * and to use that, you need PHP 7 or above * * @param number $length * @return string */ function generateRandomString($length = 10) < $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i ++) < $randomString .= $characters[rand(0, $charactersLength - 1)]; >return $randomString; > >
Password reset
ds = new DataSource(); > public function insert($memberId, $token) < $query = 'INSERT INTO tbl_password_reset (member_id, password_recovery_token, expire_at, is_valid) VALUES (?, ?, ?, ?)'; $paramType = 'sssi'; $time = date('Y-m-d H:i:s'); // expire the token after 12 hours $RESET_TOKEN_LIFE = '12 hours'; $expireAt = date('Y-m-d H:i:s', strtotime($time . ' + ' . $RESET_TOKEN_LIFE)); $paramValue = array( $memberId, $token, $expireAt, 1 ); $memberId = $this->ds->insert($query, $paramType, $paramValue); > public function getMemberForgotByResetToken($recoveryToken) < $query = 'SELECT * FROM tbl_password_reset where password_recovery_token = ? AND is_valid = 1 AND expire_at >= now()'; $paramType = 's'; $paramValue = array( $recoveryToken ); $memberRecord = $this->ds->select($query, $paramType, $paramValue); return $memberRecord; > public function expireToken($recoveryToken) < $query = 'UPDATE tbl_password_reset SET is_valid = 0, expired_at = now() WHERE password_recovery_token = ?'; $paramType = 's'; $paramValue = array( $recoveryToken ); $this->ds->execute($query, $paramType, $paramValue); > >
Reset password form
else < $token = $_GET["token"]; // token found, let's validate it $memberRecord = $passwordReset->getMemberForgotByResetToken($token); if (empty($memberRecord)) < // token expired // do not say that your token has expired for security reasons // never reveal system state to the end user echo 'Invalid request!'; exit(); >> if (! empty($_POST["reset-btn"])) < $passwordReset->expireToken($token); require_once __DIR__ . '/Model/Member.php'; $member = new Member(); $displayMessage = $member->updatePassword($memberRecord[0]['member_id'], $_POST["password"]); > ?> Reset Password Reset Password else if ($displayMessage["status"] == "success") < ?> > ?> Password Confirm Password Recover Password Database Structure
-- phpMyAdmin SQL Dump -- version 5.0.2 -- https://www.phpmyadmin.net/ -- -- Host: localhost -- Generation Time: Sep 17, 2020 at 04:16 PM -- Server version: 8.0.17 -- PHP Version: 7.4.8 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; START TRANSACTION; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- Database: `forgot-password-reset` -- -- -------------------------------------------------------- -- -- Table structure for table `tbl_member` -- CREATE TABLE `tbl_member` ( `id` int(11) NOT NULL, `username` varchar(255) NOT NULL, `password` varchar(200) NOT NULL, `email` varchar(255) NOT NULL, `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -------------------------------------------------------- -- -- Table structure for table `tbl_password_reset` -- CREATE TABLE `tbl_password_reset` ( `id` int(11) NOT NULL, `member_id` int(11) NOT NULL, `password_recovery_token` varchar(255) NOT NULL, `expire_at` timestamp NULL DEFAULT NULL, `is_valid` tinyint(4) NOT NULL, `expired_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Indexes for dumped tables -- -- -- Indexes for table `tbl_member` -- ALTER TABLE `tbl_member` ADD PRIMARY KEY (`id`); -- -- Indexes for table `tbl_password_reset` -- ALTER TABLE `tbl_password_reset` ADD PRIMARY KEY (`id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `tbl_member` -- ALTER TABLE `tbl_member` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1; -- -- AUTO_INCREMENT for table `tbl_password_reset` -- ALTER TABLE `tbl_password_reset` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1; COMMIT; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Forgot password recovery email
If the username is found in the database, a recovery mail is sent to the user’s email. The recovery mail will have a link. The link’s essential part is a hashed random secure token. This is designed in such a way that the user will not be able to mimic it.
A record against that member will be done in the table tbl_password_reset with a generated hash secure token. When the user clicks the link with the token, it will be validated for expiry time.
In this example project, for brevity, Php’s mail() function is used. If you wish you can substitute it with PHPMailer based SMTP email.