Paramclasses Academy - Blog

Tutorials Details

PHP CRUD Operations – Build a Complete Student Management System

PHP CRUD Operations – Build a Complete Student Management System

October 10, 2026

Meta Title: Core PHP Module 10: PHP CRUD Operations Tutorial

Meta Description: Learn PHP CRUD operations step by step. Build a complete student management system using Core PHP, MySQL, PDO, prepared statements, HTML forms, and validation.

Focus Keyword: PHP CRUD operations

Secondary Keywords: Core PHP CRUD tutorial, PHP MySQL CRUD example, student management system in PHP, PHP insert update delete, PHP PDO tutorial

URL Slug: php-crud-operations-student-management-system


Introduction

Welcome to Module 10 of our Core PHP tutorial series!

In Module 9, we learned how to connect PHP to MySQL, insert records, retrieve data, and update and delete records.

Now it is time to combine those concepts into a practical project.

In this tutorial, we will build a Student Management System using Core PHP and MySQL. The application will allow users to add new students, view student records, edit existing details, and delete records.

We will use PHP, MySQL, PDO, HTML, and CSS. The project will be beginner-friendly and will run locally using XAMPP.

By the end of this module, you will understand how CRUD works in a real PHP application and how to organize a small project into multiple files.

1. What Are CRUD Operations in PHP?

CRUD stands for four basic database operations.

Operation Meaning SQL command
Create Add a new student INSERT
Read Display student records SELECT
Update Edit student details UPDATE
Delete Remove a student DELETE

For example, a college might use a student management system to maintain student names, email addresses, and courses.

Instead of manually changing database records, an administrator can manage them through a web interface.

How does the application work?

  1. The user opens the student listing page.

  2. PHP retrieves records from MySQL.

  3. The user adds or edits a student's information.

  4. PHP validates the submitted data.

  5. PHP executes a prepared SQL statement.

  6. The application redirects the user to the listing page.

This pattern is used in many applications, including inventory systems, employee directories, product management systems, and content management systems.

2. Requirements for the Project

Before starting, install or prepare the following:

  • XAMPP

  • PHP

  • MySQL or MariaDB

  • A web browser

  • A code editor such as VS Code

Start Apache and MySQL from the XAMPP Control Panel.

Open phpMyAdmin at:

http://localhost/phpmyadmin/

3. Create the Database and Table

Open phpMyAdmin, select the SQL tab, and execute the following query:

CREATE DATABASE student_db;

Select the database:

USE student_db;

Create the students table:

CREATE TABLE students (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL,
    course VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

This table stores each student's ID, name, email address, course, and registration time.

If you already created student_db and the students table in Module 9, you can reuse them rather than creating them again.

4. Create the Project Folder

Inside your XAMPP htdocs directory, create a folder named:

student_management

For a typical Windows installation, the path is:

C:\xampp\htdocs\student_management

Create the following files inside this folder:

student_management/
│
├── db.php
├── functions.php
├── index.php
├── create.php
├── edit.php
├── delete.php
└── style.css

Each file has a specific responsibility:

  • db.php: Connects to the database.

  • functions.php: Contains shared validation and output helpers.

  • index.php: Displays all students.

  • create.php: Adds a student.

  • edit.php: Updates student details.

  • delete.php: Deletes a student.

  • style.css: Styles the pages.

5. Connect PHP to MySQL

Create db.php:

<?php

$host = "localhost";
$dbname = "student_db";
$username = "root";
$password = "";

try {
    $pdo = new PDO(
        "mysql:host=$host;dbname=$dbname;charset=utf8mb4",
        $username,
        $password,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        ]
    );

} catch (PDOException $e) {
    error_log($e->getMessage());

    http_response_code(500);
    exit("Unable to connect to the database. Please try again later.");
}

Explanation

The PDO object creates the connection between PHP and MySQL.

The database name is student_db, and the character set is utf8mb4.

PDO::ERRMODE_EXCEPTION tells PDO to throw exceptions when database operations fail.

