教程大纲

  1. 核心概念理解:在写任何代码之前,我们必须明白 PHP 和 MySQL 是如何协同工作的。
  2. 环境搭建:在你的电脑上创建一个可以运行 PHP 和 MySQL 的本地环境。
  3. 数据库设计:学习如何为你的网站设计数据结构。
  4. PHP 与 MySQL 连接:编写 PHP 代码连接到你的数据库。
  5. 实现核心功能:学习增、删、改、查 这四个数据库操作的核心。
  6. 实战案例:一个简单的文章管理系统:将所有知识点串联起来,动手做一个完整的小项目。
  7. 安全与最佳实践:介绍如何防止 SQL 注入等常见安全问题。
  8. 进阶学习与资源:告诉你学完基础后,下一步该去哪里。

核心概念理解:MVC 思想入门

在传统且简单的 PHP 网站布局中,我们通常遵循一种类似 MVC(Model-View-Controller) 的简化思想,它将网站分为三个主要部分:

php mysql布局教程
(图片来源网络,侵删)
  • Model (模型) - 数据层

    • 作用:负责所有与数据库相关的操作,连接数据库、执行 SQL 查询、获取数据、保存数据等。
    • 比喻:图书馆的图书管理员,他只负责管理图书(数据),不关心图书如何展示给读者。
  • View (视图) - 表现层

    • 作用:负责展示数据,它通常是包含 HTML 和少量 PHP 代码的文件,这些 PHP 代码的主要任务是显示从模型层获取的数据。
    • 比喻:图书的封面和内页,它只负责展示图书内容(数据),本身不包含任何逻辑。
  • Controller (控制器) - 逻辑层

    • 作用:网站的“大脑”,它接收用户的请求(比如点击一个链接),调用模型层获取或处理数据,然后将数据传递给视图层进行展示。
    • 比喻:图书借阅处的服务员,读者(用户)告诉他想借什么书(请求),他去书库(模型)找书,然后把书交给读者(视图展示)。

流程总结:

php mysql布局教程
(图片来源网络,侵删)
  1. 用户请求 -> 控制器 接收请求。
  2. 控制器 调用 模型 去数据库获取数据。
  3. 模型 执行 SQL,将数据返回给 控制器
  4. 控制器 将数据传递给 视图
  5. 视图 渲染最终的 HTML 页面,并展示给 用户

文件结构示例:

my_website/
├── config.php          # 数据库连接配置 (可以看作是模型的一部分)
├── index.php           # 首页控制器和视图 (简单项目里可能混在一起)
├── about.php           # 关于页面控制器和视图
├── articles/
│   ├── list.php        # 文章列表控制器和视图
│   └── view.php        # 查看单篇文章控制器和视图
├── models/
│   └── article_model.php # 专门处理文章数据的模型 (进阶用法)
└── includes/
    └── header.php      # 页头视图 (可复用)
    └── footer.php      # 页脚视图 (可复用)

环境搭建

你需要在本地电脑上安装一个服务器环境,才能运行 PHP 和 MySQL,最简单的方法是使用集成环境包。

推荐工具:

  • XAMPP (跨平台: Windows, macOS, Linux): 最流行,功能齐全。
  • WampServer (仅 Windows): Windows 用户首选,安装简单。
  • MAMP (仅 macOS): macOS 用户首选。

安装步骤(以 XAMPP 为例):

  1. 下载:从 XAMPP 官网 下载适合你操作系统的版本。
  2. 安装:像安装普通软件一样进行安装。
  3. 启动:安装完成后,打开 XAMPP Control Panel。
  4. 启动服务:点击 ApacheMySQL 模块的 Start 按钮,这两个服务是必须的。
  5. 验证
    • 在浏览器地址栏输入 http://localhosthttp://127.0.0.1,如果看到 XAMPP 的欢迎页面,说明 Apache 服务器已成功运行。
    • 在浏览器地址栏输入 http://localhost/phpmyadmin,如果看到一个管理数据库的界面,说明 MySQL 已成功运行。

你的网站根目录:默认情况下,你所有的网站文件都应该放在 XAMPP 的 htdocs 文件夹里,在 Windows 上,路径通常是 C:\xampp\htdocs


数据库设计

假设我们要做一个简单的文章管理系统,需要存储文章信息。

步骤:

  1. 打开 http://localhost/phpmyadmin
  2. 在首页的 "创建数据库" 输入框中,输入数据库名,my_blog,然后点击创建。
  3. 在左侧选择 my_blog 数据库。
  4. 点击顶部的 "SQL" 选项卡,在文本框中输入以下 SQL 语句来创建一个 articles 表:
