CRUD Operations dengan PHP & MySQL

Panduan lengkap implementasi Create, Read, Update, Delete dengan PHP dan MySQL

Apa itu CRUD?

CRUD adalah akronim untuk 4 operasi dasar dalam manajemen database:

CREATE

Membuat/menambah data baru ke database

READ

Membaca/menampilkan data dari database

UPDATE

Mengubah/memperbarui data yang sudah ada

DELETE

Menghapus data dari database

CRUD Cycle

Keempat operasi ini adalah fondasi dari semua aplikasi database

Struktur File Project

Sebelum mulai coding, kita perlu menyiapkan struktur folder yang rapi:

htdocs/ └── crud-mahasiswa/ ├── config.php // Konfigurasi database ├── index.php // Halaman utama (Read) ├── create.php // Form tambah data ├── update.php // Form edit data ├── delete.php // Hapus data └── assets/ └── style.css // CSS custom
Lokasi Folder: Buat folder crud-mahasiswa di dalam htdocs (C:\xampp\htdocs\ untuk Windows)

Step 1: Konfigurasi Database (config.php)

File ini berisi koneksi ke database yang akan digunakan di semua file PHP.

<?php // config.php - Konfigurasi Database // Informasi koneksi database define('DB_HOST', 'localhost'); // Server database define('DB_NAME', 'db_mahasiswa'); // Nama database define('DB_USER', 'root'); // Username MySQL define('DB_PASS', ''); // Password (kosong untuk XAMPP) // Membuat koneksi database menggunakan PDO try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4" ] ); } catch(PDOException $e) { die("Koneksi gagal: " . $e->getMessage()); } ?>
Penjelasan:
  • PDO (PHP Data Objects) - Cara modern dan aman untuk koneksi database
  • ATTR_ERRMODE - Menampilkan error untuk debugging
  • FETCH_ASSOC - Data dikembalikan sebagai array associative
  • utf8mb4 - Support semua karakter termasuk emoji

CREATE - Menambah Data Baru

Alur Create Operation:
1
User mengisi form
2
Submit form ke server (PHP)
3
PHP validasi input
4
PHP execute INSERT query
5
Data tersimpan di database
6
Redirect ke halaman index dengan pesan sukses

File: create.php

<?php // create.php - Form dan proses tambah data require_once 'config.php'; // Proses form jika ada submit if ($_SERVER['REQUEST_METHOD'] == 'POST') { // Ambil data dari form $nama = trim($_POST['nama']); $nim = trim($_POST['nim']); $jurusan = trim($_POST['jurusan']); $email = trim($_POST['email']); $alamat = trim($_POST['alamat']); // Validasi input if (empty($nama) || empty($nim) || empty($jurusan)) { $error = "Nama, NIM, dan Jurusan wajib diisi!"; } else { try { // Cek apakah NIM sudah ada $stmt = $pdo->prepare("SELECT id FROM mahasiswa WHERE nim = ?"); $stmt->execute([$nim]); if ($stmt->fetch()) { $error = "NIM sudah terdaftar!"; } else { // Insert data ke database $sql = "INSERT INTO mahasiswa (nama, nim, jurusan, email, alamat, created_at) VALUES (?, ?, ?, ?, ?, NOW())"; $stmt = $pdo->prepare($sql); $stmt->execute([$nama, $nim, $jurusan, $email, $alamat]); // Redirect ke index dengan pesan sukses header("Location: index.php?success=Data berhasil ditambahkan"); exit; } } catch(PDOException $e) { $error = "Error: " . $e->getMessage(); } } } ?> <!DOCTYPE html> <html> <head> <title>Tambah Data Mahasiswa</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h2>Tambah Data Mahasiswa</h2> <?php if (isset($error)): ?> <div class="alert alert-danger"><?= $error ?></div> <?php endif; ?> <form method="POST"> <div class="mb-3"> <label class="form-label">Nama *</label> <input type="text" name="nama" class="form-control" required> </div> <div class="mb-3"> <label class="form-label">NIM *</label> <input type="text" name="nim" class="form-control" required> </div> <div class="mb-3"> <label class="form-label">Jurusan *</label> <input type="text" name="jurusan" class="form-control" required> </div> <div class="mb-3"> <label class="form-label">Email</label> <input type="email" name="email" class="form-control"> </div> <div class="mb-3"> <label class="form-label">Alamat</label> <textarea name="alamat" class="form-control" rows="3"></textarea> </div> <button type="submit" class="btn btn-success">Simpan</button> <a href="index.php" class="btn btn-secondary">Batal</a> </form> </div> </body> </html>
Security Best Practices:
  • Prepared Statements: Mencegah SQL Injection
  • trim(): Menghapus spasi di awal/akhir
  • Validasi: Cek field wajib sebelum insert
  • Cek Duplikat: Pastikan NIM belum ada