The exception is logged privately, while visitors receive a generic error message. This avoids exposing database credentials or internal details.

Note: The username root and empty password are common defaults for a local XAMPP setup, but your configuration may differ. Use a dedicated, least-privilege database account with a strong password for production.

6. Create Shared Helper Functions

Create a file named functions.php:

<?php

function escapeHtml($value)
{
    return htmlspecialchars(
        (string) $value,
        ENT_QUOTES,
        "UTF-8"
    );
}

function validateStudent($name, $email, $course)
{
    $errors = [];

    if ($name === "") {
        $errors[] = "Name is required.";
    } elseif (strlen($name) > 100) {
        $errors[] = "Name must not exceed 100 characters.";
    }

    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors[] = "Please enter a valid email address.";
    } elseif (strlen($email) > 150) {
        $errors[] = "Email must not exceed 150 characters.";
    }

    if ($course === "") {
        $errors[] = "Course is required.";
    } elseif (strlen($course) > 100) {
        $errors[] = "Course must not exceed 100 characters.";
    }

    return $errors;
}

function validStudentId($value)
{
    $id = filter_var(
        $value,
        FILTER_VALIDATE_INT,
        [
            "options" => [
                "min_range" => 1
            ]
        ]
    );

    return $id === false ? null : $id;
}

Why use helper functions?

Instead of repeating the same code in every file, we can define functions once and reuse them.

escapeHtml() converts special characters into HTML-safe output. This is important when displaying names, emails, and other values that may contain untrusted text.

validateStudent() checks that required fields are provided and that their lengths and formats are acceptable.

validStudentId() checks whether an ID is a valid positive integer.

These functions make the application easier to maintain.

7. Read and Display Student Records

Create index.php:

<?php

require_once "db.php";
require_once "functions.php";

$stmt = $pdo->query(
    "SELECT id, name, email, course, created_at
     FROM students
     ORDER BY id DESC"
);

$students = $stmt->fetchAll();

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Student Management System</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<div class="container">

    <h1>Student Management System</h1>

    <a class="button" href="create.php">+ Add New Student</a>

    <h2>Student Records</h2>

    <div class="table-wrapper">
        <table>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Course</th>
                    <th>Created At</th>
                    <th>Actions</th>
                </tr>
            </thead>

            <tbody>

            <?php if ($students): ?>

                <?php foreach ($students as $student): ?>
                    <tr>
                        <td><?= escapeHtml($student["id"]) ?></td>
                        <td><?= escapeHtml($student["name"]) ?></td>
                        <td><?= escapeHtml($student["email"]) ?></td>
                        <td><?= escapeHtml($student["course"]) ?></td>
                        <td><?= escapeHtml($student["created_at"]) ?></td>

                        <td class="actions">
                            <a href="edit.php?id=<?= (int) $student["id"] ?>">
                                Edit
                            </a>

                            <form
                                action="delete.php"
                                method="POST"
                                onsubmit="return confirm('Delete this student?');"
                            >
                                <input
                                    type="hidden"
                                    name="id"
                                    value="<?= (int) $student["id"] ?>"
                                >

                                <button type="submit" class="delete-button">
                                    Delete
                                </button>
                            </form>
                        </td>
                    </tr>
                <?php endforeach; ?>

            <?php else: ?>

                <tr>
                    <td colspan="6">No student records found.</td>
                </tr>

            <?php endif; ?>

            </tbody>
        </table>
    </div>

</div>

</body>
</html>

How does this page work?

The SQL query retrieves all student records:

SELECT id, name, email, course, created_at
FROM students
ORDER BY id DESC;

The fetchAll() method retrieves the rows into an array. The foreach loop displays each student in a table row.

The Edit link opens edit.php with the student's ID. The Delete form sends a POST request to delete.php.

We use HTML escaping when displaying database values to help prevent stored HTML or JavaScript from being interpreted as active markup.

8. Create a New Student

Create create.php:

