The login system enables users to create and log in to their accounts, allowing them to access website content. The login system is a key feature for every membership website. If you want to restrict access to the website content and allow only the logged-in user to access the content, user login functionality needs to be implemented. User registration and login system can be integrated easily with PHP and MySQL. In this tutorial, we’ll show you how to build a secure login system with PHP and MySQL.
In this PHP Login System with MySQL (user authentication) script, we will implement the following features:
Before getting started to build User Login System with PHP, take a look at the complete file structure of the project.
login_system_with_php/ ├── config.php ├── index.php ├── register.php ├── forgot.php ├── reset.php ├── account.php ├── logout.php └── assets/ └── style.css
Create a MySQL database (ex: codexworld_db) and a table named users using the following SQL query. The users table includes fields for user details such as first name, last name, email, password, and created date.
CREATE TABLE `users` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL,
`last_name` VARCHAR(50) NOT NULL,
`email` VARCHAR(100) NOT NULL UNIQUE,
`password` VARCHAR(255) NOT NULL,
`reset_token` VARCHAR(255) DEFAULT NULL,
`reset_expires` DATETIME DEFAULT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
This file is used to set database connection parameters. Update the database configuration according to your MySQL setup. Also, set the base URL and mail settings for password recovery.
DB_HOST, DB_USER, DB_PASS, and DB_NAME constants, set the database connection parameters according to your MySQL setup.BASE_URL constant, set the base URL according to your project path.MAIL_FROM constant, set the email address from which password reset emails will be sent.There are also helper functions to connect to the database and sanitize user input.
<?php
// Database configuration (adjust according to your mySQL setup)
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', 'root_pass');
define('DB_NAME', 'codexworld_db');
// Base URL (adjust if necessary)
define('BASE_URL', 'http://localhost/secure_login_system_with_php/');
// Mail settings: when using localhost, ensure a mailer is configured or use SMTP in production
define('MAIL_FROM', 'no-reply@example.com');
// Start session
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Create mysqli connection
function db_connect() {
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($mysqli->connect_errno) {
die('Database connection failed: ' . $mysqli->connect_error);
}
// set charset
$mysqli->set_charset('utf8mb4');
return $mysqli;
}
// Helper: sanitize input
function e($str) {
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
?>
This file contains the user registration form and handles the registration process. It includes input validation, password hashing, and storing user details in the database. It also checks for duplicate email addresses to prevent multiple registrations with the same email.
password_hash() and the user details are inserted into the database using prepared statements to prevent SQL injection.<?php
// Include configuration file
require_once 'config.php';
// If already logged in, redirect to account
if (!empty($_SESSION['user_id'])) {
header('Location: account.php');
exit;
}
// Initialize
$errors = [];
$old = ['first_name'=>'','last_name'=>'','email'=>''];
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
$first = trim($_POST['first_name'] ?? '');
$last = trim($_POST['last_name'] ?? '');
$email = trim($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
$confirm = $_POST['password_confirm'] ?? '';
$old = ['first_name'=>$first,'last_name'=>$last,'email'=>$email];
// Validation
if ($first === '') {
$errors['first_name'] = 'First name is required';
}
if ($last === '') {
$errors['last_name'] = 'Last name is required';
}
if ($email === '') {
$errors['email'] = 'Email is required';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Email is not valid';
}
if ($password === '') {
$errors['password'] = 'Password is required';
} elseif (strlen($password) < 8) {
$errors['password'] = 'Password must be at least 8 characters';
}
if ($confirm !== $password) {
$errors['password_confirm'] = 'Passwords do not match';
}
if (empty($errors)) {
$db = db_connect();
$stmt = $db->prepare('SELECT id FROM users WHERE email = ? LIMIT 1');
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows > 0) {
$errors['email'] = 'Email is already registered';
} else {
$hash = password_hash($password, PASSWORD_DEFAULT);
$ins = $db->prepare('INSERT INTO users (first_name,last_name,email,password) VALUES (?,?,?,?)');
$ins->bind_param('ssss', $first, $last, $email, $hash);
if ($ins->execute()) {
// set a flash message and redirect to login (index.php)
$_SESSION['flash_success'] = 'Registration successful. You may now log in.';
header('Location: '.BASE_URL);
exit;
} else {
$errors['general'] = 'Registration failed. Please try again.';
}
}
$stmt->close();
$db->close();
}
}
?>
<div class="card">
<h2>Registration</h2>
<p class="muted">Please fill this form to create an account.</p>
<?php if (!empty($errors)): ?>
<div class="top-messages error">
<?php foreach ($errors as $err): ?>
<div><?php echo e($err); ?></div>
<?php endforeach; ?>
</div>
<?php elseif (!empty($success)): ?>
<div class="top-messages success"><?php echo e($success); ?></div>
<?php endif; ?>
<form method="post">
<div class="form-group">
<label for="first_name">First name</label>
<input type="text" id="first_name" name="first_name" value="<?php echo e($old['first_name']); ?>" required>
</div>
<div class="form-group">
<label for="last_name">Last name</label>
<input type="text" id="last_name" name="last_name" value="<?php echo e($old['last_name']); ?>" required>
</div>
<div class="form-group">
<label for="email_r">Email</label>
<input type="email" id="email_r" name="email" value="<?php echo e($old['email']); ?>" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required>
</div>
<div class="form-group">
<label for="password_confirm">Confirm Password</label>
<input type="password" id="password_confirm" name="password_confirm" required>
</div>
<div>
<input type="submit" name="submit" class="btn" value="Register">
<a class="btn secondary" href="<?php echo BASE_URL; ?>">Back to login</a>
</div>
<div class="switch-links">
<span class="muted">Already registered?</span>
<a href="<?php echo BASE_URL; ?>">Login</a>
</div>
</form>
</div>
This is the login form that users will see when they visit the root URL of your application. It includes fields for email and password, as well as links to the registration page. The form submits to the same page (index.php) using the POST method.
The PHP code at the top of the file handles the following:
<?php
// Include configuration file
require_once 'config.php';
// If already logged in, redirect to account
if (!empty($_SESSION['user_id'])) {
header('Location: account.php');
exit;
}
// Initialize
$errors = [];
$old = ['email'=>''];
// show flash message from registration if set
$flash_success = '';
if (!empty($_SESSION['flash_success'])) {
$flash_success = $_SESSION['flash_success'];
unset($_SESSION['flash_success']);
}
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
$email = trim($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
$old['email'] = $email;
if ($email === '') {
$errors['email'] = 'Email is required';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Email is not valid';
}
if ($password === '') {
$errors['password'] = 'Password is required';
}
if (empty($errors)) {
$db = db_connect();
$stmt = $db->prepare('SELECT id, first_name, last_name, email, password FROM users WHERE email = ? LIMIT 1');
$stmt->bind_param('s', $email);
$stmt->execute();
$res = $stmt->get_result();
if ($user = $res->fetch_assoc()) {
if (password_verify($password, $user['password'])) {
// login success
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
header('Location: account.php');
exit;
} else {
$errors['general'] = 'Email or password is incorrect';
}
} else {
$errors['general'] = 'Email or password is incorrect';
}
$stmt->close();
$db->close();
}
}
?>
<div class="card">
<h2>Login</h2>
<p class="muted">Use the login form below to access your account.</p>
<?php if (!empty($errors)): ?>
<div class="top-messages error">
<?php foreach ($errors as $err): ?>
<div><?php echo e($err); ?></div>
<?php endforeach; ?>
</div>
<?php elseif (!empty($flash_success)): ?>
<div class="top-messages success"><?php echo e($flash_success); ?></div>
<?php endif; ?>
<form method="post">
<div class="form-group">
<label for="email">Email</label>
<input id="email" name="email" type="email" value="<?php echo e($old['email']); ?>" required>
</div>
<div class="form-group">
<label for="password_l">Password</label>
<input id="password_l" name="password" type="password" required>
<span class="muted"><a href="forgot.php">Forgot Password?</a></span>
</div>
<div>
<input type="submit" name="submit" class="btn" value="Login">
</div>
<div class="switch-links">
<span class="muted">Don't have an account?</span>
<a href="register.php">Register</a>
</div>
</form>
</div>
This page is accessible only to logged-in users and displays their account information. It includes:
<?php
// Include configuration file
require_once 'config.php';
// If not logged in, redirect to login
if (empty($_SESSION['user_id'])) {
header('Location: ' . BASE_URL);
exit;
}
// Fetch user details
$db = db_connect();
$stmt = $db->prepare('SELECT id, first_name, last_name, email, created_at FROM users WHERE id = ? LIMIT 1');
$stmt->bind_param('i', $_SESSION['user_id']);
$stmt->execute();
$res = $stmt->get_result();
if (!$user = $res->fetch_assoc()) {
// user missing
session_destroy();
header('Location: ' . BASE_URL);
exit;
}
$stmt->close();
$db->close();
?>
<div class="card">
<div class="account">
<h2>My Account</h2>
<div>
<a class="btn secondary" href="logout.php">Logout</a>
</div>
</div>
<div style="margin-top:12px">
<p><strong>First name:</strong> <?php echo e($user['first_name']); ?></p>
<p><strong>Last name:</strong> <?php echo e($user['last_name']); ?></p>
<p><strong>Email:</strong> <?php echo e($user['email']); ?></p>
<p class="muted">Member since: <?php echo e($user['created_at']); ?></p>
</div>
</div>
This page logs the user out by destroying the session and redirects them to the login page.
<?php
// Include configuration file
require_once 'config.php';
// clear session
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params['path'], $params['domain'], $params['secure'], $params['httponly']
);
}
session_destroy();
// redirect to homepage
header('Location: ' . BASE_URL);
exit;
?>
This page allows users to request a password reset link by entering their email address. It includes:
<?php
// Include configuration file
require_once 'config.php';
// Initialize
$errors = [];
$status = '';
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
$email = trim($_POST['email'] ?? '');
if ($email === '') {
$errors['email'] = 'Email is required';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Email is not valid';
}
if (empty($errors)) {
$db = db_connect();
$stmt = $db->prepare('SELECT id, first_name FROM users WHERE email = ? LIMIT 1');
$stmt->bind_param('s', $email);
$stmt->execute();
$res = $stmt->get_result();
if ($user = $res->fetch_assoc()) {
$token = bin2hex(random_bytes(16));
$expires = date('Y-m-d H:i:s', time() + 3600); // 1 hour
$up = $db->prepare('UPDATE users SET reset_token = ?, reset_expires = ? WHERE id = ?');
$up->bind_param('ssi', $token, $expires, $user['id']);
if ($up->execute()) {
$resetLink = BASE_URL . 'reset.php?token=' . $token;
$subject = 'Password reset request';
$message = "Hello " . $user['first_name'] . ",\n\n" .
"We received a request to reset your password. Click the link below to reset it:\n\n" .
$resetLink . "\n\nIf you didn't request this, please ignore this email.\n\n" .
"Regards\n" . MAIL_FROM;
$headers = 'From: ' . MAIL_FROM . "\r\n" . 'Reply-To: ' . MAIL_FROM . "\r\n";
// Try to send mail; on many dev environments this may not be configured.
@mail($email, $subject, $message, $headers);
$status = 'A password reset link has been sent to your email address. Please check your inbox.';
} else {
$errors['general'] = 'Unable to create reset request. Try again later.';
}
$up->close();
} else {
// Don't reveal whether email exists
$status = 'If the email exists in our system, a reset link has been sent.';
}
$stmt->close();
$db->close();
}
}
?>
<div class="card">
<h2>Forgot Password</h2>
<p class="muted">Enter your email address below to receive a password reset link.</p>
<?php if (!empty($errors)): ?>
<div class="top-messages error">
<?php foreach ($errors as $err): ?>
<div><?php echo e($err); ?></div>
<?php endforeach; ?>
</div>
<?php elseif ($status): ?>
<div class="top-messages success"><?php echo e($status); ?></div>
<?php endif; ?>
<form method="post">
<div class="form-group">
<label for="email_f">Email</label>
<input type="email" id="email_f" name="email" required>
</div>
<div>
<input type="submit" name="submit" class="btn" value="Send Reset Link">
<a class="btn secondary" href="<?php echo BASE_URL; ?>">Back</a>
</div>
</form>
</div>
This page allows users to reset their password using the token sent to their email. It includes:
<?php
// Include configuration file
require_once 'config.php';
// Initialize
$errors = [];
$status = '';
// Get token from URL
$token = $_GET['token'] ?? '';
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])) {
$token = $_POST['token'] ?? '';
$password = $_POST['password'] ?? '';
$confirm = $_POST['password_confirm'] ?? '';
if ($password === '') {
$errors['password'] = 'Password is required';
} elseif (strlen($password) < 8) {
$errors['password'] = 'Password must be at least 8 characters';
}
if ($confirm !== $password) {
$errors['password_confirm'] = 'Passwords do not match';
}
if (empty($errors)) {
$db = db_connect();
$stmt = $db->prepare('SELECT id, reset_expires FROM users WHERE reset_token = ? LIMIT 1');
$stmt->bind_param('s', $token);
$stmt->execute();
$res = $stmt->get_result();
if ($user = $res->fetch_assoc()) {
if ($user['reset_expires'] === null || strtotime($user['reset_expires']) < time()) {
$errors['general'] = 'Reset token has expired';
} else {
$hash = password_hash($password, PASSWORD_DEFAULT);
$up = $db->prepare('UPDATE users SET password = ?, reset_token = NULL, reset_expires = NULL WHERE id = ?');
$up->bind_param('si', $hash, $user['id']);
if ($up->execute()) {
$status = 'Your password has been reset successfully. You may now log in.';
} else {
$errors['general'] = 'Unable to reset password. Try again later.';
}
$up->close();
}
} else {
$errors['general'] = 'Invalid reset token';
}
$stmt->close();
$db->close();
}
}
?>
<div class="card">
<h2>Reset Password</h2>
<p class="muted">Reset your password using the form below.</p>
<?php if (!empty($errors)): ?>
<div class="top-messages error">
<?php foreach ($errors as $err): ?>
<div><?php echo e($err); ?></div>
<?php endforeach; ?>
</div>
<?php elseif ($status): ?>
<div class="top-messages success"><?php echo e($status); ?></div>
<div style="margin-top:12px">
<a class="btn" href="<?php echo BASE_URL; ?>">Go to Login</a>
</div>
<?php endif; ?>
<?php if (empty($status)): ?>
<form method="post">
<div class="form-group">
<label for="password">New Password</label>
<input type="password" id="password" name="password" required>
</div>
<div class="form-group">
<label for="password_confirm">Confirm New Password</label>
<input type="password" id="password_confirm" name="password_confirm" required>
</div>
<div>
<input type="hidden" name="token" value="<?php echo e($token); ?>">
<input type="submit" name="submit" class="btn" value="Reset Password">
<a class="btn secondary" href="<?php echo BASE_URL; ?>">Cancel</a>
</div>
</form>
<?php endif; ?>
</div>
In this tutorial, we have created a simple user registration and login system using PHP and MySQL. We covered the following topics:
By following these steps, you can build a basic user authentication system for your PHP web applications. Remember to always prioritize security by using prepared statements to prevent SQL injection and hashing passwords before storing them in the database.
To make this code functional, ensure you have a proper PHP environment set up with access to a MySQL database. You can further enhance this system by adding features like adding CSRF protection tokens to forms, using a proper mailer (PHPMailer) with SMTP credentials, email verification, forgot password with email OTP verification functionality, password reset, and user profile management.
You can purchase a complete and ready-to-use PHP User Login System Script from the Premium Scripts section or download the standard version from the Download Source Code button below.
Looking for expert assistance to implement or extend this script’s functionality? Submit a Service Request
💰 Budget-friendly • 🌍 Global clients • 🚀 Production-ready solutions
Keep on working, great job!
Thanks. Your tutorial helped me a lot. Keep it up.
Thank you for this great job, please how do i need code for one person to register many people and submit it in one form.
hello very good work, how can i put code like this (!preg_match(“/([\w\-]+\@[\w\-]+\.[\w\-]+)/”,$value)) for the email? thanks
how to attach the php file with css stylesheet
Thanks for the tutorial
Thank you so much for a wonderful Tutorial and the source code. It helped me a lot. You are doing such a fabulous job. Looking forward more projects.
i have already created a number of web pages how do i implement this on all of them?
This is such a great work, more knowledge.
i’m trying to setup a login/registration system
where users are registered to different department and while login in, the menus displayed on the index page will be determined by the department of registration and login (while login in, the condition of username, password and department as to be true with registration) for each user.
Many thanks.
Please send your modification requirements to our support team at support@codexworld.com.
thanks a lot .this code perfectly running ,not even single errors are coming.
Hey, I’m loving the script. Can you confirm how i can check session is active on individual pages or direct back to login?
hello sir amazing script but one thing could you add email activation to avoid false registration
How can i make so only a certain ID can access a website?
thanks for the tutorial
Thank you for the tutorial . I have a major challenge, I’m using two radio buttons to display two different registration forms.On selection of one radio button, I want the form to save to a different table, likewise the other button. But I can’t seem to figure it out, since I’ve been experimenting on one radio button, but nothing on the form is saving to the database
In that case, send your requirements to our support team at support@codexworld.com.
Sir, how to add images I means upload image
To upload image in PHP, see this tutorial – https://www.codexworld.com/php-file-upload/
How to make the phone number as a data validation so that if we enter abc then something pop out saying that please enter correct phone number
You can validate the phone number easily with HTML5. Use type and pattern attribute in HTML input field for phone number validation, see the example code from here – https://www.codexworld.com/how-to/phone-number-validation-html5/
Great! Am a newbie, my challenges are:
A} how to blend the php files extentions wt main website html extention files.
b} where is the data base table created- @ the hosts Cpane l or one of the files to host.
please help me out how to connect the data base table
Good work and thanks a lot for sharing!
keep your good work
love your website
i want to work with you per my projects
add my skype id
Ion Vladescu | Microsoft & Cisco Trainer
Skype: ion.vladescu
Thank you so much for the code, it was really helpful.
I’d like to know What should we replace the varibale “$conditions” with..?
Greetings Sir,
How to check email already exists validation using JAVASCRIPT and AJAX. In Ajax i want To Post the page to the same page not at other location. I am having modal form. If am tring to do the same. Error message gets printed on home page instead of Modal Form kindly revert me asap.
Thanks for all your hard work it is much appreciated
may I ask how to use the select conditions
can you give a sample
many thanks