READ - Menampilkan Data

Operasi READ menampilkan semua data dari database dalam bentuk tabel.

File: index.php

<?php // index.php - Halaman utama menampilkan data require_once 'config.php'; // Ambil semua data mahasiswa try { $stmt = $pdo->query("SELECT * FROM mahasiswa ORDER BY created_at DESC"); $mahasiswas = $stmt->fetchAll(); } catch(PDOException $e) { die("Error: " . $e->getMessage()); } ?> <!DOCTYPE html> <html> <head> <title>Data Mahasiswa</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <div class="d-flex justify-content-between align-items-center mb-4"> <h2>Data Mahasiswa</h2> <a href="create.php" class="btn btn-success"> <i class="fas fa-plus me-2"></i>Tambah Data </a> </div> <?php if (isset($_GET['success'])): ?> <div class="alert alert-success alert-dismissible"> <?= $_GET['success'] ?> <button type="button" class="btn-close" data-bs-dismiss="alert"></button> </div> <?php endif; ?> <div class="table-responsive"> <table class="table table-bordered table-hover"> <thead class="table-dark"> <tr> <th>No</th> <th>NIM</th> <th>Nama</th> <th>Jurusan</th> <th>Email</th> <th>Aksi</th> </tr> </thead> <tbody> <?php if (count($mahasiswas) > 0): ?> <?php $no = 1; foreach($mahasiswas as $mhs): ?> <tr> <td><?= $no++ ?></td> <td><?= htmlspecialchars($mhs['nim']) ?></td> <td><?= htmlspecialchars($mhs['nama']) ?></td> <td><?= htmlspecialchars($mhs['jurusan']) ?></td> <td><?= htmlspecialchars($mhs['email']) ?></td> <td> <a href="update.php?id=<?= $mhs['id'] ?>" class="btn btn-sm btn-warning"> <i class="fas fa-edit"></i> </a> <a href="delete.php?id=<?= $mhs['id'] ?>" class="btn btn-sm btn-danger" onclick="return confirm('Yakin hapus data ini?')"> <i class="fas fa-trash"></i> </a> </td> </tr> <?php endforeach; ?> <?php else: ?> <tr> <td colspan="6" class="text-center">Tidak ada data</td> </tr> <?php endif; ?> </tbody> </table> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> </body> </html>
Tips:
  • htmlspecialchars(): Mencegah XSS attack
  • ORDER BY created_at DESC: Data terbaru di atas
  • onclick confirm: Konfirmasi sebelum hapus

UPDATE - Mengubah Data

Operasi UPDATE mengambil data berdasarkan ID, menampilkan form dengan data lama, lalu update ke database.

File: update.php

