关注点分离
一个健壮的网页模板系统,其核心思想是 关注点分离。

- HTML (结构): 只负责页面的骨架和内容,不包含任何 PHP 逻辑。
- PHP (逻辑): 负责处理数据、连接数据库、控制页面流程。
- CSS (样式): 负责页面的外观和布局。
- JavaScript (交互): 负责页面的动态行为。
我们将采用 PHP 包含文件 的方式来实现模板,这是一种非常流行且易于理解的方法。
项目结构
我们规划一个清晰的项目文件夹结构,这会让你的项目井井有条。
my_website/
├── config.php # 数据库配置信息
├── db.php # 数据库连接和查询函数
├── templates/
│ ├── header.php # 公共头部 (包含 <head>, <header>, 导航栏等)
│ ├── footer.php # 公共尾部 (包含 <footer>, <script> 标签等)
│ ├── home.php # 首页内容
│ ├── about.php # 关于我们页面内容
│ └── article.php # 文章详情页内容
├── index.php # 入口文件,根据请求加载不同的页面
└── style.css # 全局样式表
步骤 1: 数据库准备
假设我们要做一个简单的博客首页,需要从数据库获取文章列表。
-
创建数据库和表:
(图片来源网络,侵删)CREATE DATABASE my_blog; USE my_blog; CREATE TABLE articles ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -
插入一些示例数据:
INSERT INTO articles (title, content) VALUES ('欢迎来到我的博客', '这是我的第一篇博客文章,欢迎您的访问!'), ('PHP 学习心得', '今天学习了 PHP 和 MySQL 的结合,感觉非常强大。'), ('Web 开发最佳实践', '关注点分离是构建可维护网站的关键。');
步骤 2: PHP 后端逻辑
这是模板系统的“大脑”。
config.php - 安全地存储配置
重要提示: 永远不要把数据库密码等敏感信息直接写在代码里!使用一个单独的配置文件,并确保它不被直接访问。
<?php
// config.php
define('DB_HOST', 'localhost');
define('DB_USER', 'root'); // 你的数据库用户名
define('DB_PASS', 'password'); // 你的数据库密码
define('DB_NAME', 'my_blog');
?>
db.php - 数据库交互
这个文件负责连接数据库,并提供一个简单的函数来执行查询。