<?php

require_once "db.php";
require_once "functions.php";

$name = "";
$email = "";
$course = "";
$errors = [];

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $name = trim($_POST["name"] ?? "");
    $email = trim($_POST["email"] ?? "");
    $course = trim($_POST["course"] ?? "");

    $errors = validateStudent($name, $email, $course);

    if (!$errors) {
        $sql = "INSERT INTO students (name, email, course)
                VALUES (:name, :email, :course)";

        $stmt = $pdo->prepare($sql);

        $stmt->execute([
            "name" => $name,
            "email" => $email,
            "course" => $course
        ]);

        header("Location: index.php");
        exit;
    }
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Add Student</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<div class="container">

    <h1>Add New Student</h1>

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

    <form method="POST" action="">

        <label for="name">Student Name</label>
        <input
            type="text"
            id="name"
            name="name"
            maxlength="100"
            value="<?= escapeHtml($name) ?>"
            required
        >

        <label for="email">Email Address</label>
        <input
            type="email"
            id="email"
            name="email"
            maxlength="150"
            value="<?= escapeHtml($email) ?>"
            required
        >

        <label for="course">Course</label>
        <input
            type="text"
            id="course"
            name="course"
            maxlength="100"
            value="<?= escapeHtml($course) ?>"
            required
        >

        <button type="submit">Save Student</button>

    </form>

    <p><a href="index.php">Back to Student List</a></p>

</div>

</body>
</html>

Explanation

First, PHP checks whether the form was submitted using POST.

It then collects the form values, validates them, and inserts the record using a prepared statement.

After successful insertion, the browser is redirected to index.php.

The redirect prevents a refresh of the listing page from resubmitting the same form. It does not replace validation or duplicate-prevention rules.

9. Edit an Existing Student

Create edit.php:

<?php

require_once "db.php";
require_once "functions.php";

$id = validStudentId($_GET["id"] ?? null);

if ($id === null) {
    http_response_code(400);
    exit("Invalid student ID.");
}

$stmt = $pdo->prepare(
    "SELECT id, name, email, course
     FROM students
     WHERE id = :id"
);

$stmt->execute([
    "id" => $id
]);

$student = $stmt->fetch();

if (!$student) {
    http_response_code(404);
    exit("Student not found.");
}

$name = $student["name"];
$email = $student["email"];
$course = $student["course"];
$errors = [];

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $name = trim($_POST["name"] ?? "");
    $email = trim($_POST["email"] ?? "");
    $course = trim($_POST["course"] ?? "");

    $errors = validateStudent($name, $email, $course);

    if (!$errors) {
        $sql = "UPDATE students
                SET name = :name,
                    email = :email,
                    course = :course
                WHERE id = :id";

        $stmt = $pdo->prepare($sql);

        $stmt->execute([
            "name" => $name,
            "email" => $email,
            "course" => $course,
            "id" => $id
        ]);

        header("Location: index.php");
        exit;
    }
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Edit Student</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<div class="container">

    <h1>Edit Student</h1>

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

    <form method="POST" action="">

        <label for="name">Student Name</label>
        <input
            type="text"
            id="name"
            name="name"
            maxlength="100"
            value="<?= escapeHtml($name) ?>"
            required
        >

        <label for="email">Email Address</label>
        <input
            type="email"
            id="email"
            name="email"
            maxlength="150"
            value="<?= escapeHtml($email) ?>"
            required
        >

        <label for="course">Course</label>
        <input
            type="text"
            id="course"
            name="course"
            maxlength="100"
            value="<?= escapeHtml($course) ?>"
            required
        >

        <button type="submit">Update Student</button>

    </form>

    <p><a href="index.php">Back to Student List</a></p>

</div>

</body>
</html>

How does the update process work?

Suppose the student ID is 3.

The following URL opens the edit page for that student:

http://localhost/student_management/edit.php?id=3

PHP validates the ID and retrieves the matching record. The form displays the existing values.

When the form is submitted, PHP validates the new information and executes an UPDATE query for that ID.

The ID is validated and passed as a prepared-statement parameter. In a multi-user application, you must also check whether the current user is authorized to edit that student.

10. Delete a Student Safely

Create delete.php:

<?php

require_once "db.php";
require_once "functions.php";

if ($_SERVER["REQUEST_METHOD"] !== "POST") {
    http_response_code(405);
    header("Allow: POST");
    exit("Method not allowed.");
}

$id = validStudentId($_POST["id"] ?? null);

if ($id === null) {
    http_response_code(400);
    exit("Invalid student ID.");
}

$stmt = $pdo->prepare(
    "DELETE FROM students WHERE id = :id"
);

$stmt->execute([
    "id" => $id
]);

header("Location: index.php");
exit;

Why use POST instead of GET?

Deleting a record changes database data. A GET request should not be used to perform that kind of action.

This example accepts deletion requests only through POST and validates the student ID before executing the query.

However, POST alone does not protect an application from cross-site request forgery. Before deploying this project publicly, add a CSRF token, authentication, and authorization checks.

11. Add CSS Styling

Create style.css:

* {
    box-sizing: border-box;
}

body {
    font-family: Arial, sans-serif;
    background: #f4f6f9;
    margin: 0;
    padding: 20px;
    color: #222;
}

.container {
    max-width: 1100px;
    margin: 30px auto;
    background: #ffffff;
    padding: 25px;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
}

h1,
h2 {
    margin-top: 0;
}

label {
    display: block;
    margin-top: 15px;
    margin-bottom: 6px;
    font-weight: bold;
}

input {
    width: 100%;
    padding: 10px;
    border: 1px solid #cccccc;
    border-radius: 4px;
}

button,
.button {
    display: inline-block;
    margin-top: 15px;
    padding: 10px 15px;
    border: none;
    border-radius: 4px;
    background: #1769aa;
    color: #ffffff;
    text-decoration: none;
    cursor: pointer;
    font-size: 14px;
}

.table-wrapper {
    width: 100%;
    overflow-x: auto;
}

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

th,
td {
    border: 1px solid #dddddd;
    padding: 10px;
    text-align: left;
}

th {
    background: #eaf1f8;
}

.actions {
    white-space: nowrap;
}

.actions form {
    display: inline;
}

.actions form button {
    margin-top: 0;
}

.delete-button {
    background: #b42318;
}

.errors {
    padding: 10px;
    margin-bottom: 15px;
    border: 1px solid #d92d20;
    background: #fff1f0;
    color: #8a1c13;
}

@media (max-width: 600px) {
    .container {
        padding: 15px;
        margin: 10px auto;
    }
}

This stylesheet gives the application a clean layout, readable forms, styled buttons, and a horizontally scrollable table on small screens.

12. Run the Student Management System

Follow these steps to test the complete project.

  1. Start Apache and MySQL in XAMPP.

  2. Confirm that the student_db database and students table exist.

  3. Save all seven project files in the student_management folder.

  4. Open your browser.

  5. Visit the following URL:

http://localhost/student_management/

You should see the Student Management System page.

Test the features in this order:

  • Click Add New Student and add a student.

  • Confirm that the new record appears on the listing page.

  • Click Edit and change the student's course.

  • Confirm that the updated information appears.

  • Click Delete and confirm the action.

  • Verify that the record is removed from the listing.

If the page shows a database connection error, check the database credentials and ensure MySQL is running.

13. Common Problems and Solutions

Problem 1: Database connection failed

Cause: The database service may be stopped, or the username, password, or database name may be incorrect.

Solution: Check the connection settings in db.php and confirm that student_db exists.

Problem 2: Page not found

Cause: The project folder may be in the wrong location or the URL may be incorrect.

Solution: Ensure the folder is inside htdocs and open http://localhost/student_management/.

Problem 3: Student is not inserted

Cause: Required fields may be empty, validation may fail, or the table structure may differ from the example.

