Project PHP MySQL CRUD Simple Blog

Project PHP MySQL CRUD Simple Blog

Project PHP MySQL CRUD Artikel (Blog Sederhana) – Panduan Lengkap Membuat Sistem Manajemen Konten

Membangun sistem manajemen artikel/blog sederhana adalah proyek sempurna untuk mempelajari operasi database dasar. Dalam panduan komprehensif ini, kita akan membuat aplikasi PHP MySQL yang mencakup semua fungsi CRUD:

✅ Create – Formulir tambah artikel baru
✅ Read – Menampilkan daftar artikel
✅ Update – Formulir edit artikel
✅ Delete – Fungsi hapus artikel
✅ Antarmuka Responsif menggunakan Bootstrap 5 CDN
✅ Proteksi Keamanan dasar

Persiapan Proyek

Struktur Folder yang Direkomendasikan

blog_sederhana/
├── config/
│   └── database.php
├── includes/
│   ├── header.php
│   ├── footer.php
│   └── functions.php
├── articles/
│   ├── index.php
│   ├── create.php
│   ├── edit.php
│   └── delete.php
└── assets/
    └── css/
        └── style.css

Buat Database MySQL

sql
CREATE DATABASE blog_sederhana;
USE blog_sederhana;

CREATE TABLE articles (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Langkah 1: Konfigurasi Database (config/database.php)

php
<?php
// Konfigurasi Database
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'blog_sederhana');

// Koneksi dengan PDO untuk keamanan lebih baik
try {
    $dsn = "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8mb4";
    $options = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false,
    ];
    $pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
} catch (PDOException $e) {
    die("Koneksi database gagal: " . $e->getMessage());
}
?>

Langkah 2: Implemtasi includes code

Header (includes/header.php)

php
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sistem Artikel - <?= $pageTitle ?? 'Blog Sederhana azroi' ?></title>
    <!-- Bootstrap 5 CSS dari CDN -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .article-content { white-space: pre-line; }
        .pagination { justify-content: center; }
    </style>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-4">
        <div class="container">
            <a class="navbar-brand" href="/articles">Blog Sederhana</a>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav me-auto">
                    <li class="nav-item">
                        <a class="nav-link" href="/articles">Artikel</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="/articles/create.php">Tambah Artikel</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">

Footer (includes/footer.php)

php
    </div>
    <footer class="mt-5 py-3 bg-light">
        <div class="container text-center">
            <p>&copy; <?= date('Y') ?> Blog Sederhana - Azroi.</p>
        </div>
    </footer>
    <!-- Bootstrap 5 JS dari CDN -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Langkah 3: Halaman Utama Artikel (articles/index.php)

php
<?php
require_once __DIR__.'/../config/database.php';
session_start();
$pageTitle = "Daftar Artikel";

// Pagination
$limit = 5;
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$offset = ($page - 1) * $limit;

// Hitung total artikel
$totalArticles = $pdo->query("SELECT COUNT(*) FROM articles")->fetchColumn();
$totalPages = ceil($totalArticles / $limit);

// Query dengan pagination
$stmt = $pdo->prepare("SELECT * FROM articles ORDER BY created_at DESC LIMIT :limit OFFSET :offset");
$stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$articles = $stmt->fetchAll();

include __DIR__.'/../includes/header.php';
?>

<!-- Notifikasi -->
<?php if (isset($_SESSION['success'])): ?>
    <div class="alert alert-success alert-dismissible fade show">
        <?= $_SESSION['success'] ?>
        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
    <?php unset($_SESSION['success']); ?>
<?php endif; ?>

<h2 class="mb-4">Daftar Artikel</h2>
<a href="create.php" class="btn btn-primary mb-3">
    <i class="bi bi-plus-circle"></i> Tambah Artikel
</a>

