🔐 Complete Guide · PHP + MySQL

Build a Login System
with PHP & MySQL

Learn to create Sign Up, Log In, and Log Out pages step by step. You will go from zero to expert — with real code you can use right now.

7
Sections
5
PHP Files
12+
Code Blocks
EN/BN
Bilingual
Setup
Database
Sign Up
Log In
Log Out
Security
Quiz
01
Project Setup & File Structure
Install tools and create your folder

You need three tools to start: a web server (Apache), a database (MySQL), and PHP. The easiest way is to install XAMPP — it gives you all three in one package. No separate setup needed.

What you will learn
🗄️

MySQL Database

Create a database and a users table

📝

Sign Up Page

Register new users safely

🔑

Log In Page

Verify user credentials with sessions

🚪

Log Out Page

Destroy session and protect pages

🛡️

Security Rules

Hashing, prepared statements, XSS

🏠

Dashboard Page

A page only logged-in users can see

Installation steps
1

Download XAMPP

Go to apachefriends.org and download XAMPP for your system (Windows, Mac, or Linux). Run the installer and accept defaults.

2

Start Apache and MySQL

Open the XAMPP Control Panel. Click Start next to Apache and MySQL. Both must show a green light before you continue.

3

Create your project folder

Go to C:/xampp/htdocs/ and create a new folder called myauth. All your PHP files go inside this folder.

4

Open your project in the browser

Type localhost/myauth/ in your browser. This is where you will see your work.

📁 File Structure — 5 files total

myauth/ → db.php, signup.php, login.php, logout.php, dashboard.php

File Purpose
db.phpConnects to the MySQL database. All other files use this.
signup.phpShows the registration form and saves new users.
login.phpShows the login form and starts a session on success.
logout.phpDestroys the session and sends the user to login.php.
dashboard.phpA protected page. Only logged-in users can see it.
02
Create the Database & Table
Set up MySQL and write the db.php connection file

A database stores your user data. You create one table called users. Each row in this table is one user account — with an id, name, email, password, and the date they joined.

Step 1 — Open localhost/phpmyadmin in your browser. Click the SQL tab and run this:

ধাপ ১ — ব্রাউজারে localhost/phpmyadmin খুলুন। SQL ট্যাবে ক্লিক করুন এবং এটি চালান:

SQLphpmyadmin → SQL tab
CREATE DATABASE myauth_db;
USE myauth_db;

CREATE TABLE users (
  id         INT AUTO_INCREMENT PRIMARY KEY,
  name       VARCHAR(100)  NOT NULL,
  email      VARCHAR(150)  UNIQUE NOT NULL,
  password   VARCHAR(255)  NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Column Type Why?
idINT AUTO_INCREMENTUnique number for each user. Grows automatically.
nameVARCHAR(100)The user's full name. Up to 100 characters.
emailVARCHAR(150) UNIQUEThe email must be unique — no two users share one.
passwordVARCHAR(255)Stores the hashed password. Needs 255 chars for safety.
created_atTIMESTAMPRecords the exact date and time the user signed up.

Step 2 — Create db.php. Every other file will include this file to connect to MySQL:

ধাপ ২ — db.php তৈরি করুন। MySQL এ সংযুক্ত হতে অন্য সব ফাইল এই ফাইলটি অন্তর্ভুক্ত করবে:

PHPdb.php
<?php
// Database connection settings
$host     = "localhost";
$dbname   = "myauth_db";
$username = "root";       // XAMPP default username
$password = "";            // XAMPP default password (empty)

try {
    $pdo = new PDO(
        "mysql:host=$host;dbname=$dbname;charset=utf8",
        $username,
        $password
    );
    // Show errors clearly while you develop
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    // Return rows as associative arrays
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
    die("Connection failed: " . $e->getMessage());
}
?>
💡 What is PDO?

PDO (PHP Data Objects) is the modern way to talk to MySQL in PHP. It blocks SQL injection attacks. Always use PDO. Never use the old mysql_connect() function.

03
Sign Up Page
Register new users with hashed passwords

The sign up page collects a name, email, and password. It checks the email is not already taken. Then it hashes the password and saves the new user to the database. Never store a plain password!

How the sign up process works
User fills form
Validate inputs
Check email exists?
Hash password
Save to DB ✓
PHPsignup.php
<?php
require_once 'db.php';  // Load the database connection

$error   = '';
$success = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    // Step 1: Get and clean the form inputs
    $name     = trim($_POST['name']);
    $email    = trim($_POST['email']);
    $password = $_POST['password'];

    // Step 2: Check all fields are filled
    if (empty($name) || empty($email) || empty($password)) {
        $error = "All fields are required.";

    // Step 3: Check the email format is correct
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $error = "Enter a valid email address.";

    // Step 4: Check the password is long enough
    } elseif (strlen($password) < 6) {
        $error = "Password must be at least 6 characters.";

    } else {
        // Step 5: Check if this email is already registered
        $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
        $stmt->execute([$email]);

        if ($stmt->rowCount() > 0) {
            $error = "This email is already registered.";
        } else {
            // Step 6: Hash the password — NEVER store plain text
            $hashed = password_hash($password, PASSWORD_DEFAULT);

            // Step 7: Insert the new user into the database
            $stmt = $pdo->prepare(
                "INSERT INTO users (name, email, password) VALUES (?, ?, ?)"
            );
            $stmt->execute([$name, $email, $hashed]);

            $success = "Account created! You can now log in.";
        }
    }
}
?>
<!DOCTYPE html>
<html><body>
<h2>Create Account</h2>

