
PHP Login and Registration System with Sessions, Password Hashing and User Roles
A login and registration system is one of the most common features in web applications. Many websites need users to create accounts, log in, access protected pages, update profiles, and log out securely.
In PHP, an authentication system usually uses forms, validation, MySQL, prepared statements, password hashing, password verification, sessions, and authorization checks. These concepts work together to identify users and control what they can access.
This article explains how a PHP login and registration system works, including registration, password hashing, login, sessions, logout, remember me concept, user roles, validation, and security best practices.
What Is a PHP Login and Registration System?
A PHP login and registration system allows users to create accounts and access private parts of a website. Registration is the process of creating a new user account. Login is the process of verifying the user's identity and starting an authenticated session.
A basic authentication system usually includes:
A registration form.
Server-side validation.
A users database table.
Password hashing.
A login form.
Password verification.
Sessions to remember logged-in users.
Protected pages.
Logout functionality.
User roles and permissions when needed.
Authentication should always be designed carefully because it protects user accounts and private application areas.
Database Table for Users
Before building registration and login logic, you need a database table for users. A simple users table may contain an ID, name, email, password, role, and creation date.
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);The id column uniquely identifies each user. The email column is marked as unique so two users cannot register with the same email address.
The password column should store a password hash, not the plain password. The role column can be used later for authorization, such as user, editor, or admin.
In real projects, the database may also include fields such as email verification status, remember token, reset password token, last login date, profile image, or account status.
Database Connection with PDO
PHP can connect to MySQL using PDO. PDO is a good choice because it supports prepared statements and can be used in a clean and secure way.
<?php
$host = "localhost";
$dbname = "php_auth";
$username = "root";
$password = "";
try {
$pdo = new PDO(
"mysql:host=$host;dbname=$dbname;charset=utf8mb4",
$username,
$password
);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $exception) {
die("Database connection failed.");
}
?>In production, database credentials should not be hard-coded in every file. They should be stored in a configuration file or environment variables.
The connection should use utf8mb4 to support multilingual content correctly, including Arabic, Turkish, English, and emojis.
PHP Register System
The registration system receives the user's name, email, and password, validates them, checks whether the email already exists, hashes the password, and inserts the new user into the database.
A simple registration form can look like this:
<form method="post" action="register.php">
<label>Name</label>
<input type="text" name="name">
<label>Email</label>
<input type="email" name="email">
<label>Password</label>
<input type="password" name="password">
<label>Confirm Password</label>
<input type="password" name="password_confirmation">
<button type="submit">Register</button>
</form>The PHP registration logic should never trust the submitted data directly. It should validate all fields before saving the user.
<?php
require "db.php";
$errors = [];
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$name = trim($_POST["name"] ?? "");
$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";
$passwordConfirmation = $_POST["password_confirmation"] ?? "";
if ($name === "") {
$errors["name"] = "Name is required.";
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors["email"] = "A valid email address is required.";
}
if (strlen($password) < 8) {
$errors["password"] = "Password must be at least 8 characters.";
}
if ($password !== $passwordConfirmation) {
$errors["password_confirmation"] = "Password confirmation does not match.";
}
if (count($errors) === 0) {
$statement = $pdo->prepare("SELECT id FROM users WHERE email = :email LIMIT 1");
$statement->execute(["email" => $email]);
if ($statement->fetch()) {
$errors["email"] = "This email is already registered.";
}
}
if (count($errors) === 0) {
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
$statement = $pdo->prepare("
INSERT INTO users (name, email, password)
VALUES (:name, :email, :password)
");
$statement->execute([
"name" => $name,
"email" => $email,
"password" => $passwordHash
]);
echo "Registration completed successfully.";
}
}
?>This example validates required fields, checks email format, checks password length, confirms the password, prevents duplicate emails, hashes the password, and saves the new user.
PHP Password Hash
Passwords should never be stored as plain text. If a database is leaked and passwords are plain text, all user accounts become exposed.
PHP provides the password_hash() function for secure password hashing.
<?php
$password = "secret-password";
$hash = password_hash($password, PASSWORD_DEFAULT);
echo $hash;
?>The result is a secure hash that can be stored in the database. The original password cannot be recovered from the hash.
The PASSWORD_DEFAULT algorithm is recommended because PHP can update the default algorithm in future versions when better options become available.
Do not use weak hashing methods such as md5() or sha1() for passwords. These methods are not suitable for secure password storage.
PHP Password Verify
When a user logs in, the application should compare the submitted password with the stored hash using password_verify().
<?php
$submittedPassword = $_POST["password"] ?? "";
$storedHash = $user["password"];
if (password_verify($submittedPassword, $storedHash)) {
echo "Password is correct.";
} else {
echo "Invalid password.";
}
?>You should not hash the submitted password manually and compare strings. Always use password_verify() because it knows how to check the hash correctly.
Password verification is the main step that decides whether the submitted login password matches the stored password hash.
PHP Login System
The login system receives the user's email and password, validates the input, finds the user by email, verifies the password, regenerates the session ID, and stores the user ID in the session.
A simple login form can look like this:
<form method="post" action="login.php">
<label>Email</label>
<input type="email" name="email">
<label>Password</label>
<input type="password" name="password">
<button type="submit">Login</button>
</form>The PHP login logic can be written like this:
<?php
session_start();
require "db.php";
$errors = [];
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors["email"] = "A valid email address is required.";
}
if ($password === "") {
$errors["password"] = "Password is required.";
}
if (count($errors) === 0) {
$statement = $pdo->prepare("SELECT id, name, email, password, role FROM users WHERE email = :email LIMIT 1");
$statement->execute([
"email" => $email
]);
$user = $statement->fetch(PDO::FETCH_ASSOC);
if (!$user || !password_verify($password, $user["password"])) {
$errors["login"] = "Invalid email or password.";
} else {
session_regenerate_id(true);
$_SESSION["user_id"] = $user["id"];
$_SESSION["user_name"] = $user["name"];
$_SESSION["user_role"] = $user["role"];
header("Location: dashboard.php");
exit;
}
}
}
?>This example uses a prepared statement to find the user, verifies the password securely, and starts a session after successful login.
The error message says invalid email or password instead of saying exactly which one is wrong. This is safer because it does not reveal whether an email exists in the system.
PHP Auth with Sessions
Sessions allow PHP to remember that a user is logged in across multiple pages. After login, the user ID is stored in $_SESSION.
A protected page should check whether the user is logged in before showing private content.
<?php
session_start();
if (empty($_SESSION["user_id"])) {
header("Location: login.php");
exit;
}
echo "Welcome to your dashboard.";
?>This check should be added to every page that requires authentication, such as dashboards, profile pages, admin pages, and settings pages.
You can create a reusable file named auth.php:
<?php
session_start();
if (empty($_SESSION["user_id"])) {
header("Location: login.php");
exit;
}
?>Then include it at the top of protected pages:
<?php
require "auth.php";
?>
<h1>Dashboard</h1>This keeps the authentication check organized and avoids repeating the same code in many files.
PHP Logout
Logout means ending the user's authenticated session. The application should remove session data, destroy the session, and redirect the user to the login page or home page.
<?php
session_start();
$_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();
header("Location: login.php");
exit;
?>This example clears the session array, removes the session cookie, destroys the session, and redirects the user.
A simple version may only use session_destroy(), but clearing the session cookie is a cleaner approach for a complete logout.
PHP Remember Me
A remember me feature keeps the user logged in even after the browser is closed. This is usually done using a secure persistent token stored in a cookie and matched with a token stored in the database.
A remember me system should not store the password in a cookie. It should not store sensitive user information directly in the browser.
A safer general workflow is:
User logs in successfully and selects remember me.
The server creates a random token.
The token is hashed and stored in the database.
The raw token is stored in a secure cookie.
On future visits, the cookie token is checked against the database.
If valid, the user is logged in and a new session is created.
A basic remember token can be generated using random_bytes().
<?php
$token = bin2hex(random_bytes(32));
$tokenHash = hash("sha256", $token);
?>The cookie should use secure options when possible.
<?php
setcookie("remember_token", $token, [
"expires" => time() + 60 * 60 * 24 * 30,
"path" => "/",
"secure" => true,
"httponly" => true,
"samesite" => "Lax"
]);
?>Remember me is more advanced than basic sessions and must be implemented carefully. For beginner projects, it is better to first build normal session-based login before adding remember me.
PHP User Roles
User roles allow the application to control what each user can access. Common roles include user, editor, moderator, and admin.
For example, a normal user may access only their profile, while an admin may access the admin dashboard and manage other users.
After login, the user's role can be stored in the session:
<?php
$_SESSION["user_role"] = $user["role"];
?>Then protected pages can check the role.
<?php
session_start();
if (($_SESSION["user_role"] ?? "") !== "admin") {
http_response_code(403);
echo "Access denied.";
exit;
}
echo "Welcome to the admin area.";
?>Role checks should always happen on the server side. Hiding admin buttons in HTML is not enough because users can still send requests manually.
For more complex systems, permissions can be stored separately in database tables, but for beginner projects, a simple role column is enough to understand the concept.
Validation for Login and Registration
Validation is essential in authentication systems. It improves security, prevents invalid data, and gives users clear feedback.
Registration validation may include:
Name is required.
Email is required and must be valid.
Email must be unique.
Password is required.
Password must have a minimum length.
Password confirmation must match.
Login validation may include:
Email is required and must be valid.
Password is required.
Login credentials must match an existing user.
Validation should happen on the server side even if HTML form validation is also used. Browser validation improves user experience, but it can be bypassed.
CSRF Protection for Auth Forms
Authentication forms should also be protected with CSRF tokens, especially registration, login, logout, profile update, and password change forms.
A CSRF token is a random value stored in the session and included inside the form. When the form is submitted, PHP checks that the submitted token matches the session token.
<?php
session_start();
if (empty($_SESSION["csrf_token"])) {
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
}
?>
<form method="post">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($_SESSION["csrf_token"], ENT_QUOTES, "UTF-8"); ?>">
<input type="email" name="email">
<input type="password" name="password">
<button type="submit">Login</button>
</form>When processing the form:
<?php
$token = $_POST["csrf_token"] ?? "";
if (!hash_equals($_SESSION["csrf_token"] ?? "", $token)) {
http_response_code(403);
echo "Invalid request.";
exit;
}
?>CSRF protection helps prevent unwanted form submissions from other websites.
Protecting Dashboard Pages
After login, users usually access protected pages such as dashboard, profile, settings, or admin pages. These pages should check the session before showing content.
A basic dashboard page can look like this:
<?php
require "auth.php";
?>
<h1>Dashboard</h1>
<p>Welcome, <?php echo htmlspecialchars($_SESSION["user_name"], ENT_QUOTES, "UTF-8"); ?></p>
<a href="logout.php">Logout</a>Notice that the username is escaped using htmlspecialchars(). Even session data should be displayed safely because it may originally come from user input.
Protected pages should also check permissions if the action is sensitive. For example, admin pages should check the role, and edit pages should check whether the user owns the resource.
Common Login System Mistakes
Many beginner authentication systems work, but they contain serious security mistakes. Avoiding these mistakes is important.
Common mistakes include:
Storing passwords as plain text.
Using MD5 or SHA1 for passwords.
Not using prepared statements.
Showing whether the email or password specifically is wrong.
Not regenerating the session ID after login.
Not protecting private pages with session checks.
Trusting role values from forms or URLs.
Not escaping user names when displaying them.
Storing sensitive data in cookies.
Forgetting logout or session cleanup.
A secure login system is not only about checking an email and password. It also includes safe database access, password storage, session management, validation, escaping, and authorization.
Complete Login and Registration Workflow
A complete PHP authentication workflow usually follows this structure:
Create a users table in MySQL.
Create a database connection using PDO.
Create a registration form.
Validate registration input.
Check if the email already exists.
Hash the password using password_hash().
Insert the new user using a prepared statement.
Create a login form.
Find the user by email using a prepared statement.
Verify the password using password_verify().
Regenerate the session ID after successful login.
Store the user ID and role in the session.
Protect dashboard pages using session checks.
Check roles for admin pages.
Destroy the session during logout.
This workflow is the foundation of many PHP applications. After understanding it, you can expand it with email verification, password reset, profile updates, two-factor authentication, and permission systems.
Security Notes for PHP Authentication
Authentication systems must be secure because they protect user accounts and private information.
Important security practices include:
Use password_hash() for storing passwords.
Use password_verify() for checking passwords.
Use prepared statements for all database queries.
Validate all form input on the server side.
Escape output when displaying user data.
Regenerate session ID after login.
Destroy sessions on logout.
Use HTTPS in production.
Protect forms with CSRF tokens.
Use generic login error messages.
Limit repeated failed login attempts when possible.
Check user roles on the server side.
For production applications, authentication should be tested carefully. Small mistakes in login systems can lead to serious security problems.
Authentication in Modern PHP Frameworks
Modern PHP frameworks such as Laravel and Symfony provide built-in authentication tools or packages. Laravel, for example, provides features for registration, login, password hashing, sessions, CSRF protection, email verification, password reset, and authorization.
However, learning how login and registration work in pure PHP is still useful. It helps you understand the concepts behind framework authentication and makes it easier to debug, customize, and secure real applications.
Once you understand pure PHP authentication, moving to Laravel authentication becomes easier because the same ideas still exist: users table, password hashes, sessions, guards, middleware, validation, and authorization.
Conclusion
A PHP login and registration system is an essential project for learning backend development. It combines forms, validation, MySQL, prepared statements, password hashing, password verification, sessions, logout, user roles, and security practices.
The most important rules are to never store plain passwords, always use prepared statements, validate user input, escape output, regenerate session IDs after login, and protect private pages on the server side.
After building a basic login and registration system, the next step is to add features such as email verification, password reset, remember me, profile editing, role-based access control, and admin user management.

