Skip to main content
PHP Backend Development Tutorial
CHAPTER 17 Beginner

Building a Complete Backend Project

Updated: May 14, 2026
35 min read

# CHAPTER 17

Building a Complete Backend Project

1. Introduction

Theoretical knowledge is useless without practical application. In this chapter, we will synthesize everything we have learned—Forms, Validation, Sessions, PDO, Prepared Statements, Password Hashing, and MVC architecture—to build the backbone of a real-world project: a Secure Task Management System.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Architect a multi-table database schema.
  • Build a secure Registration and Login workflow.
  • Create a protected dashboard with CRUD functionality.
  • Structure the application using modular files.

3. Project Overview

We are building a "Task Manager."
  • Users can register and log in securely.
  • Logged-in users can view their own private tasks.
  • Users can Create new tasks, Mark them as complete (Update), and Delete them.
  • Users cannot see tasks belonging to other users.

4. Step 1: The Database Schema

First, open phpMyAdmin and execute these SQL commands to create two linked tables.
sql
1234567891011121314151617
CREATE DATABASE task_app;
USE task_app;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    task_name VARCHAR(255) NOT NULL,
    is_completed TINYINT(1) DEFAULT 0,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

5. Step 2: The Core Configuration (config.php)

This file is required at the top of every other file. It starts the session and connects to the database.
php
12345678910111213141516
<?php
// config.php
session_start();

$host = &#039;localhost';
$db   = &#039;task_app';
$user = &#039;root';
$pass = &#039;';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Database connection failed.");
}
?>

6. Step 3: Registration and Login (auth.php)

We will handle both login and registration in one file for simplicity.
php
123456789101112131415161718192021222324252627282930313233343536373839
<?php
// auth.php
require &#039;config.php';

if ($_SERVER[&#039;REQUEST_METHOD'] == 'POST') {
    $action = $_POST[&#039;action']; // 'register' or 'login'
    $username = trim($_POST[&#039;username']);
    $password = $_POST[&#039;password'];

    if ($action == &#039;register') {
        $hash = password_hash($password, PASSWORD_DEFAULT);
        $stmt = $pdo->prepare("INSERT INTO users (username, password_hash) VALUES (?, ?)");
        $stmt->execute([$username, $hash]);
        echo "Registration successful! Please login.";
    } 
    elseif ($action == &#039;login') {
        $stmt = $pdo->prepare("SELECT id, password_hash FROM users WHERE username = ?");
        $stmt->execute([$username]);
        $user = $stmt->fetch();

        if ($user && password_verify($password, $user[&#039;password_hash'])) {
            $_SESSION[&#039;user_id'] = $user['id'];
            header("Location: dashboard.php");
            exit;
        } else {
            echo "Invalid credentials.";
        }
    }
}
?>

<!-- Simple HTML Form -->
<h2>Register / Login</h2>
<form method="POST" action="auth.php">
    <input type="text" name="username" placeholder="Username" required>
    <input type="password" name="password" placeholder="Password" required>
    <button type="submit" name="action" value="login">Login</button>
    <button type="submit" name="action" value="register">Register</button>
</form>

7. Step 4: The Protected Dashboard (dashboard.php)

This page enforces Access Control. If you aren't logged in, you get kicked out. It then uses the $_SESSION['user_id'] to fetch *only* your tasks.
php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
<?php
// dashboard.php
require &#039;config.php';

// Access Control
if (!isset($_SESSION[&#039;user_id'])) {
    header("Location: auth.php");
    exit;
}

$user_id = $_SESSION[&#039;user_id'];

// Handle Task Creation
if ($_SERVER[&#039;REQUEST_METHOD'] == 'POST' && isset($_POST['new_task'])) {
    $task_name = htmlspecialchars($_POST[&#039;task_name']);
    $stmt = $pdo->prepare("INSERT INTO tasks (user_id, task_name) VALUES (?, ?)");
    $stmt->execute([$user_id, $task_name]);
}

// Handle Task Deletion
if (isset($_GET[&#039;delete'])) {
    $task_id = $_GET[&#039;delete'];
    // SECURITY: Ensure the task being deleted belongs to the logged-in user!
    $stmt = $pdo->prepare("DELETE FROM tasks WHERE id = ? AND user_id = ?");
    $stmt->execute([$task_id, $user_id]);
}

// Read Tasks
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE user_id = ?");
$stmt->execute([$user_id]);
$tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

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

<!-- CREATE FORM -->
<form method="POST">
    <input type="text" name="task_name" required>
    <button type="submit" name="new_task">Add Task</button>
</form>

<!-- READ / DELETE UI -->
<ul>
    <?php foreach ($tasks as $t): ?>
        <li>
            <?php echo $t[&#039;task_name']; ?> 
            <a href="?delete=<?php echo $t[&#039;id']; ?>" style="color:red;">[X]</a>
        </li>
    <?php endforeach; ?>
</ul>

8. Reviewing the Security

Look closely at the Delete function in dashboard.php: DELETE FROM tasks WHERE id = ? AND user_id = ? If we only deleted by id = ?, a malicious user could type dashboard.php?delete=5 and delete another user's task! By enforcing AND user_id = ? using the unhackable Server Session ID, we ensure users can only delete their own data. This is Authorization security.

9. Best Practices

  • Modularizing UI: In a full application, the HTML forms and lists in dashboard.php would be moved to a views/ folder, adhering strictly to the MVC architecture.

10. Summary of the Workflow

You just built a full-stack application!
  1. 1. Database created via phpMyAdmin.
  1. 2. Form captures input ($_POST).
  1. 3. Logic hashes the password and saves it (Prepared Statements).
  1. 4. Login verifies the hash and creates a Session ($_SESSION).
  1. 5. Dashboard checks the Session (Access Control).
  1. 6. Dashboard executes CRUD operations tied explicitly to that Session ID.

11. Next Chapter Recommendation

Your application works perfectly on your local machine. Now it's time to show it to the world. Proceed to Chapter 18: Deploying PHP Applications.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·