<?php // update.php - Form dan proses edit data require_once 'config.php'; // Ambil ID dari URL $id = $_GET['id'] ?? 0; // Proses form jika ada submit if ($_SERVER['REQUEST_METHOD'] == 'POST') { $nama = trim($_POST['nama']); $nim = trim($_POST['nim']); $jurusan = trim($_POST['jurusan']); $email = trim($_POST['email']); $alamat = trim($_POST['alamat']); if (empty($nama) || empty($nim) || empty($jurusan)) { $error = "Nama, NIM, dan Jurusan wajib diisi!"; } else { try { // Cek NIM duplikat (kecuali data sendiri) $stmt = $pdo->prepare("SELECT id FROM mahasiswa WHERE nim = ? AND id != ?"); $stmt->execute([$nim, $id]); if ($stmt->fetch()) { $error = "NIM sudah terdaftar!"; } else { // Update data $sql = "UPDATE mahasiswa SET nama = ?, nim = ?, jurusan = ?, email = ?, alamat = ?, updated_at = NOW() WHERE id = ?"; $stmt = $pdo->prepare($sql); $stmt->execute([$nama, $nim, $jurusan, $email, $alamat, $id]); header("Location: index.php?success=Data berhasil diupdate"); exit; } } catch(PDOException $e) { $error = "Error: " . $e->getMessage(); } } } // Ambil data mahasiswa berdasarkan ID try { $stmt = $pdo->prepare("SELECT * FROM mahasiswa WHERE id = ?"); $stmt->execute([$id]); $mhs = $stmt->fetch(); if (!$mhs) { header("Location: index.php"); exit; } } catch(PDOException $e) { die("Error: " . $e->getMessage()); } ?> <!DOCTYPE html> <html> <head> <title>Edit Data Mahasiswa</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h2>Edit Data Mahasiswa</h2> <?php if (isset($error)): ?> <div class="alert alert-danger"><?= $error ?></div> <?php endif; ?> <form method="POST"> <div class="mb-3"> <label class="form-label">Nama *</label> <input type="text" name="nama" class="form-control" value="<?= htmlspecialchars($mhs['nama']) ?>" required> </div> <div class="mb-3"> <label class="form-label">NIM *</label> <input type="text" name="nim" class="form-control" value="<?= htmlspecialchars($mhs['nim']) ?>" required> </div> <div class="mb-3"> <label class="form-label">Jurusan *</label> <input type="text" name="jurusan" class="form-control" value="<?= htmlspecialchars($mhs['jurusan']) ?>" required> </div> <div class="mb-3"> <label class="form-label">Email</label> <input type="email" name="email" class="form-control" value="<?= htmlspecialchars($mhs['email']) ?>"> </div> <div class="mb-3"> <label class="form-label">Alamat</label> <textarea name="alamat" class="form-control" rows="3"><?= htmlspecialchars($mhs['alamat']) ?></textarea> </div> <button type="submit" class="btn btn-warning">Update</button> <a href="index.php" class="btn btn-secondary">Batal</a> </form> </div> </body> </html>

DELETE - Menghapus Data

Operasi DELETE menghapus data berdasarkan ID yang diterima dari parameter URL.

File: delete.php

<?php // delete.php - Proses hapus data require_once 'config.php'; // Ambil ID dari URL $id = $_GET['id'] ?? 0; if ($id > 0) { try { // Hapus data berdasarkan ID $stmt = $pdo->prepare("DELETE FROM mahasiswa WHERE id = ?"); $stmt->execute([$id]); // Redirect dengan pesan sukses header("Location: index.php?success=Data berhasil dihapus"); exit; } catch(PDOException $e) { // Redirect dengan pesan error header("Location: index.php?error=Gagal menghapus data"); exit; } } else { // Redirect jika ID tidak valid header("Location: index.php"); exit; } ?>
PENTING - Delete Best Practices:
  • Konfirmasi: Selalu minta konfirmasi user sebelum hapus (javascript confirm)
  • Soft Delete: Untuk production, pertimbangkan soft delete (tambah column deleted_at)
  • Cascade: Pastikan relasi dengan table lain tidak bermasalah
  • Log: Simpan log siapa dan kapan menghapus data

Ringkasan CRUD Operations

Operation SQL Query HTTP Method File
CREATE INSERT INTO POST create.php
READ SELECT GET index.php
UPDATE UPDATE POST update.php
DELETE DELETE GET delete.php

Testing CRUD Application

Checklist Testing:
  1. CREATE: Tambah data baru → Cek muncul di table
  2. READ: Refresh halaman → Data tetap ada
  3. UPDATE: Edit data → Perubahan tersimpan
  4. DELETE: Hapus data → Data hilang dari table
  5. Validasi: Submit form kosong → Muncul error
  6. Duplikat NIM: Input NIM sama → Muncul error
Akses Aplikasi:
http://localhost/crud-mahasiswa/index.php

Tips & Best Practices

✅ DO
  • Gunakan Prepared Statements
  • Validasi semua input
  • Use htmlspecialchars() untuk output
  • Trim() data sebelum simpan
  • Berikan feedback ke user
  • Handle error dengan try-catch
❌ DON'T
  • Jangan langsung query dengan input user
  • Jangan simpan password plain text
  • Jangan abaikan error handling
  • Jangan skip validasi
  • Jangan hardcode database credentials
  • Jangan expose error detail ke user
Setup Database Kembali ke Unit 5