HTML5+PHP+JS+CSS+JSON 个人博客系统

62 阅读3分钟

HTML5+PHP+JS+CSS+JSON 个人博客系统

下面是一个完整的个人博客系统实现方案,使用HTML5作为前端,PHP处理后端逻辑,JSON作为数据存储,CSS进行样式设计,并支持伪静态URL。

系统结构

/blog/
├── index.php                # 首页入口
├── admin/                   # 后台管理目录
│   ├── index.php            # 后台首页
│   ├── login.php            # 登录处理
│   └── logout.php           # 退出处理
├── includes/                # 包含文件
│   ├── config.php           # 配置文件
│   ├── functions.php        # 公共函数
│   └── auth.php             # 认证检查
├── posts/                   # 文章存储目录
│   ├── sample-post.json     # 示例文章
│   └── ...                  # 其他文章
├── static/                  # 静态资源
│   ├── css/
│   │   └── style.css        # 主样式表
│   ├── js/
│   │   └── main.js          # 主JavaScript文件
│   └── images/              # 图片资源
└── templates/               # 模板文件
    ├── header.php           # 页头
    ├── footer.php           # 页脚
    ├── home.php             # 首页模板
    ├── post.php             # 文章页模板
    └── admin/               # 后台模板
        ├── dashboard.php    # 仪表盘
        └── editor.php      # 编辑器

实现代码

1. 配置文件 (includes/config.php)

<?php
// 博客配置
define('BLOG_TITLE', '我的个人博客');
define('BLOG_DESCRIPTION', '一个简单的个人博客系统');
define('BLOG_AUTHOR', '博主');
define('POSTS_DIR', __DIR__ . '/../posts/');
define('ADMIN_USERNAME', 'admin');
define('ADMIN_PASSWORD_HASH', password_hash('yourpassword', PASSWORD_DEFAULT)); // 替换为你的密码

// 开启伪静态
define('REWRITE_ENABLED', true);

// 时区设置
date_default_timezone_set('Asia/Shanghai');

2. 公共函数 (includes/functions.php)

<?php
require_once 'config.php';

// 获取所有文章
function get_all_posts() {
    $posts = [];
    $files = glob(POSTS_DIR . '*.json');
    
    foreach ($files as $file) {
        $content = file_get_contents($file);
        $post = json_decode($content, true);
        $post['slug'] = basename($file, '.json');
        $posts[] = $post;
    }
    
    // 按日期排序
    usort($posts, function($a, $b) {
        return strtotime($b['date']) - strtotime($a['date']);
    });
    
    return $posts;
}

// 获取单篇文章
function get_post($slug) {
    $file = POSTS_DIR . $slug . '.json';
    
    if (file_exists($file)) {
        $content = file_get_contents($file);
        $post = json_decode($content, true);
        $post['slug'] = $slug;
        return $post;
    }
    
    return null;
}

// 保存文章
function save_post($slug, $data) {
    $file = POSTS_DIR . $slug . '.json';
    return file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT));
}

// 删除文章
function delete_post($slug) {
    $file = POSTS_DIR . $slug . '.json';
    if (file_exists($file)) {
        return unlink($file);
    }
    return false;
}

// 生成SEO友好的URL slug
function generate_slug($title) {
    $slug = preg_replace('/[^a-z0-9]+/', '-', strtolower($title));
    $slug = trim($slug, '-');
    return $slug;
}

// 伪静态URL处理
function get_clean_url() {
    if (REWRITE_ENABLED && isset($_SERVER['PATH_INFO'])) {
        return trim($_SERVER['PATH_INFO'], '/');
    }
    return isset($_GET['page']) ? $_GET['page'] : 'home';
}

3. 认证检查 (includes/auth.php)

<?php
require_once 'config.php';
require_once 'functions.php';

session_start();

function is_logged_in() {
    return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
}

function require_login() {
    if (!is_logged_in()) {
        header('Location: /admin/login.php');
        exit;
    }
}

function login($username, $password) {
    if ($username === ADMIN_USERNAME && password_verify($password, ADMIN_PASSWORD_HASH)) {
        $_SESSION['logged_in'] = true;
        return true;
    }
    return false;
}

function logout() {
    session_destroy();
    header('Location: /admin/login.php');
    exit;
}