CREATE TABLE articles (
    id INT(11) AUTO_INCREMENT PRIMARY KEY,VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

SQL 语句解释:

  • CREATE TABLE articles (...): 创建一个名为 articles 的新表。
  • id INT(11) AUTO_INCREMENT PRIMARY KEY: 创建一个 id 字段,它是整数类型,会自动递增(每插入一条新记录,id 自动+1),并且是主键(每条记录的唯一标识),VARCHAR(255) NOT NULL 创建一个title` 字段,它是一个最大长度为255的字符串,并且不能为空。
  • content TEXT NOT NULL: 创建一个 content 字段,用于存放长文本,也不能为空。
  • created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP: 创建一个 created_at 字段,用于记录文章创建时间,默认值为当前时间。

PHP 与 MySQL 连接

我们需要一个 PHP 文件来管理数据库连接信息,这样其他文件只需要包含这个文件即可,方便维护。

创建 config.php 文件,并放在 htdocs 目录下:

<?php
// 数据库配置信息
define('DB_HOST', 'localhost');
define('DB_USER', 'root'); // XAMPP默认用户名
define('DB_PASS', '');     // XAMPP默认密码为空
define('DB_NAME', 'my_blog');
// 创建连接
$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
// 检查连接是否成功
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
}
// 设置字符集,防止中文乱码
$conn->set_charset("utf8mb4");
?>

解释:

  • mysqli: 这是 PHP 中用于操作 MySQL 数据库的一个扩展。
  • new mysqli(...): 创建一个新的数据库连接对象。
  • connect_error: 如果连接失败,这个属性会包含错误信息。
  • die(...): 如果连接失败,输出错误信息并终止脚本执行。
  • set_charset("utf8mb4"): 非常重要! 设置数据库连接的字符集为 utf8mb4,它可以完美支持包括 Emoji 在内的所有 Unicode 字符,避免乱码问题。

实现核心功能

现在我们有了数据库和连接,就可以开始进行增、删、改、查操作了,我们将在一个文件中实现这些功能。

创建 index.php 文件:

<?php
// 1. 引入数据库连接文件
require_once 'config.php';
// --- C: Create (新增文章) ---
// 检查是否是通过 POST 请求提交的表单
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['title']) && isset($_POST['content'])) {
    $title = $_POST['title'];
    $content = $_POST['content'];
    // 使用预处理语句来防止 SQL 注入
    $stmt = $conn->prepare("INSERT INTO articles (title, content) VALUES (?, ?)");
    $stmt->bind_param("ss", $title, $content); // "ss" 表示两个字符串参数
    if ($stmt->execute()) {
        echo "文章创建成功!";
    } else {
        echo "Error: " . $stmt->error;
    }
    $stmt->close();
}
// --- R: Read (读取文章列表) ---
$sql = "SELECT id, title, created_at FROM articles ORDER BY created_at DESC";
$result = $conn->query($sql);
// --- U: Update (更新文章) ---
// V: Delete (删除文章)
// ... (我们将在实战案例中实现这些)
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">我的博客</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        .article { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; }
        .article h2 { margin: 0 0 10px 0; }
        .article a { text-decoration: none; color: #0056b3; }
        .form-container { background: #f4f4f4; padding: 15px; margin-bottom: 20px; border-radius: 5px; }
    </style>
</head>
<body>
    <h1>欢迎来到我的博客</h1>
    <!-- 新增文章的表单 (View部分) -->
    <div class="form-container">
        <h2>发表新文章</h2>
        <form action="index.php" method="POST">
            <label for="title">标题:</label><br>
            <input type="text" id="title" name="title" size="50" required><br><br>
            <label for="content">内容:</label><br>
            <textarea id="content" name="content" rows="5" cols="50" required></textarea><br><br>
            <input type="submit" value="发布">
        </form>
    </div>
    <!-- 显示文章列表 (View部分) -->
    <h2>文章列表</h2>
    <?php
    if ($result->num_rows > 0) {
        // 输出每条数据
        while($row = $result->fetch_assoc()) {
            echo '<div class="article">';
            echo '<h2><a href="view.php?id=' . $row["id"] . '">' . htmlspecialchars($row["title"]) . '</a></h2>';
            echo '<p>发布于: ' . $row["created_at"] . '</p>';
            echo '</div>';
        }
    } else {
        echo "暂无文章";
    }
    ?>
    <?php
    // 5. 关闭连接
    $conn->close();
    ?>
</body>
</html>

代码解析:

  • require_once 'config.php';: 包含我们的数据库连接文件。
  • Create (新增):
    • if ($_SERVER["REQUEST_METHOD"] == "POST" ...): 判断页面是否是通过表单提交的。
    • $_POST: 一个超全局数组,用于获取通过 POST 方法提交的数据。
    • 预处理语句 (prepare, bind_param, execute): 这是防止 SQL 注入攻击的标准做法,它将 SQL 语句和数据分离开,数据库会先编译 SQL 语句,再将数据作为参数传入,从而杜绝了恶意代码被执行的可能。
    • bind_param("ss", $title, $content): "ss" 表示接下来的两个参数都是字符串。
  • Read (读取):
    • $sql = "SELECT ...": 编写 SQL 查询语句,获取所有文章的 id, title 和 created_at,并按发布时间倒序排列。
    • $conn->query($sql): 执行查询。
    • $result->num_rows > 0: 检查查询结果是否有数据。
    • while($row = $result->fetch_assoc()): 循环遍历结果集。fetch_assoc() 会将当前行数据作为一个关联数组返回($row['title'])。
    • htmlspecialchars($row["title"]): 一个非常重要的安全函数,用于将特殊字符(如 <, >, &)转换为 HTML 实体,防止 XSS (跨站脚本) 攻击。
  • 关闭连接: $conn->close(); 在脚本最后关闭数据库连接,释放资源。

实战案例:一个简单的文章管理系统

我们基于 index.php,创建 view.php 来查看单篇文章,并增加编辑和删除功能。

创建 view.php 文件:

<?php
require_once 'config.php';
// 检查 URL 中是否有 id 参数
if (!isset($_GET['id']) || empty($_GET['id'])) {
    die("文章 ID 未指定!");
}
$id = $_GET['id'];
// --- R: Read (读取单篇文章) ---
// 使用预处理语句防止 SQL 注入
$stmt = $conn->prepare("SELECT id, title, content, created_at FROM articles WHERE id = ?");
$stmt->bind_param("i", $id); // "i" 表示一个整数参数
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
    $article = $result->fetch_assoc();
} else {
    die("文章不存在!");
}
$stmt->close();
$conn->close();
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8"><?php echo htmlspecialchars($article['title']); ?></title>
    <style>
        body { font-family: sans-serif; margin: 20px; line-height: 1.6; }
        .article h1 { color: #333; }
        .article-meta { color: #777; font-size: 0.9em; margin-bottom: 20px; }
        .back-link { display: block; margin-bottom: 20px; }
    </style>
</head>
<body>
    <a href="index.php" class="back-link">&larr; 返回文章列表</a>
    <div class="article">
        <h1><?php echo htmlspecialchars($article['title']); ?></h1>
        <p class="article-meta">发布于: <?php echo $article['created_at']; ?></p>
        <hr>
        <p><?php echo nl2br(htmlspecialchars($article['content'])); ?></p>
    </div>
</body>
</html>

代码解析:

  • 我们通过 $_GET['id'] 从 URL 中获取要查看的文章 ID。
  • 使用 preparebind_param 再次安全地查询数据库。
  • get_result(): 获取预处理语句的查询结果集。
  • nl2br(): 一个有用的函数,将字符串中的换行符 \n 转换成 HTML 的 <br> 标签,这样文章内容就能正确换行了。

安全与最佳实践

我们已经在上面的代码中使用了两个最重要的安全实践:

  1. 防止 SQL 注入

    • 方法:始终使用 预处理语句参数绑定 (prepare, bind_param, execute)。
    • 为什么:它将 SQL 逻辑和数据完全分离,确保用户输入的数据不会被当作 SQL 代码来执行。
  2. 防止 XSS (跨站脚本) 攻击

    • 方法:在输出任何用户提交的数据到 HTML 页面之前,使用 htmlspecialchars() 函数。
    • 为什么:这个函数会把 <, >, &, , 等字符转换成 HTML 实体,这样,即使用户提交了 <script>alert('hacked')</script> 这样的恶意代码,浏览器也会将其作为纯文本显示,而不是执行它。

其他最佳实践:

  • 错误处理:在生产环境中,不要直接向用户显示数据库错误信息(如 die($conn->connect_error)),这会暴露服务器的敏感信息,应该记录日志,并向用户显示一个友好的错误页面。
  • 文件分离:随着项目变大,将控制器、模型、视图分离到不同的文件夹中,使代码结构更清晰。
  • 使用 PDOPDO (PHP Data Objects) 是另一种数据库访问抽象层,它比 mysqli 更灵活,因为它可以轻松切换不同类型的数据库(如 MySQL, PostgreSQL, SQLite),虽然 mysqli 也很强大,但 PDO 是更现代和推荐的选择。

进阶学习与资源

当你掌握了以上基础后,可以开始学习更高级的主题:

  • 面向对象编程:将你的模型和控制器封装成类,使代码更易于管理和复用。
  • MVC 框架:学习使用成熟的 PHP 框架,如 LaravelSymfony,它们为你提供了强大的工具(路由、ORM、模板引擎等),让你能更专注于业务逻辑,而不是重复造轮子。
  • RESTful API:学习如何构建 API,为你的移动 App 或前端 JavaScript 框架(如 Vue, React)提供数据。
  • 前端技术:学习 HTML5, CSS3, JavaScript,以及 jQuery 或现代前端框架,让你的网站交互更丰富。

推荐资源:

  • 官方文档PHP.net, MySQL.com
  • 免费教程网站:W3Schools, MDN Web Docs
  • 视频教程:YouTube, Bilibili 上有大量免费且高质量的 PHP/MySQL 教程。
  • 社区:Stack Overflow 是解决编程问题的绝佳去处。

这份教程为你打下了坚实的基础,最重要的下一步是 动手实践!尝试自己扩展这个文章系统,比如增加“编辑”和“删除”功能,或者增加“用户登录”功能,祝你学习愉快!