Solution: Check the validation messages and confirm the database columns match the SQL provided.

Problem 4: Edit page says student not found

Cause: The ID may be invalid or the record may have been deleted.

Solution: Return to the student list and open Edit for an existing record.

Problem 5: Delete does not work

Cause: The request may not be using POST, or the ID may be invalid.

Solution: Ensure the Delete button submits the form to delete.php using method="POST".

14. Security Improvements Before Production

This project is suitable as a learning foundation, but a public application needs additional protection.

  • Authentication: Require users to sign in before accessing student records.

  • Authorization: Check permissions on every read, update, and delete operation.

  • CSRF protection: Add and validate CSRF tokens for state-changing requests.

  • Prepared statements: Continue using parameterized queries for user-supplied values.

  • Output escaping: Escape values according to the context in which they are displayed.

  • Credential management: Keep database secrets outside publicly accessible source code.

  • Least privilege: Use a database account with only the necessary permissions.

  • HTTPS: Encrypt browser-to-server traffic in production.

  • Error handling: Log technical details privately and avoid exposing them to visitors.

  • Duplicate prevention: Add database constraints when certain values must be unique.

  • Backups: Maintain tested backups of important records.

The confirmation dialog in this tutorial is a convenience, not a security mechanism. Similarly, a validated ID is not an authorization check.

15. Practice Exercises

Use the project as a starting point and try these exercises yourself.

Beginner exercises

  1. Add a phone column to the students table.

  2. Display the phone number on the listing page.

  3. Add a phone-number field to the registration form.

  4. Display a message when a student is successfully added.

  5. Change the table headings and CSS to suit your preferences.

Intermediate exercises

  1. Add a search form to find students by name.

  2. Add a course filter.

  3. Validate that email addresses are unique and enforce the rule with a database constraint.

  4. Add pagination so the listing page displays a limited number of records.

  5. Add a CSRF token to the create, edit, and delete forms.

Mini project challenge

Extend the application into a college management system by adding:

  • Student profile pages.

  • Course management.

  • Search and pagination.

  • Login and logout.

  • Role-based access for administrators and staff.

  • Server-side authorization checks.

Build the features one at a time and test each operation before adding the next.

16. Frequently Asked Questions (FAQs)

Q1. What are CRUD operations in PHP?

CRUD stands for Create, Read, Update, and Delete. These are the basic operations used to manage database records from a PHP application.

Q2. Which database is used in this project?

This project uses MySQL or a compatible MariaDB database, commonly provided through XAMPP.

Q3. Why do we use PDO?

PDO provides a consistent database-access interface and supports prepared statements. It also makes it easier to adapt an application to other supported database systems.

Q4. What is the purpose of db.php?

The db.php file creates the database connection. Other PHP files include it using require_once instead of creating a separate connection in each file.

Q5. Why should we use prepared statements?

Prepared statements separate SQL instructions from supplied values and help prevent SQL injection when used correctly.

Q6. Why do we use htmlspecialchars()?

It escapes special characters before they are displayed in HTML, helping prevent untrusted text from being interpreted as HTML or JavaScript.

Q7. Is this project ready for a live website?

Not yet. It demonstrates CRUD fundamentals, but production use requires authentication, authorization, CSRF protection, secure configuration, and additional validation and operational safeguards.

Q8. Can beginners build this project?

Yes. If you understand PHP variables, arrays, functions, HTML forms, and basic SQL, this is a suitable beginner project. Work through one file at a time and test each feature.

Conclusion

In this module, we built a complete beginner-level Student Management System using Core PHP and MySQL.

You learned how to:

  • Create a database and table.

  • Connect PHP to MySQL using PDO.

  • Insert new student records.

  • Retrieve and display records.

  • Update existing student information.

  • Delete records using a POST request.

  • Validate form input and escape HTML output.

  • Organize PHP code into reusable files.

CRUD operations are among the most important skills in PHP development. With this foundation, you can begin building more advanced database-driven applications.