4. 前端入口 (index.php)

<?php
require_once 'includes/config.php';
require_once 'includes/functions.php';

$page = get_clean_url();

// 路由处理
if ($page === 'home' || empty($page)) {
    // 首页
    $posts = get_all_posts();
    include 'templates/header.php';
    include 'templates/home.php';
    include 'templates/footer.php';
} elseif (preg_match('/^post\/([a-z0-9\-]+)$/', $page, $matches)) {
    // 文章页
    $post = get_post($matches[1]);
    if ($post) {
        include 'templates/header.php';
        include 'templates/post.php';
        include 'templates/footer.php';
    } else {
        header("HTTP/1.0 404 Not Found");
        include 'templates/header.php';
        echo '<h1>文章未找到</h1>';
        include 'templates/footer.php';
    }
} else {
    // 404
    header("HTTP/1.0 404 Not Found");
    include 'templates/header.php';
    echo '<h1>页面未找到</h1>';
    include 'templates/footer.php';
}

5. 页头模板 (templates/header.php)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo BLOG_TITLE; ?> - <?php echo isset($post) ? $post['title'] : '首页'; ?></title>
    <meta name="description" content="<?php echo BLOG_DESCRIPTION; ?>">
    <meta name="author" content="<?php echo BLOG_AUTHOR; ?>">
    <link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
    <header class="site-header">
        <h1><a href="/"><?php echo BLOG_TITLE; ?></a></h1>
        <p><?php echo BLOG_DESCRIPTION; ?></p>
        <nav>
            <a href="/">首页</a>
            <?php if (is_logged_in()): ?>
                <a href="/admin/">后台</a>
                <a href="/admin/logout.php">退出</a>
            <?php else: ?>
                <a href="/admin/login.php">登录</a>
            <?php endif; ?>
        </nav>
    </header>
    <main class="container">

6. 页脚模板 (templates/footer.php)

    </main>
    <footer class="site-footer">
        <p>&copy; <?php echo date('Y'); ?> <?php echo BLOG_AUTHOR; ?>. 保留所有权利.</p>
    </footer>
    <script src="/static/js/main.js"></script>
</body>
</html>

7. 首页模板 (templates/home.php)

<section class="posts-list">
    <h2>最新文章</h2>
    <?php foreach ($posts as $post): ?>
        <article class="post-summary">
            <h3><a href="/post/<?php echo $post['slug']; ?>"><?php echo htmlspecialchars($post['title']); ?></a></h3>
            <div class="post-meta">
                <time datetime="<?php echo $post['date']; ?>"><?php echo date('Y-m-d', strtotime($post['date'])); ?></time>
            </div>
            <div class="post-excerpt">
                <?php echo nl2br(htmlspecialchars(substr($post['content'], 0, 200) . '...')); ?>
            </div>
            <a href="/post/<?php echo $post['slug']; ?>" class="read-more">阅读更多</a>
        </article>
    <?php endforeach; ?>
</section>

8. 文章页模板 (templates/post.php)

<article class="post-full">
    <h2><?php echo htmlspecialchars($post['title']); ?></h2>
    <div class="post-meta">
        <time datetime="<?php echo $post['date']; ?>"><?php echo date('Y-m-d H:i', strtotime($post['date'])); ?></time>
    </div>
    <div class="post-content">
        <?php echo nl2br(htmlspecialchars($post['content'])); ?>
    </div>
    
    <?php if (is_logged_in()): ?>
        <div class="post-actions">
            <a href="/admin/editor.php?slug=<?php echo $post['slug']; ?>" class="edit-post">编辑</a>
            <a href="/admin/delete.php?slug=<?php echo $post['slug']; ?>" class="delete-post" onclick="return confirm('确定要删除这篇文章吗?')">删除</a>
        </div>
    <?php endif; ?>
</article>

9. 后台登录 (admin/login.php)

<?php
require_once '../includes/auth.php';

if (is_logged_in()) {
    header('Location: /admin/');
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'] ?? '';
    $password = $_POST['password'] ?? '';
    
    if (login($username, $password)) {
        header('Location: /admin/');
        exit;
    } else {
        $error = '用户名或密码错误';
    }
}

include '../templates/header.php';
?>

