Appearance
第 15 章:完整实战项目(企业级风格)
实战 4:个人博客系统
项目概述
个人博客系统是一个完整的 Web 应用,包括文章列表、文章详情、分类管理、后台登录和文章增删改查功能。
技术栈
- PHP
- MySQL
- HTML/CSS
- Session
功能模块
- 前台展示
- 文章列表
- 文章详情
- 分类筛选
- 后台管理
- 管理员登录
- 文章管理(增删改查)
- 分类管理
数据库设计
sql
CREATE DATABASE IF NOT EXISTS blog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE blog;
-- 管理员表
CREATE TABLE IF NOT EXISTS admins (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 分类表
CREATE TABLE IF NOT EXISTS categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 文章表
CREATE TABLE IF NOT EXISTS articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
category_id INT,
admin_id INT,
views INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(id),
FOREIGN KEY (admin_id) REFERENCES admins(id)
);
-- 插入默认管理员
INSERT INTO admins (username, password) VALUES ('admin', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi');
-- 密码是 'password'
-- 插入默认分类
INSERT INTO categories (name) VALUES ('技术'), ('生活'), ('随笔');
-- 插入示例文章
INSERT INTO articles (title, content, category_id, admin_id) VALUES
('PHP 入门教程', 'PHP 是一种服务器端脚本语言...', 1, 1),
('MySQL 基础知识', 'MySQL 是一种关系型数据库...', 1, 1),
('我的学习心得', '学习编程需要坚持不懈...', 2, 1);项目结构
blog/
├── index.php # 首页(文章列表)
├── article.php # 文章详情
├── admin/
│ ├── login.php # 后台登录
│ ├── logout.php # 退出登录
│ ├── index.php # 后台首页
│ ├── articles.php # 文章管理
│ └── categories.php # 分类管理
├── config.php # 数据库配置
└── style.css # 样式文件核心代码实现
1. 数据库配置文件 (config.php)
php
<?php
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'blog');
// 连接数据库
function getConnection() {
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if (!$conn) {
die("连接失败: " . mysqli_connect_error());
}
mysqli_set_charset($conn, 'utf8mb4');
return $conn;
}
// 初始化数据库
function initDatabase() {
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS);
// 创建数据库
$sql = "CREATE DATABASE IF NOT EXISTS `" . DB_NAME . "` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
mysqli_query($conn, $sql);
mysqli_select_db($conn, DB_NAME);
// 创建表
$sql = "CREATE TABLE IF NOT EXISTS admins (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
mysqli_query($conn, $sql);
$sql = "CREATE TABLE IF NOT EXISTS categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
mysqli_query($conn, $sql);
$sql = "CREATE TABLE IF NOT EXISTS articles (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
category_id INT,
admin_id INT,
views INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
mysqli_query($conn, $sql);
// 插入默认数据
$sql = "SELECT COUNT(*) as count FROM admins";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
if ($row['count'] == 0) {
$hashed_password = password_hash('password', PASSWORD_DEFAULT);
$sql = "INSERT INTO admins (username, password) VALUES ('admin', '$hashed_password')";
mysqli_query($conn, $sql);
}
$sql = "SELECT COUNT(*) as count FROM categories";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
if ($row['count'] == 0) {
$sql = "INSERT INTO categories (name) VALUES ('技术'), ('生活'), ('随笔')";
mysqli_query($conn, $sql);
}
$sql = "SELECT COUNT(*) as count FROM articles";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
if ($row['count'] == 0) {
$sql = "INSERT INTO articles (title, content, category_id, admin_id) VALUES
('PHP 入门教程', 'PHP 是一种服务器端脚本语言,特别适合 Web 开发。它简单易学,功能强大,是开发动态网站的首选语言之一。', 1, 1),
('MySQL 基础知识', 'MySQL 是一种关系型数据库管理系统,广泛应用于 Web 应用中。它开源免费,性能稳定,是 PHP 的最佳搭档。', 1, 1),
('我的学习心得', '学习编程需要坚持不懈,每天进步一点点。遇到问题不要怕,多看文档,多写代码,多思考。', 2, 1)";
mysqli_query($conn, $sql);
}
mysqli_close($conn);
}
// 初始化数据库
initDatabase();
?>2. 首页 (index.php)
php
<?php
require_once 'config.php';
$conn = getConnection();
// 获取分类
$category_id = isset($_GET['category']) ? (int)$_GET['category'] : 0;
// 查询文章
if ($category_id > 0) {
$sql = "SELECT a.*, c.name as category_name
FROM articles a
LEFT JOIN categories c ON a.category_id = c.id
WHERE a.category_id = $category_id
ORDER BY a.created_at DESC";
} else {
$sql = "SELECT a.*, c.name as category_name
FROM articles a
LEFT JOIN categories c ON a.category_id = c.id
ORDER BY a.created_at DESC";
}
$result = mysqli_query($conn, $sql);
// 查询所有分类
$categories_sql = "SELECT * FROM categories ORDER BY name";
$categories_result = mysqli_query($conn, $categories_sql);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>我的博客</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; line-height: 1.6; background-color: #f5f5f5; }
.container { max-width: 1000px; margin: 0 auto; padding: 20px; }
header { background-color: #333; color: white; padding: 20px; margin-bottom: 20px; }
header h1 { margin-bottom: 10px; }
nav { background-color: #444; padding: 10px; }
nav a { color: white; text-decoration: none; margin-right: 15px; }
nav a:hover { color: #ddd; }
.content { display: flex; gap: 20px; }
.main { flex: 3; }
.sidebar { flex: 1; background-color: white; padding: 15px; border-radius: 5px; }
.article { background-color: white; padding: 20px; margin-bottom: 20px; border-radius: 5px; }
.article h2 { margin-bottom: 10px; }
.article h2 a { color: #333; text-decoration: none; }
.article h2 a:hover { color: #007bff; }
.article-meta { color: #666; font-size: 14px; margin-bottom: 10px; }
.article-content { color: #333; }
.sidebar h3 { margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #007bff; }
.category-list { list-style: none; }
.category-list li { margin-bottom: 8px; }
.category-list a { color: #333; text-decoration: none; }
.category-list a:hover { color: #007bff; }
footer { text-align: center; padding: 20px; margin-top: 20px; background-color: #333; color: white; }
</style>
</head>
<body>
<header>
<div class="container">
<h1>我的博客</h1>
<p>记录学习与生活的点滴</p>
</div>
</header>
<nav>
<div class="container">
<a href="index.php">首页</a>
<a href="admin/login.php">后台管理</a>
</div>
</nav>
<div class="container">
<div class="content">
<div class="main">
<?php if (mysqli_num_rows($result) > 0): ?>
<?php while ($row = mysqli_fetch_assoc($result)): ?>
<div class="article">
<h2><a href="article.php?id=<?php echo $row['id']; ?>"><?php echo htmlspecialchars($row['title']); ?></a></h2>
<div class="article-meta">
分类:<?php echo htmlspecialchars($row['category_name']); ?> |
浏览:<?php echo $row['views']; ?> |
时间:<?php echo date('Y-m-d', strtotime($row['created_at'])); ?>
</div>
<div class="article-content">
<?php echo mb_substr(strip_tags($row['content']), 0, 200) . '...'; ?>
</div>
</div>
<?php endwhile; ?>
<?php else: ?>
<div class="article">
<p>暂无文章</p>
</div>
<?php endif; ?>
</div>
<div class="sidebar">
<h3>分类</h3>
<ul class="category-list">
<li><a href="index.php">全部</a></li>
<?php while ($cat = mysqli_fetch_assoc($categories_result)): ?>
<li><a href="index.php?category=<?php echo $cat['id']; ?>"><?php echo htmlspecialchars($cat['name']); ?></a></li>
<?php endwhile; ?>
</ul>
</div>
</div>
</div>
<footer>
<p>© <?php echo date('Y'); ?> 我的博客. All rights reserved.</p>
</footer>
<?php mysqli_close($conn); ?>
</body>
</html>3. 文章详情页 (article.php)
php
<?php
require_once 'config.php';
$conn = getConnection();
// 获取文章 ID
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if ($id <= 0) {
die('文章不存在');
}
// 增加浏览量
$sql = "UPDATE articles SET views = views + 1 WHERE id = $id";
mysqli_query($conn, $sql);
// 查询文章
$sql = "SELECT a.*, c.name as category_name
FROM articles a
LEFT JOIN categories c ON a.category_id = c.id
WHERE a.id = $id";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) == 0) {
die('文章不存在');
}
$article = mysqli_fetch_assoc($result);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><?php echo htmlspecialchars($article['title']); ?> - 我的博客</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; line-height: 1.6; background-color: #f5f5f5; }
.container { max-width: 800px; margin: 0 auto; padding: 20px; }
header { background-color: #333; color: white; padding: 20px; margin-bottom: 20px; }
header h1 { margin-bottom: 10px; }
nav { background-color: #444; padding: 10px; }
nav a { color: white; text-decoration: none; margin-right: 15px; }
nav a:hover { color: #ddd; }
.article { background-color: white; padding: 30px; border-radius: 5px; }
.article h1 { margin-bottom: 20px; }
.article-meta { color: #666; font-size: 14px; margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #eee; }
.article-content { line-height: 1.8; }
footer { text-align: center; padding: 20px; margin-top: 20px; background-color: #333; color: white; }
</style>
</head>
<body>
<header>
<div class="container">
<h1>我的博客</h1>
<p>记录学习与生活的点滴</p>
</div>
</header>
<nav>
<div class="container">
<a href="index.php">首页</a>
<a href="admin/login.php">后台管理</a>
</div>
</nav>
<div class="container">
<div class="article">
<h1><?php echo htmlspecialchars($article['title']); ?></h1>
<div class="article-meta">
分类:<?php echo htmlspecialchars($article['category_name']); ?> |
浏览:<?php echo $article['views']; ?> |
时间:<?php echo date('Y-m-d H:i', strtotime($article['created_at'])); ?>
</div>
<div class="article-content">
<?php echo nl2br(htmlspecialchars($article['content'])); ?>
</div>
</div>
</div>
<footer>
<p>© <?php echo date('Y'); ?> 我的博客. All rights reserved.</p>
</footer>
<?php mysqli_close($conn); ?>
</body>
</html>4. 后台登录 (admin/login.php)
php
<?php
session_start();
require_once '../config.php';
// 检查是否已登录
if (isset($_SESSION['admin_id'])) {
header('Location: index.php');
exit;
}
$conn = getConnection();
$error = '';
if (isset($_POST['login'])) {
$username = mysqli_real_escape_string($conn, $_POST['username']);
$password = $_POST['password'];
if (empty($username) || empty($password)) {
$error = '用户名和密码不能为空';
} else {
$sql = "SELECT * FROM admins WHERE username = '$username'";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
$admin = mysqli_fetch_assoc($result);
if (password_verify($password, $admin['password'])) {
$_SESSION['admin_id'] = $admin['id'];
$_SESSION['admin_username'] = $admin['username'];
header('Location: index.php');
exit;
} else {
$error = '密码错误';
}
} else {
$error = '用户名不存在';
}
}
}
mysqli_close($conn);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>后台登录 - 我的博客</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; background-color: #f5f5f5; display: flex; justify-content: center; align-items: center; height: 100vh; }
.login-form { background-color: white; padding: 30px; border-radius: 5px; width: 350px; }
.login-form h2 { text-align: center; margin-bottom: 20px; }
input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; }
button { width: 100%; padding: 10px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:hover { background-color: #0056b3; }
.error { color: red; text-align: center; margin-bottom: 10px; }
</style>
</head>
<body>
<div class="login-form">
<h2>后台登录</h2>
<?php if (!empty($error)): ?>
<p class="error"><?php echo $error; ?></p>
<?php endif; ?>
<form method="post">
<input type="text" name="username" placeholder="用户名" required><br>
<input type="password" name="password" placeholder="密码" required><br>
<button type="submit" name="login">登录</button>
</form>
<p style="text-align: center; margin-top: 15px; color: #666;">
默认账号:admin / password
</p>
</div>
</body>
</html>5. 后台首页 (admin/index.php)
php
<?php
session_start();
require_once '../config.php';
// 检查是否登录
if (!isset($_SESSION['admin_id'])) {
header('Location: login.php');
exit;
}
$conn = getConnection();
// 统计数据
$sql = "SELECT COUNT(*) as count FROM articles";
$result = mysqli_query($conn, $sql);
$article_count = mysqli_fetch_assoc($result)['count'];
$sql = "SELECT COUNT(*) as count FROM categories";
$result = mysqli_query($conn, $sql);
$category_count = mysqli_fetch_assoc($result)['count'];
$sql = "SELECT SUM(views) as total FROM articles";
$result = mysqli_query($conn, $sql);
$total_views = mysqli_fetch_assoc($result)['total'] ?? 0;
// 最新文章
$sql = "SELECT * FROM articles ORDER BY created_at DESC LIMIT 5";
$recent_articles = mysqli_query($conn, $sql);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>后台管理 - 我的博客</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; background-color: #f5f5f5; }
.header { background-color: #333; color: white; padding: 15px 20px; }
.header h1 { display: inline; }
.header .user { float: right; }
.header .user a { color: white; margin-left: 15px; }
.nav { background-color: #444; padding: 10px 20px; }
.nav a { color: white; text-decoration: none; margin-right: 20px; }
.nav a:hover { color: #ddd; }
.container { padding: 20px; }
.stats { display: flex; gap: 20px; margin-bottom: 30px; }
.stat-box { background-color: white; padding: 20px; border-radius: 5px; flex: 1; text-align: center; }
.stat-box h3 { color: #666; margin-bottom: 10px; }
.stat-box .number { font-size: 32px; font-weight: bold; color: #007bff; }
.recent-articles { background-color: white; padding: 20px; border-radius: 5px; }
.recent-articles h3 { margin-bottom: 15px; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #f5f5f5; }
</style>
</head>
<body>
<div class="header">
<h1>博客后台管理</h1>
<div class="user">
欢迎,<?php echo $_SESSION['admin_username']; ?>
<a href="logout.php">退出</a>
</div>
</div>
<div class="nav">
<a href="index.php">首页</a>
<a href="articles.php">文章管理</a>
<a href="categories.php">分类管理</a>
<a href="../index.php" target="_blank">查看网站</a>
</div>
<div class="container">
<div class="stats">
<div class="stat-box">
<h3>文章总数</h3>
<div class="number"><?php echo $article_count; ?></div>
</div>
<div class="stat-box">
<h3>分类总数</h3>
<div class="number"><?php echo $category_count; ?></div>
</div>
<div class="stat-box">
<h3>总浏览量</h3>
<div class="number"><?php echo $total_views; ?></div>
</div>
</div>
<div class="recent-articles">
<h3>最新文章</h3>
<table>
<tr>
<th>ID</th>
<th>标题</th>
<th>浏览量</th>
<th>发布时间</th>
</tr>
<?php while ($row = mysqli_fetch_assoc($recent_articles)): ?>
<tr>
<td><?php echo $row['id']; ?></td>
<td><?php echo htmlspecialchars($row['title']); ?></td>
<td><?php echo $row['views']; ?></td>
<td><?php echo date('Y-m-d H:i', strtotime($row['created_at'])); ?></td>
</tr>
<?php endwhile; ?>
</table>
</div>
</div>
<?php mysqli_close($conn); ?>
</body>
</html>访问项目
- 将所有文件保存到网站根目录的
blog文件夹中 - 打开浏览器,访问
http://localhost/blog/ - 点击「后台管理」,使用账号
admin和密码password登录 - 测试文章和分类管理功能
实战 5:简单后台管理系统(CMS)
项目概述
简单后台管理系统(CMS)是一个通用的内容管理系统,可以用于管理各种类型的内容。
技术栈
- PHP
- MySQL
- HTML/CSS
- Bootstrap
- Session
功能模块
- 用户管理
- 内容管理
- 系统设置
实现步骤
由于篇幅限制,这里只提供核心思路和关键代码片段。
1. 数据库设计
sql
CREATE DATABASE IF NOT EXISTS cms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE cms;
-- 用户表
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
role ENUM('admin', 'editor') DEFAULT 'editor',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 内容表
CREATE TABLE IF NOT EXISTS contents (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT,
type VARCHAR(50) DEFAULT 'page',
status ENUM('draft', 'published') DEFAULT 'draft',
author_id INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
);2. 核心功能
php
<?php
// 用户认证
function authenticate($username, $password) {
$user = getUserByUsername($username);
if ($user && password_verify($password, $user['password'])) {
return $user;
}
return false;
}
// 权限检查
function checkPermission($required_role) {
if (!isset($_SESSION['user_role']) || $_SESSION['user_role'] !== $required_role) {
header('HTTP/1.0 403 Forbidden');
die('没有权限访问');
}
}
// 内容管理
function createContent($title, $content, $type, $author_id) {
$sql = "INSERT INTO contents (title, content, type, author_id) VALUES (?, ?, ?, ?)";
// 执行 SQL...
}
function updateContent($id, $title, $content) {
$sql = "UPDATE contents SET title = ?, content = ?, updated_at = NOW() WHERE id = ?";
// 执行 SQL...
}
function deleteContent($id) {
$sql = "DELETE FROM contents WHERE id = ?";
// 执行 SQL...
}
?>小结
通过本章的学习,你完成了两个完整的实战项目:个人博客系统和简单后台管理系统。这些项目涵盖了 PHP Web 开发的核心功能,包括数据库设计、用户认证、内容管理等。通过这些项目的实践,你可以将之前学习的 PHP 知识综合运用,为实际项目开发积累经验。在实际开发中,你还可以使用 PHP 框架(如 Laravel、CodeIgniter)来提高开发效率和代码质量。
