- 环境搭建:在你的电脑上创建一个可以运行 PHP 的本地服务器。
- 项目结构:规划好网站的文件和目录。
- 数据库设计:为博客设计并创建数据表。
- 前端页面:编写网站的 HTML 和 CSS 模板。
- 后端逻辑:使用 PHP 连接数据库、处理数据、动态生成页面。
- 核心功能实现:实现文章列表、文章详情、发表新文章等核心功能。
- 部署上线:将你的网站部署到真正的服务器上。
第零步:准备工作与环境搭建
在开始编码前,你需要一个本地的 PHP 运行环境,最简单的方法是使用集成环境包。

推荐工具:XAMPP XAMPP 是一个集成了 Apache、MySQL、PHP 和 Perl 的软件包,非常适合初学者。
- 下载 XAMPP:访问 Apache Friends 官网,下载适合你操作系统的 XAMPP 版本(推荐选择 PHP 7.4 或 8.x 的稳定版本)。
- 安装 XAMPP:像安装普通软件一样,双击安装包,一路“Next”即可。重要:在安装过程中,记住你选择的安装路径,
C:\xampp。 - 启动服务:
- 安装完成后,打开 XAMPP Control Panel。
- 点击 Apache 和 MySQL 模块的 Start 按钮,这两个服务是必须的。
- 确保它们的状态为 "Running"。
验证安装:
打开你的浏览器,访问 http://localhost 或 http://127.0.0.1,如果你能看到 XAMPP 的欢迎页面,说明环境搭建成功!
第一步:创建项目目录结构
在 XAMPP 的安装目录下,找到 htdocs 文件夹,这是你的网站根目录。
在 htdocs 文件夹里,为我们的博客项目创建一个新文件夹,my_blog。

你的项目结构应该是这样的:
C:\xampp\htdocs\my_blog\
├── assets/ # 存放 CSS, JS, 图片等静态资源
│ ├── css/
│ │ └── style.css
│ └── images/
├── includes/ # 存放公共的 PHP 文件(如数据库连接、头部、底部)
│ ├── db.php # 数据库连接文件
│ ├── header.php # 网站头部
│ └── footer.php # 网站底部
├── index.php # 首页,用于显示文章列表
├── post.php # 文章详情页
├── create_post.php # 处理发表新文章的表单
└── admin/ # 管理后台目录
└── create.php # 发表新文章的表单页面
第二步:数据库设计与创建
我们的博客需要存储文章和分类信息,我们至少需要一张数据表 posts。
- 启动 phpMyAdmin:在浏览器中访问
http://localhost/phpmyadmin,这是 XAMPP 自带的管理 MySQL 数据库的工具。 - 创建数据库:
- 在 phpMyAdmin 的主界面,点击“新建”。
- 在“数据库名”输入框中输入
blog_db,然后点击“创建”。
- 创建数据表:
- 在左侧选择刚刚创建的
blog_db数据库。 - 在右侧的“在数据库 blog_db 中创建表”区域,输入表名
posts,设置字段数为 5,然后点击“执行”。 - 按照下表定义字段:
- 在左侧选择刚刚创建的
| 字段名 | 类型 | 长度/值 | 约束 | 注释 |
|---|---|---|---|---|
id |
INT | 11 | 主键, 自增 |
文章的唯一ID |
author |
VARCHAR | 100 | 非空 |
作者 |
body |
TEXT | 非空 |
||
created_at |
TIMESTAMP | 默认:CURRENT_TIMESTAMP |
创建时间 |
* 点击“保存”按钮。
第三步:创建公共文件
在 includes 目录下创建以下文件,它们将在多个页面中被复用。
includes/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>
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<header>
<div class="container">
<a href="index.php" class="logo">我的博客</a>
<nav>
<a href="index.php">首页</a>
<a href="admin/create.php">写文章</a>
</nav>
</div>
</header>
<div class="container">
includes/footer.php
</div> <!-- .container -->
<footer>
<p>© <?php echo date("Y"); ?> 我的个人博客. All Rights Reserved.</p>
</footer>
</body>
</html>
includes/db.php
这是连接数据库的核心文件。

<?php
// 设置数据库连接参数
$host = 'localhost';
$dbname = 'blog_db';
$username = 'root'; // XAMPP 默认用户名
$password = ''; // XAMPP 默认密码为空
try {
// 创建 PDO 实例
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
// 设置 PDO 错误模式为异常
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
// 如果连接失败,显示错误信息并停止脚本
die("ERROR: Could not connect. " . $e->getMessage());
}
?>
第四步:创建样式文件
在 assets/css/style.css 中添加一些基本样式,让网站看起来更美观。
/* assets/css/style.css */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
margin: 0;
background-color: #f4f4f4;
color: #333;
}
.container {
max-width: 800px;
margin: 20px auto;
padding: 0 20px;
}
header {
background: #333;
color: #fff;
padding: 1rem 0;
position: sticky;
top: 0;
}
header .container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
color: #fff;
text-decoration: none;
font-size: 1.5rem;
font-weight: bold;
}
nav a {
color: #fff;
text-decoration: none;
margin-left: 15px;
}
nav a:hover {
text-decoration: underline;
}
.post {
background: #fff;
border: 1px solid #ddd;
border-radius: 5px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.post h2 {
margin-top: 0;
}
.post-meta {
color: #777;
font-size: 0.9em;
margin-bottom: 10px;
}
.post a {
text-decoration: none;
color: #007bff;
}
.post a:hover {
text-decoration: underline;
}
footer {
text-align: center;
padding: 20px;
margin-top: 20px;
background: #333;
color: #fff;
}
第五步:实现核心功能
我们开始用 PHP 编写网站的逻辑。
首页 - 文章列表 (index.php)
这个页面将从数据库中读取所有文章,并以列表形式展示。
<?php
// 引入头部和数据库连接文件
require_once 'includes/header.php';
require_once 'includes/db.php';
// 设置每页显示的文章数量
$per_page = 5;
// 获取当前页码,默认为第1页
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
// 计算偏移量
$offset = ($page - 1) * $per_page;
// 准备 SQL 查询,按创建时间降序排列,并限制数量
$sql = "SELECT id, title, author, created_at FROM posts ORDER BY created_at DESC LIMIT :limit OFFSET :offset";
$stmt = $pdo->prepare($sql);
// 绑定参数
$stmt->bindValue(':limit', $per_page, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
// 执行查询
$stmt->execute();
// 获取所有文章
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 获取文章总数,用于分页
$total_sql = "SELECT COUNT(*) FROM posts";
$total_stmt = $pdo->query($total_sql);
$total_posts = $total_stmt->fetchColumn();
$total_pages = ceil($total_posts / $per_page);
?>
<h1>最新文章</h1>
<?php if (empty($posts)): ?>
<p>暂无文章。</p>
<?php else: ?>
<?php foreach ($posts as $post): ?>
<article class="post">
<h2><a href="post.php?id=<?php echo htmlspecialchars($post['id']); ?>"><?php echo htmlspecialchars($post['title']); ?></a></h2>
<p class="post-meta">作者: <?php echo htmlspecialchars($post['author']); ?> | 发布于: <?php echo date("Y-m-d H:i", strtotime($post['created_at'])); ?></p>
</article>
<?php endforeach; ?>
<!-- 分页链接 -->
<div class="pagination">
<?php if ($page > 1): ?>
<a href="index.php?page=<?php echo $page - 1; ?>">上一页</a>
<?php endif; ?>
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
<a href="index.php?page=<?php echo $i; ?>" <?php echo $i == $page ? 'style="font-weight: bold;"' : ''; ?>><?php echo $i; ?></a>
<?php endfor; ?>
<?php if ($page < $total_pages): ?>
<a href="index.php?page=<?php echo $page + 1; ?>">下一页</a>
<?php endif; ?>
</div>
<?php endif; ?>
<?php
// 引入底部文件
require_once 'includes/footer.php';
?>
文章详情页 (post.php)
这个页面根据 URL 中的 id 参数来显示单篇文章的完整内容。
<?php
require_once 'includes/header.php';
require_once 'includes/db.php';
// 检查是否提供了文章 ID
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
echo "<p>无效的文章ID。</p>";
require_once 'includes/footer.php';
exit();
}
$post_id = $_GET['id'];
// 使用预处理语句防止 SQL 注入
$sql = "SELECT * FROM posts WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => $post_id]);
$post = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$post) {
echo "<p>文章未找到。</p>";
require_once 'includes/footer.php';
exit();
}
?>
<article class="post">
<h1><?php echo htmlspecialchars($post['title']); ?></h1>
<p class="post-meta">作者: <?php echo htmlspecialchars($post['author']); ?> | 发布于: <?php echo date("Y-m-d H:i", strtotime($post['created_at'])); ?></p>
<div class="post-content">
<?php echo nl2br(htmlspecialchars($post['body'])); // nl2br 保留换行 ?>
</div>
</article>
<?php
require_once 'includes/footer.php';
?>
发表新文章 - 表单页面 (admin/create.php)
这是一个简单的表单,让管理员可以输入新文章的内容。
<?php
// 检查用户是否已登录(这里为了简化,省略了登录逻辑,实际项目中必须有)
// if (!isset($_SESSION['user_id'])) {
// header('Location: login.php');
// exit;
// }
?>
<h1>发表新文章</h1>
<form action="create_post.php" method="post">
<div class="form-group">
<label for="title">标题</label>
<input type="text" id="title" name="title" required>
</div>
<div class="form-group">
<label for="author">作者</label>
<input type="text" id="author" name="author" required>
</div>
<div class="form-group">
<label for="body">内容</label>
<textarea id="body" name="body" rows="10" required></textarea>
</div>
<button type="submit">发布文章</button>
</form>
<style>
/* 简单的表单样式 */
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box; /* 保证 padding 不会影响总宽度 */
}
button {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
</style>
处理发表新文章 (create_post.php)
这个脚本接收表单提交的数据,并将其存入数据库。
<?php
// 引入数据库连接文件
require_once 'includes/db.php';
// 检查请求方法是否为 POST
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// 获取并净化表单数据
$title = trim($_POST['title']);
$author = trim($_POST['author']);
$body = trim($_POST['body']);
// 简单的数据验证
if (empty($title) || empty($author) || empty($body)) {
die("标题、作者和内容都不能为空!");
}
// 使用预处理语句插入数据,防止 SQL 注入
try {
$sql = "INSERT INTO posts (title, author, body) VALUES (:title, :author, :body)";
$stmt = $pdo->prepare($sql);
// 绑定参数
$stmt->bindParam(':title', $title);
$stmt->bindParam(':author', $author);
$stmt->bindParam(':body', $body);
// 执行插入操作
if ($stmt->execute()) {
// 插入成功,重定向到首页
header("Location: index.php");
exit();
} else {
echo "抱歉,发布文章时出错。";
}
} catch (PDOException $e) {
die("ERROR: Could not prepare/execute query: " . $e->getMessage());
}
} else {
// 如果不是 POST 请求,重定向到表单页面
header("Location: admin/create.php");
exit();
}
?>
第六步:测试你的网站
你的个人博客基本框架已经完成!打开浏览器访问 http://localhost/my_blog/,你应该能看到一个可以显示文章列表的首页。
- 访问首页:
http://localhost/my_blog/,查看文章列表。 - 点击文章标题:进入文章详情页。
- 访问管理后台:
http://localhost/my_blog/admin/create.php,填写表单并提交一篇新文章。 - 刷新首页:你应该能看到你刚刚发布的新文章了。
第七步:部署上线
当你完成了本地开发并测试无误后,就可以将你的网站部署到互联网上了。
-
购买域名和虚拟主机:
- 域名:你网站的网址,
www.myawesomewebsite.com。 - 虚拟主机:存放你网站文件和数据库的远程服务器,许多主机商提供“一键安装”环境(如 cPanel 的 Softaculous),可以自动安装 WordPress 等程序,但我们的项目需要手动上传。
- 域名:你网站的网址,
-
上传文件:
- 使用 FTP 客户端(如 FileZilla)连接到你的虚拟主机。
- 将你本地
my_blog文件夹内的所有文件(assets,includes,index.php等)上传到主机的根目录(通常是public_html或www目录)。
-
导入数据库:
- 在虚拟主机的控制面板中,找到 phpMyAdmin 或类似的数据库管理工具。
- 创建一个新的数据库(
live_blog_db)。 - 点击“导入”,选择你在本地通过 phpMyAdmin 导出的
blog_db数据库备份文件(.sql文件)。
-
修改数据库连接信息:
- 打开你上传到服务器上的
includes/db.php文件。 - 将数据库连接参数(
$host,$dbname,$username,$password)修改为你虚拟主机提供的数据库信息。
- 打开你上传到服务器上的
-
访问你的网站:
在浏览器中输入你购买的域名,你的网站就应该可以正常访问了!
总结与进阶
恭喜!你已经成功从零开始构建了一个功能完整的 PHP 博客网站。
这个教程涵盖了:
- MVC 思想:虽然我们没有严格遵循 MVC 模式,但已经将数据模型(
db.php)、视图(.php模板文件)和控制器(业务逻辑)初步分离。 - 安全性:使用了 预处理语句 来防止 SQL 注入,并对用户输出使用了
htmlspecialchars()来防止 XSS 攻击。 - 代码复用:通过
header.php和footer.php实现了代码的复用。
你可以继续学习和改进的地方:
- 用户认证系统:增加登录和注册功能,让不同用户可以发表和管理自己的文章。
- 评论系统:为每篇文章增加评论功能。
- 文章分类和标签:让文章可以归类,增加标签云。
- 前端框架:使用 Bootstrap 或 Tailwind CSS 来美化界面,使其更现代化。
- 更强大的后台:创建一个功能完善的后台管理系统,用于管理文章、评论和用户。
- 安全性增强:学习更多关于 CSRF、文件上传安全等知识。
这个实例为你打下了坚实的基础,希望你能在此基础上继续探索,开发出更精彩的项目!
