Project Overview

A To-Do List Application allows users to add, view, edit, and delete tasks. This project helps in understanding CRUD (Create, Read, Update, Delete) operations, form handling, and database interactions using PHP and MySQL.

Prerequisites

Before starting, ensure you have the following:

  • Web Server: Apache (using XAMPP, WAMP, or MAMP)
  • PHP: Version 7.4 or higher
  • MySQL: For database management
  • Code Editor: VS Code, Sublime Text, PHPStorm, etc.
  • Composer: For dependency management (optional)

Step-by-Step Procedure

1. Setting Up the Development Environment

  1. Install XAMPP:
    • Download from XAMPP Official Website.
    • Follow the installation wizard and install it in the default directory.
  2. Start Apache and MySQL:
    • Open the XAMPP Control Panel.
    • Start the Apache and MySQL modules.

2. Creating the Database

  1. Access phpMyAdmin:
    • Navigate to http://localhost/phpmyadmin/ in your browser.
  2. Create a New Database:
    • Click on “New” in the left sidebar.
    • Name the database todo_app.
    • Choose “utf8mb4_unicode_ci” as the collation.
    • Click “Create”.
  3. Create a tasks Table:
    • Select the todo_app database.
    • Click on “New” to create a table.
    • Define the table with the following fields:
    Field Type Null Key Default Extra id INT NO PRI NULL AUTO_INCREMENT title VARCHAR(255) NO NULL status ENUM NO ‘pending’ created_at TIMESTAMP NO CURRENT_TIMESTAMP
    • Click “Save”.

3. Project Structure

Organize your project files as follows:

todo-app/
├── assets/
│   ├── css/
│   │   └── styles.css
│   └── js/
│       └── scripts.js
├── config/
│   └── db.php
├── templates/
│   ├── header.php
│   └── footer.php
├── add_task.php
├── edit_task.php
├── delete_task.php
├── index.php
└── README.md

4. Configuration

a. Database Connection (config/db.php)

Create a file named db.php inside the config directory to handle database connections.

<?php
// config/db.php

$host = 'localhost';
$db   = 'todo_app';
$user = 'root'; // Default XAMPP MySQL user
$pass = '';     // Default XAMPP MySQL password is empty
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Enable exceptions
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // Fetch associative arrays
    PDO::ATTR_EMULATE_PREPARES   => false,                  // Disable emulation
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    // Handle connection errors
    throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
?>

5. Creating Reusable Templates

a. Header (templates/header.php)
<?php
// templates/header.php
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>To-Do List Application</title>
    <link rel="stylesheet" href="/todo-app/assets/css/styles.css">
</head>
<body>
    <header>
        <h1>To-Do List Application</h1>
        <nav>
            <a href="/todo-app/index.php">Home</a>
            <a href="/todo-app/add_task.php">Add Task</a>
        </nav>
    </header>
    <main>
b. Footer (templates/footer.php)
<?php
// templates/footer.php
?>
    </main>
    <footer>
        <p>&copy; <?php echo date("Y"); ?> Your Company Name</p>
    </footer>
    <script src="/todo-app/assets/js/scripts.js"></script>
</body>
</html>

6. Styling the Application (assets/css/styles.css)

Add basic styles to enhance the appearance.

/* assets/css/styles.css */

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

header, footer {
    background-color: #333;
    color: #fff;
    padding: 10px 20px;
}

header h1, footer p {
    margin: 0;
}

nav a {
    color: #fff;
    margin-right: 15px;
    text-decoration: none;
}

main {
    padding: 20px;
}

table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
}

table, th, td {
    border: 1px solid #ddd;
}

th, td {
    padding: 12px;
    text-align: left;
}

th {
    background-color: #f4f4f4;
}

a {
    color: #007BFF;
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

button {
    padding: 8px 12px;
    background-color: #28a745;
    color: #fff;
    border: none;
    cursor: pointer;
}

button:hover {
    background-color: #218838;
}

.form-group {
    margin-bottom: 15px;
}

label {
    display: block;
    margin-bottom: 5px;
}

input[type="text"] {
    width: 100%;
    padding: 8px;
    box-sizing: border-box;
}

select {
    width: 100%;
    padding: 8px;
    box-sizing: border-box;
}

7. Building the Home Page (index.php)

This page displays all tasks with options to edit or delete them.

<?php
// index.php

require 'config/db.php';
require 'templates/header.php';

// Fetch all tasks
$stmt = $pdo->query('SELECT * FROM tasks ORDER BY created_at DESC');
$tasks = $stmt->fetchAll();
?>

<h2>My To-Do List</h2>

<?php if ($tasks): ?>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Title</th>
                <th>Status</th>
                <th>Created At</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($tasks as $task): ?>
                <tr>
                    <td><?php echo htmlspecialchars($task['id']); ?></td>
                    <td><?php echo htmlspecialchars($task['title']); ?></td>
                    <td><?php echo htmlspecialchars($task['status']); ?></td>
                    <td><?php echo htmlspecialchars($task['created_at']); ?></td>
                    <td>
                        <a href="edit_task.php?id=<?php echo $task['id']; ?>">Edit</a> |
                        <a href="delete_task.php?id=<?php echo $task['id']; ?>" onclick="return confirm('Are you sure you want to delete this task?');">Delete</a>
                    </td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
<?php else: ?>
    <p>No tasks found. <a href="add_task.php">Add a new task</a>.</p>
<?php endif; ?>

<?php
require 'templates/footer.php';
?>

8. Adding New Tasks (add_task.php)

This page allows users to add new tasks to the list.

<?php
// add_task.php

require 'config/db.php';
require 'templates/header.php';

$errors = [];
$success = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and validate input
    $title = trim($_POST['title']);
    $status = trim($_POST['status']);

    if (empty($title)) {
        $errors[] = 'Task title is required.';
    }

    if (empty($status)) {
        $errors[] = 'Task status is required.';
    } elseif (!in_array($status, ['pending', 'completed'])) {
        $errors[] = 'Invalid task status.';
    }

    if (empty($errors)) {
        // Insert into database
        $stmt = $pdo->prepare('INSERT INTO tasks (title, status) VALUES (?, ?)');
        if ($stmt->execute([$title, $status])) {
            $success = 'Task added successfully.';
            // Clear form fields
            $title = $status = '';
        } else {
            $errors[] = 'There was an error adding the task. Please try again.';
        }
    }
}
?>

