Skip to main content
MySQL Basics
CHAPTER 27 Beginner

CRUD Application with PHP and MySQL

Updated: May 16, 2026
5 min read

# CHAPTER 27

CRUD Application with PHP and MySQL

1. Introduction

A database without an interface is invisible. A web application without a database is amnesiac. Combining them creates fully functional software. Every major web application—from Twitter to WordPress—is essentially a CRUD application. They allow users to Create posts, Read feeds, Update profiles, and Delete comments. In this chapter, we will build the core PHP logic for a complete User Management system.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Architect the folder structure for a PHP CRUD app.
  • Implement the "Create" logic to insert new records.
  • Implement the "Read" logic to fetch and display records in an HTML table.
  • Implement the "Update" logic to modify existing data.
  • Implement the "Delete" logic to remove records securely.

3. The Setup (database.php)

First, we isolate our PDO connection logic into a single file so we can include it anywhere.
database.php
12345678910111213
<?php
$host = &#039;localhost';
$dbname = &#039;crud_app';
$username = &#039;root';
$password = &#039;';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Connection failed: " . $e->getMessage());
}
?>

4. Create (Inserting Data)

We need an HTML form that submits via POST. When the form is submitted, we capture the data and use a Prepared Statement to safely insert it.
create.php
123456789101112131415161718192021
<?php
require &#039;database.php';

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $name = trim($_POST[&#039;name']);
    $email = trim($_POST[&#039;email']);

    $sql = "INSERT INTO users (name, email) VALUES (:name, :email)";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([&#039;name' => $name, 'email' => $email]);
    
    echo "User created successfully!";
}
?>

<!-- HTML Form -->
<form method="POST" action="create.php">
    Name: <input type="text" name="name" required>
    Email: <input type="email" name="email" required>
    <button type="submit">Create User</button>
</form>

5. Read (Displaying Data)

Now we want to view all the users we created. We query the database and loop through the array to generate an HTML table.
read.php
1234567891011121314151617181920212223
<?php
require &#039;database.php';

$sql = "SELECT id, name, email FROM users ORDER BY id DESC";
$stmt = $pdo->query($sql);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

<table border="1">
    <tr><th>ID</th><th>Name</th><th>Email</th><th>Actions</th></tr>
    <?php foreach ($users as $user): ?>
    <tr>
        <td><?= htmlspecialchars($user[&#039;id']) ?></td>
        <td><?= htmlspecialchars($user[&#039;name']) ?></td>
        <td><?= htmlspecialchars($user[&#039;email']) ?></td>
        <td>
            <!-- Links to the Update and Delete pages! -->
            <a href="update.php?id=<?= $user[&#039;id'] ?>">Edit</a>
            <a href="delete.php?id=<?= $user[&#039;id'] ?>">Delete</a>
        </td>
    </tr>
    <?php endforeach; ?>
</table>

6. Update (Modifying Data)

Updating requires two steps: First, fetch the existing user's data to pre-fill the form. Second, save the newly submitted data.
update.php
12345678910111213141516171819202122232425262728
<?php
require &#039;database.php';
$id = $_GET[&#039;id']; // Get the ID from the URL

// 1. Fetch current data
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([&#039;id' => $id]);
$user = $stmt->fetch();

// 2. Process form submission
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $sql = "UPDATE users SET name = :name, email = :email WHERE id = :id";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([
        &#039;name' => $_POST['name'],
        &#039;email' => $_POST['email'],
        &#039;id' => $id
    ]);
    echo "User updated!";
}
?>

<!-- Pre-fill the form with existing data -->
<form method="POST">
    Name: <input type="text" name="name" value="<?= htmlspecialchars($user[&#039;name']) ?>">
    Email: <input type="email" name="email" value="<?= htmlspecialchars($user[&#039;email']) ?>">
    <button type="submit">Update</button>
</form>

7. Delete (Removing Data)

Deletion is the simplest, but the most dangerous. Always use a Prepared Statement, even if the ID is just coming from the URL!
delete.php
1234567891011121314151617
<?php
require &#039;database.php';

// NEVER do this: $pdo->query("DELETE FROM users WHERE id = " . $_GET['id']);
// A hacker could pass ?id=1 OR 1=1 to delete everyone!

// ALWAYS do this:
if (isset($_GET[&#039;id'])) {
    $sql = "DELETE FROM users WHERE id = :id";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([&#039;id' => $_GET['id']]);
    
    echo "User securely deleted!";
    // Redirect back to the Read page
    header("Location: read.php");
}
?>

8. Common Mistakes

  • Trusting $_GET Variables: In the delete.php script, the ID comes from the URL ($_GET['id']). Beginners often concatenate this directly into the SQL string because "it's just a number." Hackers can easily type text or malicious SQL into the URL bar. ALWAYS use Prepared Statements for $_GET variables!
  • Missing htmlspecialchars(): If a malicious user types <script>alert('Hacked!');</script> into the Name field on create.php, and you echo it out directly on read.php, the script will run in everyone's browser. htmlspecialchars() converts the HTML brackets into safe text entities, neutralizing the attack.

9. Best Practices

  • Post/Redirect/Get (PRG) Pattern: In create.php, if a user clicks "Refresh" after submitting the form, their browser will submit the data again, creating a duplicate row! To prevent this, after the $stmt->execute(), you should immediately redirect them away using header("Location: read.php");.

10. Exercises

  1. 1. What does the acronym CRUD stand for, and which fundamental SQL commands (INSERT, SELECT, UPDATE, DELETE) correspond to each letter?
  1. 2. Why must you wrap database outputs in htmlspecialchars() before displaying them in an HTML table?

11. MCQ Quiz with Answers

Question 1

In the "Read" portion of a CRUD app, what PDO method is used to retrieve all the rows from the executed query and store them in a PHP Array?

Question 2

When building a "Delete" feature, why is it critical to use a Prepared Statement even if the ID is simply being passed via the URL ($_GET)?

12. Interview Questions

  • Q: Explain the Post/Redirect/Get (PRG) pattern and how it prevents duplicate row insertions in a standard PHP/MySQL CRUD application.
  • Q: Walk me through the security vulnerabilities of taking an ID from the URL (delete.php?id=5) and concatenating it directly into a DELETE query string.

13. FAQs

Q: Should I put all my CRUD logic in one file or multiple files? A: For learning, separating them into create.php, read.php, etc., is best. In professional environments, developers use an MVC Framework (like Laravel or Symfony) that routes all actions through a single "Controller" file.

14. Summary

You have successfully built the engine of the web. By combining the database.php connection logic with the four fundamental SQL operations (INSERT, SELECT, UPDATE, DELETE), and securing every single step with Prepared Statements, you now possess the skills to build almost any basic web application from scratch.

15. Next Chapter Recommendation

MySQL is the king of Relational Databases. But in recent years, a new type of database has emerged: NoSQL. When should you use MySQL, and when should you abandon it for MongoDB? In Chapter 28: NoSQL vs SQL Databases, we explore the architectural differences of modern data storage.

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: ·