CRUD PHP MySQL Lengkap dengan Upload Gambar

By | 12 October 2025

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

  1. Pastikan folder uploads/ tidak bisa menjalankan file PHP (gunakan .htaccess untuk keamanan).

  2. Gunakan nama file unik untuk menghindari bentrok dan overwriting.

  3. 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.