StreetGeek Academy Β· PHP Foundations

🧩 Module 12: Final Project – Simple Blog System

Objective: Build a complete, functional Blog System using PHP and MySQL.
Students will be able to create, read, edit, and delete posts, with basic admin authentication and error handling.

🧱 Project Overview

Your final project will include:

  • A home page that lists all blog posts
  • A form to add new posts
  • A page to edit and delete posts
  • A database to store posts
  • Sessions for simple admin login
  • Error handling to keep the system stable

πŸ—‚ Project Structure

php-blog/
β”‚
β”œβ”€β”€ db.php
β”œβ”€β”€ index.php
β”œβ”€β”€ add-post.php
β”œβ”€β”€ edit-post.php
β”œβ”€β”€ delete-post.php
β”œβ”€β”€ login.php
β”œβ”€β”€ logout.php
└── style.css

πŸ”Ή Step 1: Set Up Database

Create database:

  • Name: streetgeek_blog

Create table:

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

πŸ”Ή Step 2: Database Connection (db.php)

<?php
$host = "localhost";
$user = "root";
$pass = "";
$db  = "streetgeek_blog";

$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
?>

πŸ”Ή Step 3: Blog Homepage (index.php)

Displays all blog posts in reverse order.

<?php include('db.php'); ?>
<!DOCTYPE html>
<html>
<head>
  <title>StreetGeek Blog</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>StreetGeek Blog</h1>
  <a href="add-post.php" class="button">+ Add New Post</a>

  <hr>

  <?php
  $sql    = "SELECT * FROM posts ORDER BY created_at DESC";
  $result = $conn->query($sql);

  if ($result->num_rows > 0) {
      while($row = $result->fetch_assoc()) {
          echo "<h2>" . htmlspecialchars($row['title']) . "</h2>";
          echo "<p>" . nl2br(htmlspecialchars(substr($row['content'], 0, 250))) . "...</p>";
          echo "<p><em>By " . htmlspecialchars($row['author']) . " on " . $row['created_at'] . "</em></p>";
          echo "<a href='edit-post.php?id=" . $row['id'] . "'>Edit</a> | ";
          echo "<a href='delete-post.php?id=" . $row['id'] . "'>Delete</a>";
          echo "<hr>";
      }
  } else {
      echo "<p>No posts found.</p>";
  }
  $conn->close();
  ?>
</body>
</html>

πŸ”Ή Step 4: Add New Post (add-post.php)

<?php include('db.php'); ?>

<!DOCTYPE html>
<html>
<head>
  <title>Add Post</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h2>Add a New Blog Post</h2>

  <form method="POST" action="">
    Title: <br>
    <input type="text" name="title" required><br>
    Content: <br>
    <textarea name="content" rows="8" required></textarea><br>
    Author: <br>
    <input type="text" name="author" required><br>
    <input type="submit" name="submit" value="Publish Post">
  </form>

  <?php
  if (isset($_POST['submit'])) {
      $title   = htmlspecialchars($_POST['title']);
      $content = htmlspecialchars($_POST['content']);
      $author  = htmlspecialchars($_POST['author']);

      $stmt = $conn->prepare("INSERT INTO posts (title, content, author) VALUES (?, ?, ?)");
      $stmt->bind_param("sss", $title, $content, $author);

      if ($stmt->execute()) {
          echo "<p style='color:green;'>Post published successfully!</p>";
      } else {
          echo "<p style='color:red;'>Error: " . $conn->error . "</p>";
      }
  }
  ?>
  <a href="index.php">← Back to Blog</a>
</body>
</html>

πŸ”Ή Step 5: Edit Post (edit-post.php)

<?php include('db.php'); ?>

<?php
if (isset($_GET['id'])) {
    $id     = intval($_GET['id']);
    $result = $conn->query("SELECT * FROM posts WHERE id=$id");
    $post   = $result->fetch_assoc();
}

if (isset($_POST['update'])) {
    $title   = htmlspecialchars($_POST['title']);
    $content = htmlspecialchars($_POST['content']);
    $author  = htmlspecialchars($_POST['author']);
    $id      = intval($_POST['id']);

    $stmt = $conn->prepare("UPDATE posts SET title=?, content=?, author=? WHERE id=?");
    $stmt->bind_param("sssi", $title, $content, $author, $id);
    $stmt->execute();

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

<h2>Edit Post</h2>
<form method="POST" action="">
  <input type="hidden" name="id" value="<?php echo $post['id']; ?>">
  Title: <br>
  <input type="text" name="title" value="<?php echo htmlspecialchars($post['title']); ?>" required><br>
  Content: <br>
  <textarea name="content" rows="8" required><?php echo htmlspecialchars($post['content']); ?></textarea><br>
  Author: <br>
  <input type="text" name="author" value="<?php echo htmlspecialchars($post['author']); ?>" required><br>
  <input type="submit" name="update" value="Update Post">
</form>

<a href="index.php">← Back to Blog</a>

πŸ”Ή Step 6: Delete Post (delete-post.php)

<?php include('db.php'); ?>

<?php
if (isset($_GET['id'])) {
    $id   = intval($_GET['id']);
    $stmt = $conn->prepare("DELETE FROM posts WHERE id=?");
    $stmt->bind_param("i", $id);
    $stmt->execute();
}

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

πŸ”Ή Step 7: Admin Login (login.php / logout.php)

Add basic session login to protect editing/deleting.

login.php

<?php
session_start();
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $user = $_POST["username"];
    $pass = $_POST["password"];
    if ($user == "admin" && $pass == "1234") {
        $_SESSION["admin"] = $user;
        header("Location: index.php");
        exit;
    } else {
        $error = "Invalid login.";
    }
}
?>
<h2>Admin Login</h2>
<form method="POST" action="">
  Username: <input type="text" name="username"><br>
  Password: <input type="password" name="password"><br>
  <input type="submit" value="Login">
</form>
<?php if (isset($error)) echo "<p style='color:red;'>$error</p>"; ?>

logout.php

<?php
session_start();
session_destroy();
header("Location: login.php");
exit;
?>

You can extend your edit/delete files to check:

<?php
session_start();
if (!isset($_SESSION["admin"])) {
    header("Location: login.php");
    exit;
}
?>

πŸ”Ή Step 8: Add Basic Styling (style.css)

body {
  font-family: Arial, sans-serif;
  margin: 40px;
  background: #f5f6fa;
  color: #333;
}
h1, h2 {
  color: #0E477B;
}
input, textarea {
  width: 100%;
  margin-bottom: 10px;
  padding: 8px;
}
.button {
  background: #0E477B;
  color: white;
  padding: 8px 16px;
  text-decoration: none;
  border-radius: 4px;
}
.button:hover {
  background: #08315c;
}

βœ… Clean, readable UI for your first blog system.

🎯 BONUS: Error Handling Integration

Add this to the top of db.php:

ini_set('log_errors', 1);
ini_set('error_log', 'blog-errors.log');
error_reporting(E_ALL);

βœ… Logs database or PHP errors to blog-errors.log safely.

🧾 Module 12 Quiz

# Question Options Correct
1 What SQL command retrieves data? a) GET Β· b) SELECT Β· c) FETCH b
2 What function connects PHP to MySQL? a) mysqli_connect() Β· b) connect_db() Β· c) mysql_start() a
3 What does CRUD stand for? a) Create, Read, Update, Delete Β· b) Copy, Read, Upload, Download a
4 How do you prevent SQL injection? a) Escape quotes Β· b) Use prepared statements Β· c) Use cookies b
5 What command deletes a record from a table? a) DROP Β· b) ERASE Β· c) DELETE c

πŸ’ͺ FINAL CHALLENGE – StreetGeek Simple CMS

Objective: Transform your blog into a lightweight CMS with:

  • Secure admin login
  • Create/Edit/Delete blog posts
  • Error logging
  • Dynamic homepage

Bonus Features:

  • βœ… Add β€œPublished Date” and β€œCategory” fields
  • βœ… Implement search or filter by author
  • βœ… Add a β€œRead More” page for full post content

🧾 Submission Checklist

  • βœ… Database: streetgeek_blog created
  • βœ… index.php β†’ displays posts
  • βœ… add-post.php β†’ inserts new posts
  • βœ… edit-post.php β†’ updates existing post
  • βœ… delete-post.php β†’ removes posts
  • βœ… login.php + logout.php β†’ working session login
  • βœ… CSS applied for layout
  • βœ… Quiz completed

🏁 CONGRATULATIONS! πŸŽ‰
You’ve just built your first dynamic PHP + MySQL application.
You now understand the full lifecycle of a PHP web app β€” from server setup to database integration and user interaction.

Next steps:

  • Deploy your project on your StreetGeek VPS or LocalWP.
  • Back up your database using phpMyAdmin.
  • Prepare your course capstone submission for review.