Ini episode penutup series PHP Native. Enam episode sudah kita lewati: kenalan PHP (#56), variabel (#57), logika (#58), array dan form (#59), validasi (#60), session dan upload (#61). Satu keping puzzle yang belum: tempat menyimpan data secara permanen dan terstruktur. Episode #62 ini tentang MySQL dan CRUD, dirangkai jadi proyek beneran: aplikasi buku tamu.
Setelah ini series PHP Native tamat, dan episode #63 membuka series baru: Database dan SQL, tempat kita belajar merancang database yang rapi. Jadi anggap episode ini sebagai "bisa pakai dulu", episode berikutnya "paham cara merancangnya".
Persepsi yang Diluruskan: Database Tidak Seseram Itu
Kata "database" terdengar berat, seperti ruangan server dengan lampu berkedip. Kenyataannya, untuk pemula database cuma soal empat operasi: Create (simpan data baru), Read (baca data), Update (ubah data), Delete (hapus data). Disingkat CRUD. Semua aplikasi di dunia, dari Instagram sampai aplikasi kasir warung, intinya CRUD yang dibungkus tampilan bagus.
Selama ini datamu tinggal di variabel (hilang saat request selesai), session (hilang saat logout), atau localStorage (cuma di satu browser). Database adalah gudang permanen di server: data tersimpan rapi dalam tabel, bisa dicari, diubah, dan diakses kapan pun. MySQL adalah database relasional gratis paling populer untuk PHP, dan ia sudah sepaket di XAMPP/Laragon yang kita bahas di #56.
Pastikan MySQL/MariaDB jalan di XAMPP Control Panel (klik Start), lalu buka http://localhost/phpmyadmin. Itu phpMyAdmin, alat bantu visual untuk mengelola database lewat browser. Bikin database baru bernama buku_tamu_db, lalu jalankan SQL ini di tab SQL untuk bikin tabelnya:
CREATE TABLE tamu (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
pesan TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Jangan panik dengan syntax SQL-nya, kita bedah tuntas di series berikutnya mulai #63. Untuk sekarang cukup tahu: tabel tamu punya kolom id (nomor otomatis), nama, pesan, dan waktu dibuat.
Menyambungkan PHP ke MySQL
Koneksi dibuat sekali dan dipakai ulang. Bikin file koneksi.php:
<?php
$host = "localhost";
$user = "root";
$pass = ""; // default XAMPP: password root kosong
$db = "buku_tamu_db";
$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) {
die("Koneksi gagal: " . $conn->connect_error);
}
?>
Pola include 'koneksi.php'; di tiap file yang butuh database membuatmu tidak menulis ulang kredensial di mana-mana. Kalau password database berubah besok, cuma satu file yang diedit. Ini penerapan prinsip DRY (Don't Repeat Yourself) paling sederhana.
Catatan: contoh ini pakai kredensial default XAMPP (root tanpa password) yang cuma aman untuk belajar di laptop sendiri. Di server beneran, password root wajib diisi dan user database sebaiknya dibatasi haknya. Jangan deploy contoh ini apa adanya.
Berhenti dan tebak dulu! Apa yang terjadi kalau password di koneksi.php salah?
<?php
$conn = new mysqli("localhost", "root", "salah", "buku_tamu_db");
if ($conn->connect_error) {
die("Koneksi gagal: " . $conn->connect_error);
}
echo "Terhubung!";
?>
CRUD Satu per Satu
Sekarang empat operasinya. Perhatikan satu benang merah: semua query yang melibatkan data dari user memakai prepared statement (tanda tanya sebagai placeholder), BUKAN menempel variabel langsung ke string SQL. Kenapa? Karena menempel langsung membuka celah SQL injection: user jahat bisa menyisipkan perintah SQL lewat input form dan membaca atau menghapus seluruh database-mu. Prepared statement memisahkan perintah SQL dari datanya, sehingga input user selalu diperlakukan sebagai data, tidak pernah sebagai perintah.
Create: simpan data baru.
<?php
include 'koneksi.php';
$stmt = $conn->prepare("INSERT INTO tamu (nama, pesan) VALUES (?, ?)");
$stmt->bind_param("ss", $nama, $pesan); // "ss" = dua-duanya string
$stmt->execute();
$stmt->close();
?>
bind_param("ss", ...) artinya "isi dua tanda tanya dengan dua string". Hurufnya menyesuaikan tipe: s untuk string, i untuk integer, d untuk desimal. Urutannya harus cocok dengan urutan tanda tanya.
Read: baca semua data.
<?php
include 'koneksi.php';
$result = $conn->query("SELECT * FROM tamu ORDER BY created_at DESC");
while ($row = $result->fetch_assoc()) {
echo htmlspecialchars($row["nama"]) . ": " . htmlspecialchars($row["pesan"]) . "<br>";
}
?>
fetch_assoc() mengambil satu baris sebagai array asosiatif (nama kolom jadi kunci), dan while mengulang sampai baris habis. Pola while-fetch ini akan kamu tulis ratusan kali sepanjang karier PHP-mu. Perhatikan htmlspecialchars tetap dipakai: data dari database sama tidak terpercayanya dengan data dari form, karena dulu ia juga berasal dari form.
Update dan Delete: ubah dan hapus data tertentu.
<?php
include 'koneksi.php';
// Update pesan tamu dengan id 3
$stmt = $conn->prepare("UPDATE tamu SET pesan = ? WHERE id = ?");
$stmt->bind_param("si", $pesanBaru, $id);
$stmt->execute();
// Hapus tamu dengan id 3
$stmt = $conn->prepare("DELETE FROM tamu WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
?>
Perhatikan WHERE id = ? di keduanya. WHERE adalah penentu "baris mana". DELETE tanpa WHERE menghapus SEMUA baris di tabel tanpa konfirmasi. Ini bukan teori: setiap tahun ada developer yang menghapus data production karena lupa WHERE. Kebiasaan amannya: tulis WHERE dulu sebelum menulis perintahnya, atau tes dulu sebagai SELECT dengan WHERE yang sama untuk melihat baris mana yang kena.
Kuis cepat: Kenapa query pakai prepared statement (tanda ?) bukan langsung menempel variabel?
Proyek: Aplikasi Buku Tamu
Saatnya merakit. Satu file index.php berisi form tambah pesan plus daftar semua pesan, dan satu file hapus.php untuk menghapus. Ini pola "satu file form-plus-daftar" yang sama seperti episode #59, sekarang datanya dari database.
<?php include 'koneksi.php'; ?>
<!-- Form tambah pesan -->
<form method="post">
<input type="text" name="nama" placeholder="Namamu" required>
<textarea name="pesan" placeholder="Tulis pesan..." required></textarea>
<button type="submit" name="kirim">Kirim</button>
</form>
<?php
// Proses form (Create + validasi ala episode #60)
if (isset($_POST["kirim"])) {
$nama = trim($_POST["nama"] ?? "");
$pesan = trim($_POST["pesan"] ?? "");
if ($nama !== "" && $pesan !== "") {
$stmt = $conn->prepare("INSERT INTO tamu (nama, pesan) VALUES (?, ?)");
$stmt->bind_param("ss", $nama, $pesan);
$stmt->execute();
$stmt->close();
}
}
// Tampilkan semua (Read)
$result = $conn->query("SELECT * FROM tamu ORDER BY created_at DESC");
while ($row = $result->fetch_assoc()) {
echo "<div>";
echo "<b>" . htmlspecialchars($row["nama"]) . "</b> ";
echo "<small>" . $row["created_at"] . "</small>";
echo "<p>" . htmlspecialchars($row["pesan"]) . "</p>";
echo "<a href='hapus.php?id=" . $row["id"] . "'>Hapus</a>";
echo "</div><hr>";
}
?>
Dan hapus.php yang sederhana:
<?php
include 'koneksi.php';
$id = (int) ($_GET["id"] ?? 0); // paksa jadi integer, pertahanan tambahan
if ($id > 0) {
$stmt = $conn->prepare("DELETE FROM tamu WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$stmt->close();
}
header("Location: index.php"); // kembali ke daftar
exit;
?>
Perhatikan (int) sebelum memakai id dari URL: memaksa jadi angka sehingga input aneh seperti id=abc jadi 0 dan tidak diproses. Lapisan pertahanan kecil yang murah. Dan header("Location: ...") mengarahkan browser kembali ke daftar setelah hapus, pola Post/Redirect/Get sederhana supaya refresh tidak mengulang penghapusan.
Berhenti dan tebak dulu! Apa beda hasil dua query ini?
DELETE FROM tamu WHERE id = 3;
DELETE FROM tamu;
Latihan Penutup Series
Latihan 1. Selesaikan aplikasi buku tamu di atas sampai jalan: bikin database, tabel, koneksi.php, index.php, hapus.php. Isi 5 pesan lewat form dan pastikan semuanya tampil dengan urutan terbaru di atas.
Latihan 2. TAMBAHKAN fitur edit: link "Edit" di tiap pesan yang membuka edit.php?id=... berisi form terisi pesan lama, lalu UPDATE saat disubmit. Petunjuk: ambil data lama dulu dengan SELECT WHERE id, tampilkan di form, proses POST dengan prepared statement UPDATE.
Latihan 3. TAMBAHKAN validasi: nama maksimal 50 karakter, pesan maksimal 500 karakter, tampilkan pesan error kalau dilanggar (pola episode #60). Lalu UBAH link hapus jadi form POST kecil dengan tombol, karena menghapus data lewat link GET itu berbahaya (bayangkan crawler search engine mengklik semua link hapus).
Selamat, series PHP Native tamat. Kamu sekarang bisa bikin aplikasi web dinamis lengkap: form, validasi, session, upload, dan database. Episode #63 membuka series baru, Database dan SQL, di mana kita belajar merancang tabel yang rapi: primary key, foreign key, dan relasi antar tabel. Karena buku tamu satu tabel itu gampang, aplikasi beneran butuh banyak tabel yang saling terhubung. Sampai jumpa.
Diskusi & Komentar 0
Punya tanggapan, pertanyaan, atau tips seputar tutorial ini? Tulis komentar kamu di bawah!
Jadilah yang pertama membuka obrolan dan berbagi pandangan seputar tutorial resep kode ini.
Tulis Komentar
Komentar menggunakan akun Google. Harap berkomentar dengan santun dan berbobot.