<?php
// db.php
require_once 'config.php';
// 创建数据库连接
function getDbConnection() {
try {
$conn = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS);
// 设置 PDO 错误模式为异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $conn;
} catch(PDOException $e) {
die("连接失败: " . $e->getMessage());
}
}
// 获取所有文章
function getArticles() {
$conn = getDbConnection();
$stmt = $conn->query("SELECT id, title, created_at FROM articles ORDER BY created_at DESC");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 根据ID获取单篇文章
function getArticleById($id) {
$conn = getDbConnection();
$stmt = $conn->prepare("SELECT * FROM articles WHERE id = :id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetch(PDO::FETCH_ASSOC);
}
?>
步骤 3: 模板文件
模板文件是纯 HTML,我们使用 PHP 的 include 和 foreach 等语法来嵌入动态内容。
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"><?php echo $page_title ?? '默认标题'; ?></title> <!-- 页面标题可动态设置 -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<nav>
<a href="index.php">首页</a>
<a href="about.php">关于我们</a>
</nav>
</header>
<main>
templates/home.php - 首页内容
这个文件只包含首页特有的内容。
<!-- templates/home.php -->
<h1>最新文章</h1>
<div class="article-list">
<?php
// 这里会从主页面的 index.php 中接收 $articles 变量
if (!empty($articles)):
foreach ($articles as $article):
?>
<article class="article-item">
<h2><a href="article.php?id=<?php echo htmlspecialchars($article['id']); ?>"><?php echo htmlspecialchars($article['title']); ?></a></h2>
<p class="post-meta">发布于: <?php echo date('Y-m-d', strtotime($article['created_at'])); ?></p>
</article>
<?php
endforeach;
else:
?>
<p>暂无文章。</p>
<?php endif; ?>
</div>
注意: htmlspecialchars() 是一个非常重要的安全函数,可以防止 XSS (跨站脚本) 攻击,所有输出到 HTML 的用户数据都应该经过它处理。
templates/footer.php - 公共尾部
这个文件会在每个页面的底部被包含。
</main>
<footer>
<p>© <?php echo date('Y'); ?> 我的博客. All rights reserved.</p>
</footer>
<script src="script.js"></script> <!-- 假设的JS文件 -->
</body>
</html>
步骤 4: 整合与入口
我们创建一个 index.php 文件作为所有页面请求的入口,它会根据请求加载不同的模板。
index.php - 主控制器
<?php
// index.php
// 1. 引入必要的文件
require_once 'db.php';
require_once 'templates/header.php';
// 2. 根据URL参数决定加载哪个页面
$page = $_GET['page'] ?? 'home'; // 默认加载首页
// 设置页面标题
$page_title = '首页';
// 3. 处理页面逻辑并加载对应的模板
switch ($page) {
case 'home':
// 获取文章数据
$articles = getArticles();
// 将数据传递给首页模板
require_once 'templates/home.php';
break;
case 'about':
$page_title = '关于我们';
// 加载关于我们页面
require_once 'templates/about.php';
break;
case 'article':
$page_title = '文章详情';
$article_id = $_GET['id'] ?? null;
if ($article_id && is_numeric($article_id)) {
$article = getArticleById($article_id);
if ($article) {
// 将单篇文章数据传递给文章详情模板
require_once 'templates/article.php';
} else {
// 文章不存在,显示404错误
echo "<h1>文章未找到</h1>";
echo "<p>抱歉,您访问的文章不存在。</p>";
}
} else {
// ID无效,显示404错误
http_response_code(404);
echo "<h1>页面未找到</h1>";
echo "<p>无效的文章ID。</p>";
}
break;
default:
// 处理404错误
http_response_code(404);
$page_title = '404 - 页面未找到';
echo "<h1>404 - 页面未找到</h1>";
echo "<p>抱歉,您访问的页面不存在。</p>";
break;
}
// 4. 引入公共尾部
require_once 'templates/footer.php';
?>
templates/about.php - 关于我们页面
<!-- templates/about.php --> <h1>关于我们</h1> <p>这是一个使用 PHP 和 MySQL 构建的简单博客模板示例。</p> <p>我们致力于分享有用的技术和生活感悟。</p>
templates/article.php - 文章详情页
<!-- templates/article.php -->
<?php if ($article): ?>
<article class="full-article">
<h1><?php echo htmlspecialchars($article['title']); ?></h1>
<p class="post-meta">发布于: <?php echo date('Y-m-d H:i:s', strtotime($article['created_at'])); ?></p>
<div class="article-content">
<p><?php echo nl2br(htmlspecialchars($article['content'])); ?></p>
</div>
</article>
<?php endif; ?>
进阶与最佳实践
-
模板引擎: 当项目变得复杂时,手写 PHP 混合 HTML 会变得难以维护,这时可以考虑使用专业的 模板引擎,如 Twig 或 Blade (Laravel)。
- 优点: 提供更干净的语法、自动转义、模板继承、布局等功能,能强制实现逻辑与表现的分离。
-
MVC 架构: 更进一步的架构是 MVC (Model-View-Controller)。
- Model (模型): 负责 数据库交互 (相当于我们的
db.php)。 - View (视图): 负责 显示HTML (相当于我们的
templates/目录)。 - Controller (控制器): 负责 接收用户请求、调用 Model、处理数据、选择 View 并渲染 (相当于我们的
index.php的逻辑部分)。 MVC 是大型 Web 应用的标准架构,能让代码结构更清晰、更易于扩展和维护。
- Model (模型): 负责 数据库交互 (相当于我们的
-
安全性:
- SQL 注入: 我们使用了 PDO (PHP Data Objects) 和 预处理语句,这是防止 SQL 注入攻击的最佳实践。
- XSS 攻击: 我们使用了
htmlspecialchars()函数来过滤输出到 HTML 的数据。 - 文件包含漏洞: 确保
config.php等敏感文件不能通过 Web 直接访问(Web 服务器配置会阻止)。
-
URL 重写: 使用
.htaccess文件和mod_rewrite模块,可以将index.php?page=article&id=1这样的 URL 变得更美观,如article/1,这需要一定的 Apache 服务器配置知识。
通过这个完整的例子,你已经掌握了使用 PHP 和 MySQL 创建网页模板的核心流程:
- 分离关注点: HTML 在模板,PHP 在逻辑文件。
- 使用
include/require来组装页面。 - 数据库操作 通过独立的函数完成。
- 入口文件 (
index.php) 作为总控制器,分发请求。 - 始终注意安全,使用 PDO 和
htmlspecialchars。
这个模板系统是构建任何动态网站(如博客、CMS、电商网站)的基础,你可以基于这个框架,不断添加新的页面和功能。