<div class="login-form">
    <h2>后台登录</h2>
    <?php if (isset($error)): ?>
        <div class="error"><?php echo $error; ?></div>
    <?php endif; ?>
    <form method="post">
        <div class="form-group">
            <label for="username">用户名:</label>
            <input type="text" id="username" name="username" required>
        </div>
        <div class="form-group">
            <label for="password">密码:</label>
            <input type="password" id="password" name="password" required>
        </div>
        <button type="submit">登录</button>
    </form>
</div>

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

10. 后台首页 (admin/index.php)

<?php
require_once '../includes/auth.php';
require_login();

$posts = get_all_posts();

include '../templates/header.php';
?>

<div class="admin-dashboard">
    <h2>文章管理</h2>
    <a href="/admin/editor.php" class="new-post">新建文章</a>
    
    <table class="posts-table">
        <thead>
            <tr>
                <th>标题</th>
                <th>日期</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($posts as $post): ?>
                <tr>
                    <td><?php echo htmlspecialchars($post['title']); ?></td>
                    <td><?php echo date('Y-m-d', strtotime($post['date'])); ?></td>
                    <td>
                        <a href="/admin/editor.php?slug=<?php echo $post['slug']; ?>">编辑</a>
                        <a href="/admin/delete.php?slug=<?php echo $post['slug']; ?>" onclick="return confirm('确定要删除这篇文章吗?')">删除</a>
                    </td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
</div>

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

11. 编辑器 (admin/editor.php)

<?php
require_once '../includes/auth.php';
require_login();

$slug = $_GET['slug'] ?? '';
$post = $slug ? get_post($slug) : null;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = trim($_POST['title']);
    $content = trim($_POST['content']);
    $date = date('Y-m-d H:i:s');
    
    $new_slug = generate_slug($title);
    
    $post_data = [
        'title' => $title,
        'content' => $content,
        'date' => $date
    ];
    
    // 如果是编辑现有文章且标题改变,需要删除旧文件
    if ($post && $slug !== $new_slug) {
        delete_post($slug);
    }
    
    if (save_post($new_slug, $post_data)) {
        header('Location: /admin/');
        exit;
    } else {
        $error = '保存文章时出错';
    }
}

include '../templates/header.php';
?>

<div class="post-editor">
    <h2><?php echo $post ? '编辑文章' : '新建文章'; ?></h2>
    <?php if (isset($error)): ?>
        <div class="error"><?php echo $error; ?></div>
    <?php endif; ?>
    
    <form method="post">
        <div class="form-group">
            <label for="title">标题:</label>
            <input type="text" id="title" name="title" value="<?php echo $post ? htmlspecialchars($post['title']) : ''; ?>" required>
        </div>
        <div class="form-group">
            <label for="content">内容:</label>
            <textarea id="content" name="content" rows="15" required><?php echo $post ? htmlspecialchars($post['content']) : ''; ?></textarea>
        </div>
        <button type="submit">保存</button>
        <a href="/admin/" class="cancel">取消</a>
    </form>
</div>

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

12. 删除文章 (admin/delete.php)

<?php
require_once '../includes/auth.php';
require_login();

$slug = $_GET['slug'] ?? '';

if ($slug && delete_post($slug)) {
    header('Location: /admin/');
    exit;
} else {
    header('Location: /admin/?error=delete_failed');
    exit;
}

13. 退出登录 (admin/logout.php)

<?php
require_once '../includes/auth.php';
logout();

14. 主样式表 (static/css/style.css)

/* 基础样式 */
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 0;
    color: #333;
    background-color: #f9f9f9;
}

.container {
    max-width: 800px;
    margin: 0 auto;
    padding: 20px;
}

/* 页头样式 */
.site-header {
    background: #333;
    color: #fff;
    padding: 20px 0;
    text-align: center;
}

.site-header a {
    color: #fff;
    text-decoration: none;
}

.site-header nav a {
    margin: 0 10px;
    padding: 5px 10px;
    border-radius: 3px;
}

.site-header nav a:hover {
    background: #555;
}

/* 页脚样式 */
.site-footer {
    text-align: center;
    padding: 20px 0;
    margin-top: 40px;
    border-top: 1px solid #ddd;
}

/* 文章列表样式 */
.posts-list {
    margin-top: 30px;
}

.post-summary {
    background: #fff;
    padding: 20px;
    margin-bottom: 20px;
    border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.post-summary h3 {
    margin-top: 0;
}

.post-meta {
    color: #666;
    font-size: 0.9em;
    margin-bottom: 10px;
}

.post-excerpt {
    margin-bottom: 15px;
}

.read-more {
    display: inline-block;
    background: #333;
    color: #fff;
    padding: 5px 10px;
    text-decoration: none;
    border-radius: 3px;
    font-size: 0.9em;
}

/* 完整文章样式 */
.post-full {
    background: #fff;
    padding: 30px;
    border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.post-content {
    margin-top: 20px;
}

/* 后台样式 */
.admin-dashboard {
    background: #fff;
    padding: 30px;
    border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.new-post {
    display: inline-block;
    background: #4CAF50;
    color: #fff;
    padding: 8px 15px;
    margin-bottom: 20px;
    text-decoration: none;
    border-radius: 3px;
}

.posts-table {
    width: 100%;
    border-collapse: collapse;
}

.posts-table th, .posts-table td {
    padding: 10px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}

.posts-table th {
    background: #f5f5f5;
}

.posts-table a {
    margin-right: 10px;
    color: #333;
}

/* 编辑器样式 */
.post-editor {
    background: #fff;
    padding: 30px;
    border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

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

.form-group label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
}

.form-group input[type="text"],
.form-group textarea {
    width: 100%;
    padding: 8px;
    border: 1px solid #ddd;
    border-radius: 3px;
}

.form-group textarea {
    min-height: 300px;
}

button[type="submit"] {
    background: #4CAF50;
    color: #fff;
    border: none;
    padding: 10px 20px;
    border-radius: 3px;
    cursor: pointer;
}

.cancel {
    margin-left: 10px;
    color: #333;
    text-decoration: none;
}

/* 登录表单样式 */
.login-form {
    max-width: 400px;
    margin: 50px auto;
    background: #fff;
    padding: 30px;
    border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.login-form h2 {
    margin-top: 0;
}

.error {
    color: #f44336;
    margin-bottom: 15px;
    padding: 10px;
    background: #ffebee;
    border-radius: 3px;
}

/* 响应式设计 */
@media (max-width: 600px) {
    .container {
        padding: 10px;
    }
    
    .post-full, .post-summary, .admin-dashboard, .post-editor, .login-form {
        padding: 15px;
    }
}

15. 主JavaScript文件 (static/js/main.js)

document.addEventListener('DOMContentLoaded', function() {
    // 可以在这里添加前端交互逻辑
    console.log('博客系统已加载');
    
    // 示例:为代码块添加语法高亮
    document.querySelectorAll('pre code').forEach((block) => {
        hljs.highlightBlock(block);
    });
});

16. 伪静态配置 (Apache的.htaccess)

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    
    # 首页
    RewriteRule ^$ index.php [L]
    
    # 文章页
    RewriteRule ^post/([a-z0-9\-]+)$ index.php?page=post/$1 [L]
    
    # 其他页面
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php?page=$1 [L,QSA]
</IfModule>

部署说明

  1. 将上述文件按照目录结构放置到你的Web服务器上
  2. 确保服务器支持PHP (PHP 7.0+)
  3. 确保posts目录有写入权限 (chmod 775 posts/)
  4. 如果使用Apache,确保启用了mod_rewrite模块
  5. 修改admin/config.php中的用户名和密码

功能特点

  1. 无数据库设计:使用JSON文件存储文章数据
  2. 伪静态URL:支持友好的URL结构
  3. 响应式设计:适配各种设备屏幕
  4. 完整的前后台分离:HTML5实现前台展示,PHP处理后端逻辑
  5. 简单的文章管理:支持创建、编辑、删除文章
  6. 基础认证系统:保护后台管理功能

扩展建议

  1. 添加文章分类功能
  2. 实现文章标签系统
  3. 添加评论功能
  4. 实现文章搜索
  5. 添加图片上传功能
  6. 实现缓存机制提高性能

这个博客系统简单但功能完整,适合个人使用。你可以根据需要进一步扩展和定制。 更多详情:baijiahao.baidu.com/s?id=183050…