<div class="table-responsive">
    <table class="table table-striped table-hover">
        <thead class="table-dark">
            <tr>
                <th width="5%">#</th>
                <th width="30%">Judul</th>
                <th width="20%">Tanggal</th>
                <th width="15%">Aksi</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($articles as $index => $article): ?>
            <tr>
                <td><?= $index + 1 + $offset ?></td>
                <td><?= htmlspecialchars($article['title']) ?></td>
                <td><?= date('d/m/Y H:i', strtotime($article['created_at'])) ?></td>
                <td>
                    <a href="edit.php?id=<?= $article['id'] ?>" class="btn btn-sm btn-warning">
                        <i class="bi bi-pencil"></i> Edit
                    </a>
                    <form action="delete.php" method="POST" class="d-inline">
                        <input type="hidden" name="id" value="<?= $article['id'] ?>">
                        <button type="submit" class="btn btn-sm btn-danger" 
                                onclick="return confirm('Yakin menghapus artikel ini?')">
                            <i class="bi bi-trash"></i> Hapus
                        </button>
                    </form>
                </td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
</div>

<!-- Pagination -->
<?php if ($totalPages > 1): ?>
<nav aria-label="Page navigation">
    <ul class="pagination">
        <li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>">
            <a class="page-link" href="?page=<?= $page-1 ?>">Sebelumnya</a>
        </li>
        
        <?php for ($i = 1; $i <= $totalPages; $i++): ?>
        <li class="page-item <?= $i == $page ? 'active' : '' ?>">
            <a class="page-link" href="?page=<?= $i ?>"><?= $i ?></a>
        </li>
        <?php endfor; ?>
        
        <li class="page-item <?= $page >= $totalPages ? 'disabled' : '' ?>">
            <a class="page-link" href="?page=<?= $page+1 ?>">Selanjutnya</a>
        </li>
    </ul>
</nav>
<?php endif; ?>

<?php include __DIR__.'/../includes/footer.php'; ?>

Langkah 4: Membuat Artikel Baru (articles/create.php)

php
<?php
require_once __DIR__.'/../config/database.php';
session_start();
$pageTitle = "Tambah Artikel Baru";

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = trim($_POST['title']);
    $content = trim($_POST['content']);
    
    // Validasi
    $errors = [];
    if (empty($title)) $errors[] = "Judul artikel wajib diisi";
    if (strlen($title) > 255) $errors[] = "Judul maksimal 255 karakter";
    if (empty($content)) $errors[] = "Konten artikel wajib diisi";
    
    if (empty($errors)) {
        try {
            $stmt = $pdo->prepare("INSERT INTO articles (title, content) VALUES (?, ?)");
            $stmt->execute([$title, $content]);
            
            $_SESSION['success'] = "Artikel berhasil ditambahkan!";
            header("Location: index.php");
            exit;
        } catch (PDOException $e) {
            $errors[] = "Gagal menyimpan artikel: " . $e->getMessage();
        }
    }
}

include __DIR__.'/../includes/header.php';
?>

<h2 class="mb-4">Tambah Artikel Baru</h2>

<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
    <h5>Terjadi Kesalahan:</h5>
    <ul class="mb-0">
        <?php foreach ($errors as $error): ?>
        <li><?= $error ?></li>
        <?php endforeach; ?>
    </ul>
</div>
<?php endif; ?>

<form method="POST">
    <div class="mb-3">
        <label for="title" class="form-label">Judul Artikel</label>
        <input type="text" class="form-control" id="title" name="title" 
               value="<?= htmlspecialchars($_POST['title'] ?? '') ?>" required>
    </div>
    
    <div class="mb-3">
        <label for="content" class="form-label">Konten Artikel</label>
        <textarea class="form-control" id="content" name="content" 
                  rows="10" required><?= htmlspecialchars($_POST['content'] ?? '') ?></textarea>
    </div>
    
    <div class="d-grid gap-2 d-md-flex justify-content-md-end">
        <a href="index.php" class="btn btn-secondary me-md-2">Kembali</a>
        <button type="submit" class="btn btn-primary">Simpan Artikel</button>
    </div>
</form>

<?php include __DIR__.'/../includes/footer.php'; ?>

Langkah 5: Mengedit Artikel (articles/edit.php)

php
<?php
require_once __DIR__.'/../config/database.php';
session_start();
$pageTitle = "Edit Artikel";

// Ambil ID dari URL
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// Ambil data artikel
$stmt = $pdo->prepare("SELECT * FROM articles WHERE id = ?");
$stmt->execute([$id]);
$article = $stmt->fetch();

if (!$article) {
    $_SESSION['error'] = "Artikel tidak ditemukan";
    header("Location: index.php");
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = trim($_POST['title']);
    $content = trim($_POST['content']);
    
    $errors = [];
    if (empty($title)) $errors[] = "Judul wajib diisi";
    if (strlen($title) > 255) $errors[] = "Judul maksimal 255 karakter";
    if (empty($content)) $errors[] = "Konten wajib diisi";
    
    if (empty($errors)) {
        try {
            $stmt = $pdo->prepare("UPDATE articles SET title = ?, content = ? WHERE id = ?");
            $stmt->execute([$title, $content, $id]);
            
            $_SESSION['success'] = "Artikel berhasil diperbarui!";
            header("Location: index.php");
            exit;
        } catch (PDOException $e) {
            $errors[] = "Gagal update artikel: " . $e->getMessage();
        }
    }
}

include __DIR__.'/../includes/header.php';
?>

<h2 class="mb-4">Edit Artikel</h2>

<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
    <h5>Terjadi Kesalahan:</h5>
    <ul class="mb-0">
        <?php foreach ($errors as $error): ?>
        <li><?= $error ?></li>
        <?php endforeach; ?>
    </ul>
</div>
<?php endif; ?>

<form method="POST">
    <div class="mb-3">
        <label for="title" class="form-label">Judul Artikel</label>
        <input type="text" class="form-control" id="title" name="title" 
               value="<?= htmlspecialchars($article['title']) ?>" required>
    </div>
    
    <div class="mb-3">
        <label for="content" class="form-label">Konten Artikel</label>
        <textarea class="form-control" id="content" name="content" 
                  rows="10" required><?= htmlspecialchars($article['content']) ?></textarea>
    </div>
    
    <div class="d-grid gap-2 d-md-flex justify-content-md-end">
        <a href="index.php" class="btn btn-secondary me-md-2">Batal</a>
        <button type="submit" class="btn btn-primary">Update Artikel</button>
    </div>
</form>

<?php include __DIR__.'/../includes/footer.php'; ?>

Langkah 6: Menghapus Artikel (articles/delete.php)

php
<?php
require_once __DIR__.'/../config/database.php';
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $id = isset($_POST['id']) ? (int)$_POST['id'] : 0;
    
    if ($id > 0) {
        try {
            // Cek apakah artikel ada
            $stmt = $pdo->prepare("SELECT id FROM articles WHERE id = ?");
            $stmt->execute([$id]);
            
            if ($stmt->fetch()) {
                // Hapus artikel
                $deleteStmt = $pdo->prepare("DELETE FROM articles WHERE id = ?");
                if ($deleteStmt->execute([$id])) {
                    $_SESSION['success'] = "Artikel berhasil dihapus";
                } else {
                    $_SESSION['error'] = "Gagal menghapus artikel";
                }
            } else {
                $_SESSION['error'] = "Artikel tidak ditemukan";
            }
        } catch (PDOException $e) {
            $_SESSION['error'] = "Error: " . $e->getMessage();
        }
    } else {
        $_SESSION['error'] = "ID artikel tidak valid";
    }
}

header("Location: index.php");
exit;
?>
 


Kesimpulan dan Pengembangan Lanjutan

Yang Sudah Dibangun:

✔ Sistem CRUD artikel lengkap
✔ Tampilan responsif dengan Bootstrap 5
✔ Pagination untuk navigasi artikel
✔ Validasi input dan proteksi keamanan
✔ Notifikasi operasi berhasil/gagal

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *