PHP – Use Case 4: Developing a Simple Blogging Platform

Project Overview

A Simple Blogging Platform allows users to create, read, update, and delete blog posts. This project encompasses content management, user authentication, and dynamic content rendering using PHP and MySQL.

Prerequisites

Ensure you have the following:

  • Web Server: Apache (using XAMPP, WAMP, or MAMP)
  • PHP: Version 7.4 or higher
  • MySQL: For database management
  • Code Editor: VS Code, Sublime Text, PHPStorm, etc.
  • Composer: For dependency management (optional)

Step-by-Step Procedure

1. Setting Up the Development Environment

  1. Install XAMPP:
    • Download from XAMPP Official Website.
    • Follow the installation wizard and install it in the default directory.
  2. Start Apache and MySQL:
    • Open the XAMPP Control Panel.
    • Start the Apache and MySQL modules.

2. Creating the Database

  1. Access phpMyAdmin:
    • Navigate to http://localhost/phpmyadmin/ in your browser.
  2. Create a New Database:
    • Click on “New” in the left sidebar.
    • Name the database blog_platform.
    • Choose “utf8mb4_unicode_ci” as the collation.
    • Click “Create”.
  3. Create a posts Table:
    • Select the blog_platform database.
    • Click on “New” to create a table.
    • Define the table with the following fields:
    Field Type Null Key Default Extra id INT NO PRI NULL AUTO_INCREMENT title VARCHAR(255) NO NULL content TEXT NO NULL author VARCHAR(100) NO NULL created_at TIMESTAMP NO CURRENT_TIMESTAMP updated_at TIMESTAMP YES NULL ON UPDATE CURRENT_TIMESTAMP
    • Click “Save”.

3. Project Structure

Organize your project files as follows:

blog-platform/
├── assets/
│   ├── css/
│   │   └── styles.css
│   └── js/
│       └── scripts.js
├── config/
│   └── db.php
├── templates/
│   ├── header.php
│   └── footer.php
├── create_post.php
├── edit_post.php
├── delete_post.php
├── view_post.php
├── index.php
└── README.md

4. Configuration

a. Database Connection (config/db.php)
<?php
// config/db.php

$host = 'localhost';
$db   = 'blog_platform';
$user = 'root'; // Default XAMPP MySQL user
$pass = '';     // Default XAMPP MySQL password is empty
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Enable exceptions
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // Fetch associative arrays
    PDO::ATTR_EMULATE_PREPARES   => false,                  // Disable emulation
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    // Handle connection errors
    throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
?>

5. Creating Reusable Templates

a. Header (templates/header.php)
<?php
// templates/header.php
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Simple Blogging Platform</title>
    <link rel="stylesheet" href="/blog-platform/assets/css/styles.css">
</head>
<body>
    <header>
        <h1>Simple Blogging Platform</h1>
        <nav>
            <a href="/blog-platform/index.php">Home</a>
            <a href="/blog-platform/create_post.php">Create New Post</a>
        </nav>
    </header>
    <main>
b. Footer (templates/footer.php)
<?php
// templates/footer.php
?>
    </main>
    <footer>
        <p>&copy; <?php echo date("Y"); ?> Your Company Name</p>
    </footer>
    <script src="/blog-platform/assets/js/scripts.js"></script>
</body>
</html>

6. Styling the Application (assets/css/styles.css)

Add basic styles to enhance the appearance.

/* assets/css/styles.css */

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

header, footer {
    background-color: #333;
    color: #fff;
    padding: 10px 20px;
}

header h1, footer p {
    margin: 0;
}

nav a {
    color: #fff;
    margin-right: 15px;
    text-decoration: none;
}

main {
    padding: 20px;
}

form {
    max-width: 600px;
    margin: auto;
}

.form-group {
    margin-bottom: 15px;
}

label {
    display: block;
    margin-bottom: 5px;
}

input[type="text"],
textarea {
    width: 100%;
    padding: 8px;
    box-sizing: border-box;
}

button {
    padding: 10px 15px;
    background-color: #007BFF;
    color: #fff;
    border: none;
    cursor: pointer;
}

button:hover {
    background-color: #0069d9;
}

table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
}

table, th, td {
    border: 1px solid #ddd;
}

th, td {
    padding: 12px;
    text-align: left;
}

th {
    background-color: #f4f4f4;
}

a {
    color: #007BFF;
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

.error {
    background-color: #f2dede;
    color: #a94442;
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid #ebccd1;
    border-radius: 4px;
}

.success {
    background-color: #dff0d8;
    color: #3c763d;
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid #d6e9c6;
    border-radius: 4px;
}

7. Creating a New Post (create_post.php)

This page allows users to create new blog posts.

<?php
// create_post.php

require 'config/db.php';
require 'templates/header.php';

$errors = [];
$success = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and validate inputs
    $title   = trim($_POST['title']);
    $content = trim($_POST['content']);
    $author  = trim($_POST['author']);

    if (empty($title)) {
        $errors[] = 'Post title is required.';
    }

    if (empty($content)) {
        $errors[] = 'Post content is required.';
    }

    if (empty($author)) {
        $errors[] = 'Author name is required.';
    }

    if (empty($errors)) {
        // Insert into database
        $stmt = $pdo->prepare('INSERT INTO posts (title, content, author) VALUES (?, ?, ?)');
        if ($stmt->execute([$title, $content, $author])) {
            $success = 'Post created successfully.';
            // Clear form fields
            $title = $content = $author = '';
        } else {
            $errors[] = 'There was an error creating the post. Please try again.';
        }
    }
}
?>

<h2>Create New Post</h2>

<?php if (!empty($errors)): ?>
    <div class="error">
        <ul>
            <?php foreach($errors as $error): ?>
                <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="success">
        <p><?php echo htmlspecialchars($success); ?></p>
    </div>
<?php endif; ?>

<form action="create_post.php" method="POST">
    <div class="form-group">
        <label for="title">Post Title:</label>
        <input type="text" id="title" name="title" value="<?php echo htmlspecialchars($title ?? ''); ?>" required>
    </div>

    <div class="form-group">
        <label for="content">Post Content:</label>
        <textarea id="content" name="content" rows="10" required><?php echo htmlspecialchars($content ?? ''); ?></textarea>
    </div>

    <div class="form-group">
        <label for="author">Author Name:</label>
        <input type="text" id="author" name="author" value="<?php echo htmlspecialchars($author ?? ''); ?>" required>
    </div>

    <button type="submit">Create Post</button>
</form>

<?php
require 'templates/footer.php';
?>

8. Viewing All Posts (index.php)

This page lists all blog posts with options to view, edit, or delete them.

<?php
// index.php

require 'config/db.php';
require 'templates/header.php';

// Fetch all posts
$stmt = $pdo->query('SELECT * FROM posts ORDER BY created_at DESC');
$posts = $stmt->fetchAll();
?>

<h2>All Blog Posts</h2>

<?php if ($posts): ?>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Title</th>
                <th>Author</th>
                <th>Created At</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($posts as $post): ?>
                <tr>
                    <td><?php echo htmlspecialchars($post['id']); ?></td>
                    <td><?php echo htmlspecialchars($post['title']); ?></td>
                    <td><?php echo htmlspecialchars($post['author']); ?></td>
                    <td><?php echo htmlspecialchars($post['created_at']); ?></td>
                    <td>
                        <a href="view_post.php?id=<?php echo $post['id']; ?>">View</a> |
                        <a href="edit_post.php?id=<?php echo $post['id']; ?>">Edit</a> |
                        <a href="delete_post.php?id=<?php echo $post['id']; ?>" onclick="return confirm('Are you sure you want to delete this post?');">Delete</a>
                    </td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
<?php else: ?>
    <p>No posts found. <a href="create_post.php">Create a new post</a>.</p>
<?php endif; ?>

<?php
require 'templates/footer.php';
?>

9. Viewing a Single Post (view_post.php)

This page displays the full content of a single blog post.

<?php
// view_post.php

require 'config/db.php';
require 'templates/header.php';

// Get post ID from URL
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// Fetch post details
$stmt = $pdo->prepare('SELECT * FROM posts WHERE id = ?');
$stmt->execute([$id]);
$post = $stmt->fetch();

if ($post):
?>

<h2><?php echo htmlspecialchars($post['title']); ?></h2>
<p><strong>Author:</strong> <?php echo htmlspecialchars($post['author']); ?></p>
<p><strong>Created At:</strong> <?php echo htmlspecialchars($post['created_at']); ?></p>
<div>
    <?php echo nl2br(htmlspecialchars($post['content'])); ?>
</div>
<a href="index.php">Back to All Posts</a>

<?php
else:
    echo "<p>Post not found.</p>";
endif;

require 'templates/footer.php';
?>

10. Editing Posts (edit_post.php)

This page allows users to edit existing blog posts.

<?php
// edit_post.php

require 'config/db.php';
require 'templates/header.php';

$errors = [];
$success = '';

// Get post ID from URL
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// Fetch existing post
$stmt = $pdo->prepare('SELECT * FROM posts WHERE id = ?');
$stmt->execute([$id]);
$post = $stmt->fetch();

if (!$post) {
    echo "<p>Post not found.</p>";
    require 'templates/footer.php';
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Sanitize and validate inputs
    $title   = trim($_POST['title']);
    $content = trim($_POST['content']);
    $author  = trim($_POST['author']);

    if (empty($title)) {
        $errors[] = 'Post title is required.';
    }

    if (empty($content)) {
        $errors[] = 'Post content is required.';
    }

    if (empty($author)) {
        $errors[] = 'Author name is required.';
    }

    if (empty($errors)) {
        // Update in database
        $stmt = $pdo->prepare('UPDATE posts SET title = ?, content = ?, author = ? WHERE id = ?');
        if ($stmt->execute([$title, $content, $author, $id])) {
            $success = 'Post updated successfully.';
            // Refresh post data
            $stmt = $pdo->prepare('SELECT * FROM posts WHERE id = ?');
            $stmt->execute([$id]);
            $post = $stmt->fetch();
        } else {
            $errors[] = 'There was an error updating the post. Please try again.';
        }
    }
}
?>

<h2>Edit Post</h2>

<?php if (!empty($errors)): ?>
    <div class="error">
        <ul>
            <?php foreach($errors as $error): ?>
                <li><?php echo htmlspecialchars($error); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if ($success): ?>
    <div class="success">
        <p><?php echo htmlspecialchars($success); ?></p>
    </div>
<?php endif; ?>

<form action="edit_post.php?id=<?php echo $id; ?>" method="POST">
    <div class="form-group">
        <label for="title">Post Title:</label>
        <input type="text" id="title" name="title" value="<?php echo htmlspecialchars($post['title']); ?>" required>
    </div>

    <div class="form-group">
        <label for="content">Post Content:</label>
        <textarea id="content" name="content" rows="10" required><?php echo htmlspecialchars($post['content']); ?></textarea>
    </div>

    <div class="form-group">
        <label for="author">Author Name:</label>
        <input type="text" id="author" name="author" value="<?php echo htmlspecialchars($post['author']); ?>" required>
    </div>

    <button type="submit">Update Post</button>
</form>

<?php
require 'templates/footer.php';
?>

11. Deleting Posts (delete_post.php)

This script handles the deletion of blog posts.

<?php
// delete_post.php

require 'config/db.php';

// Get post ID from URL
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

// Delete post
$stmt = $pdo->prepare('DELETE FROM posts WHERE id = ?');
$stmt->execute([$id]);

// Redirect back to home page
header('Location: index.php');
exit;
?>

12. Testing the Application

  1. Access the Create Post Page:
    • Navigate to http://localhost/blog-platform/create_post.php.
    • Fill in the form and submit.
    • Verify that the post appears on the “All Blog Posts” page.
  2. View a Single Post:
    • Click on “View” next to a post.
    • Ensure that the full content is displayed correctly.
  3. Edit a Post:
    • Click on “Edit” next to a post.
    • Modify the details and submit.
    • Verify that the changes are reflected on the “All Blog Posts” page.
  4. Delete a Post:
    • Click on “Delete” next to a post.
    • Confirm the deletion.
    • Ensure that the post is removed from the list.

13. Deployment Considerations

When deploying to a live server:

  • Implement User Authentication: To restrict access to creating, editing, and deleting posts.
  • Sanitize Inputs: Ensure all user inputs are properly sanitized to prevent SQL injection and XSS attacks.
  • Use HTTPS: Ensure your website uses HTTPS for encrypted data transmission.
  • Regular Backups: Implement regular backups of your database and files.
  • Error Reporting: Disable detailed error messages in production to prevent information leakage. // In production, set error reporting to minimal ini_set('display_errors', 0); ini_set('log_errors', 1);
  • Update Dependencies: Keep PHP and all libraries updated to their latest versions to patch security vulnerabilities.
Leave a Comment

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 *