<h2>Add New Task</h2>

<?php if (!empty($errors)): ?>
    <div class="error">
        <ul>
            <?php foreach($errors as $error): ?>
                <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="success">
        <p><?php echo htmlspecialchars($success); ?></p>
    </div>
<?php endif; ?>

<form action="add_task.php" method="POST">
    <div class="form-group">
        <label for="title">Task Title:</label>
        <input type="text" id="title" name="title" value="<?php echo htmlspecialchars($title ?? ''); ?>" required>
    </div>

    <div class="form-group">
        <label for="status">Status:</label>
        <select id="status" name="status" required>
            <option value="pending" <?php echo (isset($status) && $status === 'pending') ? 'selected' : ''; ?>>Pending</option>
            <option value="completed" <?php echo (isset($status) && $status === 'completed') ? 'selected' : ''; ?>>Completed</option>
        </select>
    </div>

    <button type="submit">Add Task</button>
</form>

<?php
require 'templates/footer.php';
?>

9. Editing Tasks (edit_task.php)

This page allows users to edit existing tasks.

<?php
// edit_task.php

require 'config/db.php';
require 'templates/header.php';

$errors = [];
$success = '';

// Get task ID from URL
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// Fetch existing task
$stmt = $pdo->prepare('SELECT * FROM tasks WHERE id = ?');
$stmt->execute([$id]);
$task = $stmt->fetch();

if (!$task) {
    echo "<p>Task not found.</p>";
    require 'templates/footer.php';
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and validate input
    $title = trim($_POST['title']);
    $status = trim($_POST['status']);

    if (empty($title)) {
        $errors[] = 'Task title is required.';
    }

    if (empty($status)) {
        $errors[] = 'Task status is required.';
    } elseif (!in_array($status, ['pending', 'completed'])) {
        $errors[] = 'Invalid task status.';
    }

    if (empty($errors)) {
        // Update in database
        $stmt = $pdo->prepare('UPDATE tasks SET title = ?, status = ? WHERE id = ?');
        if ($stmt->execute([$title, $status, $id])) {
            $success = 'Task updated successfully.';
            // Refresh task data
            $stmt = $pdo->prepare('SELECT * FROM tasks WHERE id = ?');
            $stmt->execute([$id]);
            $task = $stmt->fetch();
        } else {
            $errors[] = 'There was an error updating the task. Please try again.';
        }
    }
}
?>

<h2>Edit Task</h2>

<?php if (!empty($errors)): ?>
    <div class="error">
        <ul>
            <?php foreach($errors as $error): ?>
                <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="success">
        <p><?php echo htmlspecialchars($success); ?></p>
    </div>
<?php endif; ?>

<form action="edit_task.php?id=<?php echo $id; ?>" method="POST">
    <div class="form-group">
        <label for="title">Task Title:</label>
        <input type="text" id="title" name="title" value="<?php echo htmlspecialchars($task['title']); ?>" required>
    </div>

    <div class="form-group">
        <label for="status">Status:</label>
        <select id="status" name="status" required>
            <option value="pending" <?php echo ($task['status'] === 'pending') ? 'selected' : ''; ?>>Pending</option>
            <option value="completed" <?php echo ($task['status'] === 'completed') ? 'selected' : ''; ?>>Completed</option>
        </select>
    </div>

    <button type="submit">Update Task</button>
</form>

<?php
require 'templates/footer.php';
?>

10. Deleting Tasks (delete_task.php)

This script handles the deletion of tasks.

<?php
// delete_task.php

require 'config/db.php';

// Get task ID from URL
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// Delete task
$stmt = $pdo->prepare('DELETE FROM tasks WHERE id = ?');
$stmt->execute([$id]);

// Redirect back to home page
header('Location: index.php');
exit;
?>

11. Testing the Application

  1. Access the Application:
    • Navigate to http://localhost/todo-app/index.php in your browser.
  2. Add a New Task:
    • Click on “Add Task”.
    • Fill in the task details and submit.
    • Verify that the task appears on the home page.
  3. Edit a Task:
    • Click on “Edit” next to a task.
    • Modify the details and submit.
    • Ensure the changes are reflected on the home page.
  4. Delete a Task:
    • Click on “Delete” next to a task.
    • Confirm the deletion.
    • Verify that the task is removed from the list.

12. Deployment Considerations

When deploying to a live server:

  • Secure Database Credentials: Use environment variables or secure configuration methods.
  • Use HTTPS: Ensure your website uses HTTPS for encrypted data transmission.
  • Regular Backups: Implement regular backups of your database and files.
  • Error Reporting: Disable detailed error messages in production to prevent information leakage. // In production, set error reporting to minimal ini_set('display_errors', 0); ini_set('log_errors', 1);
  • Update Dependencies: Keep PHP and all libraries updated to their latest versions to patch security vulnerabilities.
Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *