PHP Login Registration Scripts
PHP simple Login & Remember me script using Cookies
A “Remember me” checkbox on a login form is very common. But the way it is built matters a lot. In this tutorial you will learn two safe methods: remember the username in the form, and keep the user logged in with a secure token.
Method 1: remember the username
This is the simple case: the form shows the username automatically the next time, and the user types only the password. We save only the username in a cookie.
login.php
<?php
session_start();
$username = $_COOKIE["remembered_user"] ?? ""; // value for the form
$message = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$username = trim($_POST["username"] ?? "");
$password = $_POST["password"] ?? "";
// Replace this check with your real login check (see the login and registration script)
$valid = ($username === "robin" && $password === "secret123");
if ($valid) {
session_regenerate_id(true);
$_SESSION["user"] = $username;
if (!empty($_POST["remember"])) {
setcookie("remembered_user", $username, [
"expires" => time() + 30 * 24 * 3600, // 30 days
"path" => "/",
"secure" => true,
"httponly" => true,
"samesite" => "Lax"
]);
} else {
setcookie("remembered_user", "", time() - 3600, "/"); // delete it
}
header("Location: dashboard.php");
exit;
}
$message = "Wrong username or password.";
}
?>
<form method="post">
<p>Username: <input type="text" name="username" value="<?php echo htmlspecialchars($username); ?>"></p>
<p>Password: <input type="password" name="password"></p>
<p><label><input type="checkbox" name="remember" <?php echo $username !== "" ? "checked" : ""; ?>> Remember my username</label></p>
<p><button type="submit">Login</button></p>
</form>
<p><?php echo htmlspecialchars($message); ?></p>
Result: If the user checks the box, the username is already in the field the next time. If the box is not checked, the cookie is deleted and the field is empty.
Method 2: keep the user logged in (stay signed in)
Many sites keep the user logged in for days, even after the browser is closed. For this you must not store the user id or the password in the cookie. Do this:
- When the user logs in with “remember me”, create two random values: a selector (to find the record) and a validator (the secret).
- Save the selector and a hash of the validator in a database table. Put
selector:validatorin the cookie. - On the next visit, find the record by the selector and compare the hash of the cookie validator with
hash_equals(). If it matches, log the user in and create a new token. - On logout, delete the token from the database and the cookie.
Database table
CREATE TABLE remember_tokens (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
selector CHAR(18) NOT NULL UNIQUE,
token_hash CHAR(64) NOT NULL,
expires_at DATETIME NOT NULL
);
Create the token after a successful login (save this function in a file named functions.php, and include that file in your login page and in auth.php. Call it right after the password check. $conn is a mysqli connection)
<?php
function rememberUser(mysqli $conn, int $userId): void
{
$selector = bin2hex(random_bytes(9)); // 18 characters
$validator = bin2hex(random_bytes(32));
$hash = hash("sha256", $validator);
$expires = date("Y-m-d H:i:s", time() + 30 * 24 * 3600);
$stmt = $conn->prepare("INSERT INTO remember_tokens (user_id, selector, token_hash, expires_at) VALUES (?, ?, ?, ?)");
$stmt->bind_param("isss", $userId, $selector, $hash, $expires);
$stmt->execute();
setcookie("remember", $selector . ":" . $validator, [
"expires" => time() + 30 * 24 * 3600,
"path" => "/",
"secure" => true,
"httponly" => true,
"samesite" => "Lax"
]);
}
?>
auth.php: include this at the top of every protected page, after your database connection file and functions.php. It logs the user in from the cookie when there is no session.
<?php
session_start();
if (empty($_SESSION["user_id"]) && !empty($_COOKIE["remember"])) {
$parts = explode(":", $_COOKIE["remember"], 2);
if (count($parts) === 2) {
[$selector, $validator] = $parts;
$stmt = $conn->prepare("SELECT id, user_id, token_hash FROM remember_tokens WHERE selector = ? AND expires_at > NOW()");
$stmt->bind_param("s", $selector);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
if ($row && hash_equals($row["token_hash"], hash("sha256", $validator))) {
session_regenerate_id(true);
$_SESSION["user_id"] = $row["user_id"];
// Remove the used token and create a new one
$del = $conn->prepare("DELETE FROM remember_tokens WHERE id = ?");
$del->bind_param("i", $row["id"]);
$del->execute();
rememberUser($conn, (int) $row["user_id"]);
}
}
}
if (empty($_SESSION["user_id"])) {
header("Location: login.php");
exit;
}
?>
On logout, delete the row of that token from remember_tokens, delete the cookie with setcookie("remember", "", time() - 3600, "/"), and destroy the session.
Why this is safe
- The cookie has a random secret that means nothing without the database. A stolen database does not give working cookies, because only a hash is saved.
- The token changes every time it is used, and it expires after 30 days.
httponlyhides the cookie from JavaScript,securesends it only over HTTPS andsamesitehelps against CSRF.
Run this only on HTTPS. Learn the basics in PHP Cookies and PHP Session, and see the login and registration code in PHP Simple Login and Registration Script.
PHP Simple Login and Registration Script
This is a simple login and registration system in PHP and MySQL. A new user registers with a name, email and password. After that the user can log in, see protected pages, and log out. The user is remembered with a PHP session (read PHP Session to understand it).
The code is short, but it follows the important security rules: passwords are saved as hashes with password_hash(), every database query is a prepared statement, and all printed values are escaped.
Files of the script
| File | Purpose |
|---|---|
| database.sql | Creates the database and the users table |
| db-config.php | Connects PHP with MySQL |
| register.php | Registration form and the code to save a new user |
| login.php | Login form and the code to check the email and password |
| dashboard.php | A protected page, only for logged in users |
| logout.php | Destroys the session and logs the user out |
Create a folder, for example login-script, inside the folder of your local server (htdocs in XAMPP) and save all the files in it. Run http://localhost/login-script/register.php.
1) database.sql
Run these queries in phpMyAdmin (or import the file).
CREATE DATABASE IF NOT EXISTS register_login_db
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE register_login_db;
CREATE TABLE IF NOT EXISTS users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
The password column is VARCHAR(255), because a password hash is long. The email is UNIQUE, so the same email can not register two times.
2) db-config.php
<?php
// Show database errors as exceptions (do not display them on a live site)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = new mysqli("localhost", "root", "", "register_login_db");
$conn->set_charset("utf8mb4");
3) register.php
<?php
session_start();
require_once "db-config.php";
$message = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$name = trim($_POST["name"] ?? "");
$email = filter_var(trim($_POST["email"] ?? ""), FILTER_VALIDATE_EMAIL);
$password = $_POST["password"] ?? "";
if ($name === "" || !$email || strlen($password) < 8) {
$message = "Enter your name, a valid email and a password of at least 8 characters.";
} else {
// Is the email already registered?
$stmt = $conn->prepare("SELECT id FROM users WHERE email = ?");
$stmt->bind_param("s", $email);
$stmt->execute();
if ($stmt->get_result()->num_rows > 0) {
$message = "This email is already registered.";
} else {
$hash = password_hash($password, PASSWORD_DEFAULT);
$insert = $conn->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
$insert->bind_param("sss", $name, $email, $hash);
$insert->execute();
$message = "Registration successful. You can login now.";
}
}
}
?>
<h2>Register</h2>
<p><?php echo htmlspecialchars($message); ?></p>
<form method="post">
<p>Name: <input type="text" name="name" value="<?php echo htmlspecialchars($_POST["name"] ?? ""); ?>"></p>
<p>Email: <input type="email" name="email" value="<?php echo htmlspecialchars($_POST["email"] ?? ""); ?>"></p>
<p>Password: <input type="password" name="password"></p>
<p><button type="submit">Register</button></p>
</form>
<p><a href="login.php">Already have an account? Login</a></p>
4) login.php
<?php
session_start();
require_once "db-config.php";
$message = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";
$stmt = $conn->prepare("SELECT id, name, password FROM users WHERE email = ?");
$stmt->bind_param("s", $email);
$stmt->execute();
$user = $stmt->get_result()->fetch_assoc();
if ($user && password_verify($password, $user["password"])) {
session_regenerate_id(true); // new session id after login
$_SESSION["user_id"] = $user["id"];
$_SESSION["user_name"] = $user["name"];
header("Location: dashboard.php");
exit;
}
// Same message for a wrong email and a wrong password
$message = "Wrong email or password.";
}
?>
<h2>Login</h2>
<p><?php echo htmlspecialchars($message); ?></p>
<form method="post">
<p>Email: <input type="email" name="email"></p>
<p>Password: <input type="password" name="password"></p>
<p><button type="submit">Login</button></p>
</form>
<p><a href="register.php">Create an account</a></p>
5) dashboard.php (protected page)
Add the same check at the top of every page that only logged in users can see.
<?php
session_start();
if (empty($_SESSION["user_id"])) {
header("Location: login.php");
exit;
}
?>
<h2>Welcome, <?php echo htmlspecialchars($_SESSION["user_name"]); ?></h2>
<p>This page is only for logged in users.</p>
<p><a href="logout.php">Logout</a></p>
6) logout.php
<?php
session_start();
$_SESSION = [];
session_destroy();
header("Location: login.php");
exit;
How it works
- Registration: the data is validated, the email is checked for duplicates, the password is turned into a hash and the user is inserted with a prepared statement.
- Login: the user row is found by the email.
password_verify()compares the typed password with the saved hash. On success the user id is saved in the session. - Protected pages: every protected page checks
$_SESSION["user_id"]. Without it, the visitor is sent to the login page. - Logout: the session data is removed and the session is destroyed.
Before you use it on a live website
- Use HTTPS, and set the session cookie as secure, httponly and SameSite. See how to store passwords securely and PHP Security Tips.
- Add a CSRF token to both forms: What is CSRF?.
- Limit the login attempts (for example lock for 15 minutes after 5 wrong tries), to stop password guessing.
- Add email verification and a password reset feature, and use a dedicated MySQL user (not root) with limited rights.
- Do not show database errors to visitors.
Want a “Remember me” option? See PHP Login with Remember me using Cookies.