<?php if ($error):   ?><p style="color:red"><?= $error   ?></p><?php endif; ?>
<?php if ($success): ?><p style="color:green"><?= $success ?></p><?php endif; ?>

<form method="POST">
  <input type="text"     name="name"     placeholder="Full Name"  required>
  <input type="email"    name="email"    placeholder="Email"      required>
  <input type="password" name="password" placeholder="Password"   required>
  <button type="submit">Sign Up</button>
</form>
<p>Already have an account? <a href="login.php">Log In</a></p>
</body></html>
⚠️ Important: password_hash()

password_hash($password, PASSWORD_DEFAULT) turns "hello123" into a scrambled string like $2y$10$abc.... Even if someone steals your database, they cannot read the original passwords. Always use this function.

💡 What does trim() do?

trim() removes extra spaces from the start and end of a value. For example, " hello " becomes "hello". This stops users from signing up with emails like " user@gmail.com " (with accidental spaces).

04
Log In Page
Verify credentials and start a PHP session

The login page checks the email and password the user types. It finds the user in the database, then uses password_verify() to check the password. If it matches, it starts a session — PHP's way of remembering "this user is logged in."

How the login process works
User submits form
Find user by email
password_verify()
session_start() ✓
Go to dashboard
PHPlogin.php
<?php
session_start();     // Always call this FIRST — before any output
require_once 'db.php';

// If the user is already logged in, send them to dashboard
if (isset($_SESSION['user_id'])) {
    header("Location: dashboard.php");
    exit;
}

$error = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    $email    = trim($_POST['email']);
    $password = $_POST['password'];

    // Step 1: Check fields are not empty
    if (empty($email) || empty($password)) {
        $error = "Please enter your email and password.";
    } else {
        // Step 2: Find user by email (prepared statement)
        $stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
        $stmt->execute([$email]);
        $user = $stmt->fetch();

        // Step 3: Check user exists AND password matches
        if ($user && password_verify($password, $user['password'])) {

            // Step 4: Save user info in session (login success!)
            $_SESSION['user_id']   = $user['id'];
            $_SESSION['user_name'] = $user['name'];
            $_SESSION['user_email']= $user['email'];

            // Step 5: Send to dashboard
            header("Location: dashboard.php");
            exit;

        } else {
            // Generic error — never say "wrong password" specifically
            $error = "Invalid email or password.";
        }
    }
}
?>
<!DOCTYPE html>
<html><body>
<h2>Log In</h2>
<?php if ($error): ?>
  <p style="color:red"><?= $error ?></p>
<?php endif; ?>
<form method="POST">
  <input type="email"    name="email"    placeholder="Email"    required>
  <input type="password" name="password" placeholder="Password" required>
  <button type="submit">Log In</button>
</form>
<p>No account yet? <a href="signup.php">Sign Up</a></p>
</body></html>
💡 What is a Session?

A session keeps data on the server for one user. When you set $_SESSION['user_id'], PHP saves a small cookie in the user's browser. On every next page, PHP reads that cookie and knows who the user is. Think of it as a wristband at an event — you get it at the door and show it on every ride.

⚠️ Why use a generic error message?

We say "Invalid email or password." — not "Wrong password." This is on purpose. If you say "Wrong password," a hacker knows the email is correct and keeps guessing passwords. A generic message gives nothing away.

05
Log Out Page + Protected Dashboard
Destroy the session and protect private pages

Logging out means you destroy the session. This removes all saved user data from the server. You also need to protect private pages — if a user is not logged in, send them back to the login page right away.

logout.php — 4 clear steps
PHPlogout.php
<?php
session_start();

// Step 1: Clear all session variables
$_SESSION = [];

// Step 2: Delete the session cookie from the browser
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(
        session_name(),
        '',
        time() - 42000,   // Set expiry to the past to delete it
        $params["path"],
        $params["domain"]
    );
}

// Step 3: Destroy the session data on the server
session_destroy();

// Step 4: Send the user back to the login page
header("Location: login.php");
exit;
?>
dashboard.php — a protected page

Add this guard block at the very top of any page you want to protect. If the user is not logged in, PHP sends them to login.php right away.

আপনি যে পেজটি রক্ষা করতে চান তার একদম উপরে এই গার্ড ব্লক যোগ করুন। ব্যবহারকারী লগইন না থাকলে PHP তাকে সাথে সাথে login.php তে পাঠায়।

PHPdashboard.php
<?php
session_start();

// Guard: if not logged in → send to login page immediately
if (!isset($_SESSION['user_id'])) {
    header("Location: login.php");
    exit;
}
?>
<!DOCTYPE html>
<html><body>

<h2>
  Welcome, <?= htmlspecialchars($_SESSION['user_name']) ?>!
</h2>
<p>You are logged in as <?= htmlspecialchars($_SESSION['user_email']) ?></p>

<a href="logout.php">Log Out</a>

</body></html>
Dashboard preview
localhost/myauth/dashboard.php
Welcome, Rahim!
You are logged in as rahim@example.com
🚪 Log Out
💡 Always use htmlspecialchars()

When you show user data on a page, always wrap it in htmlspecialchars(). This stops XSS attacks where a user saves HTML or JavaScript in their name (for example, <script>steal cookies</script>).

06
Security Checklist
5 rules every PHP developer must follow
1. Never store plain passwords. Always use password_hash() to save passwords. Use password_verify() to check them.
2. Use prepared statements. Always use $pdo->prepare() with ? placeholders. Never put a variable directly in an SQL string.
3. Escape all output. Always use htmlspecialchars() when you show user data in HTML. This blocks XSS attacks.
4. Validate all inputs. Use empty(), filter_var(), and strlen() to check every value before using it.
5. Use HTTPS in production. On a live server, always add an SSL certificate. HTTPS encrypts all data sent between the user and your server.
# Rule PHP Function Blocks
1Hash passwordspassword_hash()Data theft
2Prepared statements$pdo->prepare()SQL Injection
3Escape outputhtmlspecialchars()XSS
4Validate inputsfilter_var(), empty()Bad data
5HTTPSSSL certificateMan-in-the-middle
⚠️ SQL Injection — the most common attack

Never build SQL like this: "SELECT * FROM users WHERE email = '$email'". A hacker can type ' OR 1=1 -- as the email and log in without a password. Always use prepare() with ? placeholders instead.

Unsafe vs safe — see the difference
PHP❌ UNSAFE — Never do this
// WRONG — SQL injection possible
$email = $_POST['email'];
$sql   = "SELECT * FROM users WHERE email = '$email'";
$result = $pdo->query($sql);
PHP✅ SAFE — Always do this
// CORRECT — prepared statement with placeholder
$email = $_POST['email'];
$stmt  = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user  = $stmt->fetch();
07
Test Your Knowledge
5 questions to check what you learned
Progress
0 / 5
Question 1 of 5
Which PHP function safely checks a password against its hash?
✓ Correct! password_verify() safely checks the typed password against the hashed one in the database.
✗ Not quite. The answer is password_verify($password, $hash). Functions like md5 and sha1 are insecure for passwords.
Question 2 of 5
What must you call at the top of every PHP page that uses sessions?
✓ Correct! session_start() must be the very first line before any HTML output.
✗ The correct answer is session_start(). It must come before any HTML output, even a blank line.
Question 3 of 5
What does $pdo->prepare("SELECT * FROM users WHERE id = ?") protect against?
✓ Correct! Prepared statements separate your SQL from user data, which blocks SQL injection completely.
✗ Prepared statements protect against SQL Injection. Hackers try to inject SQL code through form inputs.
Question 4 of 5
What does session_destroy() do?
✓ Correct! session_destroy() removes all session data from the server. This is the core of the log out process.
session_destroy() destroys all session data stored on the server — this is what logs the user out.
Question 5 of 5
Which function do you use to show user data safely in HTML and prevent XSS?
✓ Correct! htmlspecialchars() converts characters like < and > to safe HTML entities, stopping scripts from running.
✗ The correct answer is htmlspecialchars($data). It converts HTML special characters to safe entities so scripts cannot run.