Pada tutorial sebelumnya, kita telah mempelajari dasar CRUD PHP MySQLi OOP menggunakan Prepared Statement. Namun, di dunia nyata, data tidak hanya berupa teks, sering kali kita perlu mengunggah gambar seperti foto produk, avatar pengguna, atau bukti pembayaran.
Dalam artikel ini, kamu akan belajar membuat CRUD PHP MySQL Lengkap dengan Upload Gambar:
-
Koneksi database menggunakan MySQLi OOP
-
Prepared Statement untuk keamanan
-
Upload gambar dengan validasi tipe & ukuran file
-
CRUD (Create, Read, Update, Delete) data dan file
1. Struktur Folder Proyek
crud_upload/ │ ├── koneksi.php ├── index.php ← Menampilkan data ├── tambah.php ← Form tambah data + upload gambar ├── edit.php ← Form edit data + ganti gambar ├── hapus.php ← Hapus data + gambar dari folder └── uploads/ ← Folder penyimpanan gambar
Pastikan folder uploads/
sudah dibuat dan memiliki izin tulis (chmod 755
atau 777
di Linux).
2. Membuat Koneksi Database (koneksi.php)
<?php $servername = "localhost"; $username = "root"; $password = ""; $dbname = "belajar_php"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die("Koneksi gagal: " . $conn->connect_error); } ?>
3. CREATE – Tambah Data + Upload Gambar (tambah.php)
<?php include 'koneksi.php'; if (isset($_POST['submit'])) { $nama = $_POST['nama']; $email = $_POST['email']; $gambar = $_FILES['gambar']; // Validasi file $allowedTypes = ['image/jpeg', 'image/png', 'image/gif']; $maxSize = 2 * 1024 * 1024; // 2MB if (!in_array($gambar['type'], $allowedTypes)) { echo "Tipe file tidak diijinkan (hanya JPG, PNG, GIF)."; } elseif ($gambar['size'] > $maxSize) { echo "Ukuran file terlalu besar. Maksimal 2MB."; } else { // Upload file $fileName = time() . "_" . basename($gambar['name']); $targetPath = "uploads/" . $fileName; if (move_uploaded_file($gambar['tmp_name'], $targetPath)) { // Simpan data ke database $stmt = $conn->prepare("INSERT INTO users (nama, email, gambar) VALUES (?, ?, ?)"); $stmt->bind_param("sss", $nama, $email, $fileName); if ($stmt->execute()) { echo "Data berhasil disimpan!"; } else { echo "Gagal menyimpan data: " . $stmt->error; } $stmt->close(); } else { echo "Gagal upload gambar."; } } } ?> <form method="post" enctype="multipart/form-data"> Nama: <input type="text" name="nama" required><br> Email: <input type="email" name="email" required><br> Gambar: <input type="file" name="gambar" required><br> <input type="submit" name="submit" value="Simpan"> </form>
Penjelasan:
-
Validasi tipe file menggunakan
$_FILES['type']
. -
Batas ukuran 2MB (
2 * 1024 * 1024
). -
Nama file diubah agar unik menggunakan
time()
.
4. READ – Menampilkan Data (index.php)
<?php include 'koneksi.php'; $result = $conn->query("SELECT * FROM users"); ?> <h2>Daftar Pengguna</h2> <a href="tambah.php">Tambah Data</a> <table border="1" cellpadding="5"> <tr> <th>ID</th> <th>Nama</th> <th>Email</th> <th>Gambar</th> <th>Aksi</th> </tr> <?php while ($row = $result->fetch_assoc()): ?> <tr> <td><?= $row['id']; ?></td> <td><?= $row['nama']; ?></td> <td><?= $row['email']; ?></td> <td><img src="uploads/<?= $row['gambar']; ?>" width="80"></td> <td> <a href="edit.php?id=<?= $row['id']; ?>">Edit</a> | <a href="hapus.php?id=<?= $row['id']; ?>" onclick="return confirm('Yakin hapus?')">Hapus</a> </td> </tr> <?php endwhile; ?> </table>
5. UPDATE – Edit Data dan Ganti Gambar (edit.php)
<?php include 'koneksi.php'; $id = $_GET['id']; $stmt = $conn->prepare("SELECT * FROM users WHERE id=?"); $stmt->bind_param("i", $id); $stmt->execute(); $result = $stmt->get_result(); $user = $result->fetch_assoc(); if (isset($_POST['update'])) { $nama = $_POST['nama']; $email = $_POST['email']; $gambarBaru = $_FILES['gambar']; $fileName = $user['gambar']; // default gambar lama if ($gambarBaru['name']) { $allowedTypes = ['image/jpeg', 'image/png', 'image/gif']; $maxSize = 2 * 1024 * 1024; if (!in_array($gambarBaru['type'], $allowedTypes)) { echo "Tipe file tidak diijinkan."; } elseif ($gambarBaru['size'] > $maxSize) { echo "Ukuran file terlalu besar."; } else { $fileName = time() . "_" . basename($gambarBaru['name']); $targetPath = "uploads/" . $fileName; if (move_uploaded_file($gambarBaru['tmp_name'], $targetPath)) { if (file_exists("uploads/" . $user['gambar'])) { unlink("uploads/" . $user['gambar']); } } } } $stmt = $conn->prepare("UPDATE users SET nama=?, email=?, gambar=? WHERE id=?"); $stmt->bind_param("sssi", $nama, $email, $fileName, $id); if ($stmt->execute()) { echo "Data berhasil diupdate!"; } else { echo "Gagal update data."; } } ?> <form method="post" enctype="multipart/form-data"> Nama: <input type="text" name="nama" value="<?= $user['nama']; ?>"><br> Email: <input type="email" name="email" value="<?= $user['email']; ?>"><br> Gambar Lama: <img src="uploads/<?= $user['gambar']; ?>" width="80"><br> Ganti Gambar: <input type="file" name="gambar"><br> <input type="submit" name="update" value="Update"> </form>
6. DELETE – Menghapus Data dan File (hapus.php)
<?php include 'koneksi.php'; $id = $_GET['id']; // Ambil nama file gambar $stmt = $conn->prepare("SELECT gambar FROM users WHERE id=?"); $stmt->bind_param("i", $id); $stmt->execute(); $result = $stmt->get_result(); $data = $result->fetch_assoc(); if ($data) { $gambar = "uploads/" . $data['gambar']; if (file_exists($gambar)) unlink($gambar); $stmt = $conn->prepare("DELETE FROM users WHERE id=?"); $stmt->bind_param("i", $id); $stmt->execute(); echo "Data berhasil dihapus!"; } else { echo "Data tidak ditemukan."; } ?>
Tips Keamanan Tambahan
-
Pastikan folder
uploads/
tidak bisa menjalankan file PHP (gunakan.htaccess
untuk keamanan). -
Gunakan nama file unik untuk menghindari bentrok dan overwriting.
-
Jangan menampilkan path asli file di browser.
Kesimpulan
Dengan tutorial ini, kamu telah membuat sistem CRUD lengkap menggunakan:
-
MySQLi OOP + Prepared Statement
-
Upload gambar dengan validasi format dan ukuran
-
Penghapusan file otomatis saat data dihapus
Hasilnya lebih aman, efisien, dan profesional untuk proyek web nyata seperti toko online, galeri, atau sistem manajemen data.