当前位置:首页>php>PHP 操作 MySQL 速查:PDO 连接/预处理/CRUD/事务

PHP 操作 MySQL 速查:PDO 连接/预处理/CRUD/事务

  • 2026-08-19 10:08:26
PHP 操作 MySQL 速查:PDO 连接/预处理/CRUD/事务

资料在文章末尾

前面几篇数据都存在变量、数组、文件里,但真正上线的网站需要持久化、可查询、能扛并发的存储方案。本篇从 MySQL 安装和基本概念讲起,用 phpMyAdmin 可视化建库建表,掌握 SQL 增删改查,再用 PHP 的 PDO 扩展连接数据库、执行预处理语句,彻底堵死 SQL 注入。最后两个综合实战——注册登录系统数据库版 + 博客文章 CRUD,把前面学的全串起来。

一、为什么需要数据库

上一篇的注册系统把用户数据写进了 users.json 文件。这种方式在练习阶段够用,但真上生产环境问题就暴露了:想查某个用户得把整个文件读进来遍历;两个人同时注册可能互相覆盖写入;数据量上千后性能断崖式下跌;想按注册时间排序、统计用户数量,都得自己写一堆代码。

数据库就是来解决这些问题的。它把数据按表结构分类存放,提供标准化的 SQL 语言做增删改查,内置锁机制保证多人同时操作不冲突,还有索引让查询速度不随数据量增长而暴跌。MySQL 是最主流的开源关系型数据库,和 PHP 组合就是经典的 LAMP 技术栈,本篇所有操作基于它。

二、MySQL 简介与安装确认

2.1 几个核心概念

MySQL 是关系型数据库管理系统(RDBMS),数据按表组织,表和表之间通过键关联。先把这几个术语记住,后面写代码会反复用到:

• 数据库(Database):一个项目对应一个数据库,里面可以有多张表• 表(Table):具体存数据的地方,由行和列组成,类似 Excel 工作表• 行(Row):一条完整记录,比如一个用户的所有信息• 列(Column):记录的某个属性,比如用户名、邮箱、注册时间• 主键(Primary Key):唯一标识一行的字段,通常用自增整数 id• 外键(Foreign Key):关联另一张表的字段,比如文章表里的 user_id 指向用户表

2.2 确认 MySQL 是否启动

之前装的 XAMPP 已经自带了 MySQL(实际上是 MariaDB,MySQL 的分支,完全兼容)。打开 XAMPP 控制面板,点 MySQL 那行的 Start,端口 3306 变绿就说明启动了:

也可以点 XAMPP 的 Shell 按钮打开命令行,输入 mysql -u root 回车(默认无密码),进入 MySQL 命令行后输入 SELECT VERSION(); 能看到版本号就说明一切正常:

三、SQL 入门:增删改查

SQL 就是操作数据库的标准语言,不管是 MySQL、PostgreSQL 还是 SQLite,SQL 语法基本通用。先从建库建表开始。

3.1 创建数据库和表

假设要做博客系统,先建数据库 blog,再建用户表 users:

-- 创建数据库(如果不存在)CREATE DATABASE IF NOT EXISTS blog DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;-- 使用该数据库USE blog;-- 创建用户表CREATE TABLE IF NOT EXISTS users (    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,    username VARCHAR(50) NOT NULL UNIQUE,    password VARCHAR(255) NOT NULL,    email VARCHAR(100) NOT NULL,    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

逐行说明:

• id:自增主键,每插一行自动 +1,不用手动指定• username:最长 50 字符,NOT NULL 不能为空,UNIQUE 值不能重复• password:最长 255,存哈希后的密码串• created_at:时间戳,DEFAULT CURRENT_TIMESTAMP 自动填插入时间• ENGINE=InnoDB:支持事务和外键的存储引擎• CHARSET=utf8mb4:支持 emoji 等 4 字节字符,别用 utf8(只支持 3 字节)

踩坑提醒:MySQL 里的 utf8 是阉割版,只能存 3 字节字符,遇到 emoji 会报错。建库建表一律用 utf8mb4,这是很多人的血泪教训。

3.2 插入数据 INSERT

INSERT INTO users (username, password, email) VALUES ('zhangsan', 'hashed_password_here', 'zhangsan@example.com');

批量插入也支持,一条语句插多行:

INSERT INTO users (username, password, email) VALUES('lisi', 'pass2', 'lisi@test.com'),('wangwu', 'pass3', 'wangwu@test.com');

3.3 查询数据 SELECT

查所有列所有行:

SELECT * FROM users;

只查指定列(生产环境建议明确写列名,别用 *):

SELECT username, email FROM users;

带条件查询:

SELECT * FROM users WHERE id = 1;SELECT * FROM users WHERE username LIKE '%zhang%';  -- 模糊搜索

排序和限制结果数量:

SELECT * FROM users ORDER BY created_at DESC LIMIT 10;  -- 按注册时间倒序,取最新10条

3.4 更新数据 UPDATE

UPDATE users SET email = 'newemail@test.com' WHERE id = 2;

务必加 WHERE!忘加 WHERE 的 UPDATE 会把整张表每一行都改掉,这是个经典的删库级操作。删数据同理,下面会说到。

3.5 删除数据 DELETE

DELETE FROM users WHERE id = 3;

同样,忘加 WHERE 会清空整张表。如果只是想清空表但保留结构,用 TRUNCATE TABLE users 更快,但这也是不可逆的。

3.6 其他常用 SQL

• COUNT():计数,如 SELECT COUNT(*) FROM users;• SUM() / AVG() / MAX() / MIN():求和、平均、最大、最小• GROUP BY:分组统计,如按城市统计用户数• JOIN:多表联查,后面文章 CRUD 会用到• ALTER TABLE:修改表结构,比如加列、改列类型

四、phpMyAdmin 可视化管理

命令行写 SQL 虽然专业,但刚开始学的时候可视化工具更直观。XAMPP 内置了 phpMyAdmin,浏览器访问 http://localhost/phpmyadmin 就能打开:

左侧点"新建",输入数据库名 blog,排序规则选 utf8mb4_unicode_ci,点创建:

在新建的 blog 数据库里创建表,名称填 users,字段数填 5,点执行:

然后按上面的 SQL 定义填写各字段的名称、类型、长度、索引等,点保存就行。顶部的 SQL 标签页可以直接输入 SQL 语句执行,"插入"和"浏览"功能也很好用。

个人建议:图形界面方便归方便,但 SQL 一定要自己会写。因为代码里操作数据库靠的是 PDO 执行 SQL 语句,不是靠点 phpMyAdmin 的按钮。图形工具用来调试和看数据结构就好。

五、PHP 连接 MySQL:PDO 方式

5.1 三种连接方式的历史

• mysql 扩展:PHP 5.5 废弃,PHP 7.0 彻底移除,现在写就是报错,别用• mysqli 扩展:改进版,支持面向对象和过程化,但只支持 MySQL 一种数据库• PDO(PHP Data Objects):数据库抽象层,一套接口支持 12 种数据库,原生支持预处理语句,安全性最好

本篇只讲 PDO,它是目前 PHP 连接数据库的推荐方式。

5.2 PDO 连接数据库

<?php$host = '127.0.0.1';$dbname = 'blog';$username = 'root';$password = '';$charset = 'utf8mb4';try {    $dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";    $pdo = new PDO($dsn, $username, $password, [        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,      // 抛出异常便于调试        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 默认返回关联数组        PDO::ATTR_EMULATE_PREPARES => false,              // 使用真正的预处理    ]);    echo "数据库连接成功!";} catch (PDOException $e) {    die("数据库连接失败:" . $e->getMessage());}?>

三个配置项很关键,解释一下:

• ERRMODE_EXCEPTION:出错时抛异常,比手动检查 errorInfo 方便,try-catch 就能接住• FETCH_ASSOC:fetch 时默认返回以列名为键的关联数组,不用每次都写 FETCH_ASSOC• EMULATE_PREPARES => false:关闭模拟预处理,让 MySQL 原生处理预处理语句,安全性更高

5.3 执行查询并输出结果

<?php// 数据库连接配置$host     = '127.0.0.1';$dbname   = 'blog';$dbUser   = 'root';$dbPass   = '';$charset  = 'utf8mb4';$pdo = null;try {    $dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";    $options = [        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,        PDO::ATTR_EMULATE_PREPARES   => false,    ];    $pdo = new PDO($dsn, $dbUser, $dbPass, $options);    echo "<p style='color:green'>数据库连接成功!</p>";} catch (PDOException $e) {    die("<p style='color:red'>数据库连接失败:" . htmlspecialchars($e->getMessage()) . "</p>");}// 查询用户表数据try {    $stmt = $pdo->query("SELECT * FROM users");    $users = $stmt->fetchAll();    if (empty($users)) {        echo "<p>暂无用户数据</p>";    } else {        foreach ($users as $user) {            $username = htmlspecialchars($user['username'] ?? '');            $email = htmlspecialchars($user['email'] ?? '');            echo "用户名:{$username},邮箱:{$email}<br>";        }    }} catch (PDOException $e) {    echo "<p style='color:red'>查询失败:" . htmlspecialchars($e->getMessage()) . "</p>";}?>

query() 适合没有外部变量的固定查询。一旦涉及用户输入,就必须用预处理语句,否则就是给 SQL 注入侵略者开门。

六、预处理语句:安全与高效的基石

6.1 为什么必须用预处理

先看反面教材。如果你直接把用户输入拼进 SQL:

$username = $_POST['username'];$sql = "SELECT * FROM users WHERE username = '$username'";

黑客在输入框里填 ' OR '1'='1,SQL 就变成了 SELECT * FROM users WHERE username = '' OR '1'='1',条件恒真,返回所有用户数据。这就是 SQL 注入攻击。

预处理语句的原理是:先把 SQL 模板发给数据库(结构已固定),再把参数单独发送(只当数据处理,不会被执行为 SQL 语法)。这样不管参数里填什么,都不可能改变 SQL 的结构,从根本上杜绝注入。

6.2 基本用法

<?php// 准备 SQL 模板,用命名占位符 :username$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");// 绑定参数$username = $_POST['username'];$stmt->bindParam(':username', $username);// 执行$stmt->execute();// 获取结果$user = $stmt->fetch();  // 获取一条记录?>

6.3 问号占位符写法

$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");$stmt->execute([$id]);  // 按顺序绑定$user = $stmt->fetch();

命名占位符和问号占位符功能一样,选哪个看个人习惯。命名占位符可读性好一些,参数多了不容易搞混顺序。

6.4 插入数据预处理

<?php$username = $_POST['username'];$password = password_hash($_POST['password'], PASSWORD_DEFAULT);$email = $_POST['email'];$sql = "INSERT INTO users (username, password, email) VALUES (:username, :password, :email)";$stmt = $pdo->prepare($sql);$stmt->execute([    ':username' => $username,    ':password' => $password,    ':email'    => $email,]);echo "新用户 ID:" . $pdo->lastInsertId();?>

execute() 接收一个关联数组,键名对应命名占位符。lastInsertId() 返回本次插入的自增主键值,注册后自动登录经常会用到。

6.5 更新和删除预处理

// 更新$sql = "UPDATE users SET email = :email WHERE id = :id";$stmt = $pdo->prepare($sql);$stmt->execute([':email' => $newEmail, ':id' => $userId]);// 删除$sql = "DELETE FROM users WHERE id = :id";$stmt = $pdo->prepare($sql);$stmt->execute([':id' => $userId]);

$stmt->rowCount() 返回受影响的行数,可以用来判断更新或删除是否真的执行了。

七、综合实战一:注册登录系统(数据库版)

把上一篇基于 JSON 文件的注册系统升级为数据库版。先建一张更完整的用户表,加上头像字段:

CREATE DATABASE IF NOT EXISTS blog DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;USE blog;CREATE TABLE IF NOT EXISTS users (    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户主键ID',    username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',    password VARCHAR(255) NOT NULL COMMENT '加密密码',    email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱',    avatar VARCHAR(255) DEFAULT NULL COMMENT '头像文件相对路径',    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

7.1 公共连接文件 db.php

用单例模式封装 PDO 连接,全局复用同一个连接对象,避免重复创建:

<?php/** * 数据库公共连接文件 * 单例模式获取PDO连接,全局复用,避免重复创建连接 * @return PDO */function getPdo(): PDO{    // 静态变量仅首次调用实例化    static $pdo = null;    if ($pdo === null) {        $host    = '127.0.0.1';        $dbname  = 'blog';        $dbUser  = 'root';        $dbPass  = '';        $charset = 'utf8mb4';        $dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";        $options = [            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,            PDO::ATTR_EMULATE_PREPARES   => false,        ];        $pdo = new PDO($dsn, $dbUser, $dbPass, $options);    }    return $pdo;}

后续所有页面 require 'db.php'; 后调用 getPdo() 就能拿到连接。

7.2 注册页面 register_db.php

注册逻辑:CSRF 校验 → 表单验证 → 头像上传 → 查重 → 密码哈希 → 写入数据库 → 自动登录跳转。代码比较长,建议照着敲一遍理解流程:

<?phprequire 'db.php';session_start();header("X-XSS-Protection: 1; mode=block");header("X-Frame-Options: DENY");// 生成CSRF令牌if (empty($_SESSION['csrf_token'])) {    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));}$errors = [];$inputFill = ['username' => '', 'email' => ''];$uploadDir = __DIR__ . '/uploads/avatar/';if (!file_exists($uploadDir)) {    mkdir($uploadDir, 0755, true);}$avatarPath = '';if ($_SERVER['REQUEST_METHOD'] === 'POST') {    // CSRF校验    $postToken = $_POST['csrf_token'] ?? '';    if (!hash_equals($_SESSION['csrf_token'], $postToken)) {        $errors['global'] = '非法请求,禁止跨站重复提交';    }    $username  = trim($_POST['username'] ?? '');    $password  = $_POST['password'] ?? '';    $password2 = $_POST['password2'] ?? '';    $email     = trim($_POST['email'] ?? '');    $inputFill['username'] = $username;    $inputFill['email']    = $email;    // 表单校验    if (empty($username)) {        $errors['username'] = '用户名不能为空';    } elseif (mb_strlen($username) < 3) {        $errors['username'] = '用户名至少3个字符';    }    if (empty($password)) {        $errors['password'] = '密码不能为空';    } elseif (strlen($password) < 6) {        $errors['password'] = '密码长度最少6位';    }    if ($password !== $password2) {        $errors['password2'] = '两次输入密码不一致';    }    if (empty($email)) {        $errors['email'] = '邮箱不能为空';    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {        $errors['email'] = '邮箱格式不合法';    }    // 头像上传处理    if (isset($_FILES['avatar']) && $_FILES['avatar']['error'] !== UPLOAD_ERR_NO_FILE) {        $file = $_FILES['avatar'];        if ($file['error'] !== UPLOAD_ERR_OK) {            $errors['avatar'] = '文件上传失败,请重新选择';        } else {            $finfo = new finfo(FILEINFO_MIME_TYPE);            $mime = $finfo->file($file['tmp_name']);            $allowMime = ['image/jpeg', 'image/png'];            if (!in_array($mime, $allowMime)) {                $errors['avatar'] = '仅支持 JPG / PNG 图片头像';            } elseif ($file['size'] > 1048576) {                $errors['avatar'] = '头像文件不能超过 1MB';            } else {                $ext = $mime === 'image/png' ? 'png' : 'jpg';                $fileName = md5(uniqid(microtime(true), true) . $username) . '.' . $ext;                $destFile = $uploadDir . $fileName;                if (move_uploaded_file($file['tmp_name'], $destFile)) {                    $avatarPath = 'uploads/avatar/' . $fileName;                } else {                    $errors['avatar'] = '头像保存失败,检查目录权限';                }            }        }    }    // 无错误再操作数据库    if (empty($errors)) {        try {            $pdo = getPdo();            // 查重            $checkSql = "SELECT id FROM users WHERE username = :username";            $checkStmt = $pdo->prepare($checkSql);            $checkStmt->execute([':username' => $username]);            if ($checkStmt->fetch()) {                $errors['username'] = '该用户名已被占用,请更换';            } else {                $hashPwd = password_hash($password, PASSWORD_DEFAULT);                $insertSql = "INSERT INTO users (username, password, email, avatar) VALUES (:u, :p, :e, :avatar)";                $insertStmt = $pdo->prepare($insertSql);                $insertStmt->execute([                    ':u' => $username,                    ':p' => $hashPwd,                    ':e' => $email,                    ':avatar' => $avatarPath                ]);                $uid = $pdo->lastInsertId();                $_SESSION['logged_in'] = true;                $_SESSION['user_id']   = $uid;                $_SESSION['username']  = $username;                $_SESSION['avatar']    = $avatarPath;                header('Location: welcome_db.php', true, 302);                exit;            }        } catch (PDOException $e) {            $errors['global'] = '注册失败,服务器繁忙,请稍后重试';        }    }}?><!-- HTML部分:表单含CSRF隐藏域、用户名、密码、确认密码、邮箱、头像上传 --><form method="post" enctype="multipart/form-data">    <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token'], ENT_QUOTES) ?>">    <input type="text" name="username" placeholder="至少3个字符">    <input type="password" name="password" placeholder="最少6位字符">    <input type="password" name="password2" placeholder="再次输入密码">    <input type="email" name="email" placeholder="example@xxx.com">    <input type="file" name="avatar" accept="image/jpeg,image/png">    <button type="submit">完成注册</button></form>

实战细节:数据库报错信息不要直接展示给用户,catch 里用通用提示"服务器繁忙"即可,真实错误写日志。因为 PDO 异常信息可能暴露表结构或 SQL 语句,给攻击者可乘之机。

7.3 登录页面 login_db.php

登录逻辑:查用户名 → password_verify 校验密码 → 写 Session → 跳转欢迎页:

<?phprequire 'db.php';session_start();header("X-XSS-Protection: 1; mode=block");header("X-Frame-Options: DENY");$error = '';$fillUser = '';if ($_SERVER['REQUEST_METHOD'] === 'POST') {    $username = trim($_POST['username'] ?? '');    $password = $_POST['password'] ?? '';    $fillUser = $username;    if (empty($username) || empty($password)) {        $error = '用户名和密码均不能为空';    } else {        try {            $pdo = getPdo();            $sql = "SELECT id, username, password, avatar FROM users WHERE username = :u";            $stmt = $pdo->prepare($sql);            $stmt->execute([':u' => $username]);            $user = $stmt->fetch();            if ($user && password_verify($password, $user['password'])) {                $_SESSION['logged_in'] = true;                $_SESSION['user_id']   = $user['id'];                $_SESSION['username']  = $user['username'];                $_SESSION['avatar']    = $user['avatar'];                header('Location: welcome_db.php', true, 302);                exit;            } else {                $error = '用户名或密码不正确';            }        } catch (PDOException $e) {            $error = '登录异常,请稍后重试';        }    }}?><!-- HTML部分:用户名输入框 + 密码输入框 + 登录按钮 --><form method="post">    <input type="text" name="username" placeholder="请输入注册用户名">    <input type="password" name="password" placeholder="输入登录密码">    <button type="submit">登录</button></form>

注意:登录失败提示统一写"用户名或密码不正确",不要区分"用户名不存在"和"密码错误"。否则攻击者可以通过提示差异枚举出哪些用户名是存在的,这叫用户枚举攻击。

7.4 欢迎页 welcome_db.php + 退出 logout_db.php

welcome_db.php 是受登录保护的页面,未登录自动跳回登录页,显示用户名和头像:

<?phpsession_start();if (empty($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {    header('Location: login_db.php', true, 302);    exit;}$userName = htmlspecialchars($_SESSION['username'], ENT_QUOTES);$avatar = $_SESSION['avatar'] ?? '';?><!DOCTYPE html><html lang="zh-CN"><head>    <meta charset="UTF-8">    <title>个人中心</title></head><body>    <h2>欢迎你,<?= $userName ?>!</h2>    <div>        <?php if (!empty($avatar) && file_exists($avatar)): ?>            <img src="<?= htmlspecialchars($avatar, ENT_QUOTES) ?>"                 style="width:140px;height:140px;border-radius:50%;object-fit:cover;border:3px solid #2563eb;">        <?php else: ?>            <div style="width:140px;height:140px;border-radius:50%;background:#e2e8f0;display:inline-flex;align-items:center;justify-content:center;color:#666;">暂无头像</div>        <?php endif; ?>    </div>    <a href="logout_db.php" style="display:inline-block;margin-top:24px;padding:10px 24px;background:#6c757d;color:#fff;text-decoration:none;border-radius:6px;">安全退出登录</a></body></html>

logout_db.php 安全退出三步走——清 Session 数据、清 Cookie、销毁会话文件:

<?phpsession_start();// 1. 清空会话数据$_SESSION = [];// 2. 销毁浏览器Session Cookieif (ini_get("session.use_cookies")) {    $cookieParam = session_get_cookie_params();    setcookie(        session_name(), '', time() - 86400,        $cookieParam["path"], $cookieParam["domain"],        $cookieParam["secure"], $cookieParam["httponly"]    );}// 3. 销毁服务器端会话文件session_destroy();// 4. 跳转登录页header('Location: login_db.php', true, 302);exit;?>

八、综合实战二:博客文章 CRUD

继续完善博客系统,实现文章的增、查、改、删完整流程。先建文章表,用外键关联用户表:

8.1 创建文章表

USE blog;CREATE TABLE posts (    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,    user_id INT UNSIGNED NOT NULL,    title VARCHAR(200) NOT NULL,    content TEXT NOT NULL,    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ON DELETE CASCADE 表示用户被删除时,其名下文章自动一起删除。外键约束保证文章必须有对应的作者。

8.2 发布文章 create_post.php

登录后才能发布,CSRF 校验 + 表单验证 + 预处理插入:

<?phprequire 'db.php';session_start();header("X-XSS-Protection: 1; mode=block");header("X-Frame-Options: DENY");// 未登录拦截if (empty($_SESSION['logged_in'])) {    header('Location: login_db.php', true, 302);    exit;}// CSRF令牌if (empty($_SESSION['csrf_post'])) {    $_SESSION['csrf_post'] = bin2hex(random_bytes(32));}$errors = [];$titleFill = '';$contentFill = '';if ($_SERVER['REQUEST_METHOD'] === 'POST') {    $token = $_POST['csrf_token'] ?? '';    if (!hash_equals($_SESSION['csrf_post'], $token)) {        $errors[] = '非法提交请求';    }    $titleFill   = trim($_POST['title'] ?? '');    $contentFill = trim($_POST['content'] ?? '');    if (empty($titleFill)) $errors[] = '文章标题不能为空';    if (mb_strlen($titleFill) > 200) $errors[] = '标题不能超过200个字符';    if (empty($contentFill)) $errors[] = '文章内容不能为空';    if (empty($errors)) {        try {            $pdo = getPdo();            $stmt = $pdo->prepare("INSERT INTO posts (user_id, title, content) VALUES (:uid, :title, :content)");            $stmt->execute([                ':uid'     => $_SESSION['user_id'],                ':title'   => $titleFill,                ':content' => $contentFill            ]);            header('Location: list_posts.php', true, 302);            exit;        } catch (PDOException $e) {            $errors[] = '文章发布失败,请稍后重试';        }    }}?><!-- HTML部分:标题输入框 + 内容textarea + CSRF隐藏域 + 发布按钮 -->

8.3 文章列表 list_posts.php

用 JOIN 联查文章表和用户表,一次查询拿到文章标题、作者名、发布时间:

<?phprequire 'db.php';session_start();header("X-XSS-Protection: 1; mode=block");header("X-Frame-Options: DENY");$pdo = getPdo();// 联表查询文章+作者$sql = "SELECT p.id, p.title, p.created_at, u.username        FROM posts p        JOIN users u ON p.user_id = u.id        ORDER BY p.created_at DESC";$stmt = $pdo->query($sql);$postList = $stmt->fetchAll();?><!-- HTML部分:遍历$postList输出文章卡片,每篇带标题链接和作者信息 -->

8.4 查看文章 view_post.php

<?phprequire 'db.php';session_start();header("X-XSS-Protection: 1; mode=block");header("X-Frame-Options: DENY");$id = trim($_GET['id'] ?? '');$pdo = getPdo();$sql = "SELECT p.*, u.username, u.id as author_uid        FROM posts p        JOIN users u ON p.user_id = u.id        WHERE p.id = :pid";$stmt = $pdo->prepare($sql);$stmt->execute([':pid' => $id]);$post = $stmt->fetch();// 文章不存在则跳转if (!$post) {    header('Location: list_posts.php', true, 302);    exit;}// 判断当前用户是否是作者(控制编辑/删除按钮显示)$isAuthor = (!empty($_SESSION['logged_in']) && $_SESSION['user_id'] == $post['author_uid']);?><!-- HTML部分:文章标题+作者+时间+正文,作者可见编辑/删除按钮 --><div class="content">    <?= nl2br(htmlspecialchars($post['content'])) ?></div>

安全提醒:输出数据库内容到 HTML 时,仍然要用 htmlspecialchars 转义。因为用户可能在文章内容里写 <script> 标签,存进数据库再输出时就变成 XSS 攻击了。数据库存原文,输出时转义,这是标准做法。

8.5 编辑文章 edit_post.php

编辑前先校验当前用户是不是文章作者,防止越权修改别人文章:

<?phprequire 'db.php';session_start();header("X-XSS-Protection: 1; mode=block");header("X-Frame-Options: DENY");if (empty($_SESSION['logged_in'])) {    header('Location: login_db.php', true, 302);    exit;}$id = trim($_GET['id'] ?? '');$pdo = getPdo();// 查询文章并校验归属$stmt = $pdo->prepare("SELECT * FROM posts WHERE id = :pid");$stmt->execute([':pid' => $id]);$post = $stmt->fetch();// 不是作者直接跳走if (!$post || $post['user_id'] != $_SESSION['user_id']) {    header('Location: list_posts.php', true, 302);    exit;}// CSRFif (empty($_SESSION['csrf_edit'])) {    $_SESSION['csrf_edit'] = bin2hex(random_bytes(32));}$errors = [];$titleFill = $post['title'];$contentFill = $post['content'];if ($_SERVER['REQUEST_METHOD'] === 'POST') {    $token = $_POST['csrf_token'] ?? '';    if (!hash_equals($_SESSION['csrf_edit'], $token)) {        $errors[] = '非法请求';    }    $titleFill   = trim($_POST['title'] ?? '');    $contentFill = trim($_POST['content'] ?? '');    if (empty($titleFill)) $errors[] = '标题不能为空';    if (mb_strlen($titleFill) > 200) $errors[] = '标题最多200字符';    if (empty($contentFill)) $errors[] = '内容不能为空';    if (empty($errors)) {        try {            $upd = $pdo->prepare("UPDATE posts SET title=:t, content=:c WHERE id=:id");            $upd->execute([':t' => $titleFill, ':c' => $contentFill, ':id' => $id]);            header("Location: view_post.php?id=$id", true, 302);            exit;        } catch (PDOException $e) {            $errors[] = '保存修改失败';        }    }}?><!-- HTML部分:预填标题和内容的编辑表单 -->

8.6 删除文章 delete_post.php

删除走二次确认,GET 请求展示确认页,POST 请求才真正执行删除:

<?phprequire 'db.php';session_start();header("X-XSS-Protection: 1; mode=block");header("X-Frame-Options: DENY");if (empty($_SESSION['logged_in'])) {    header('Location: login_db.php', true, 302);    exit;}$id = trim($_GET['id'] ?? '');$pdo = getPdo();$stmt = $pdo->prepare("SELECT id, title, user_id FROM posts WHERE id = :pid");$stmt->execute([':pid' => $id]);$post = $stmt->fetch();// 拦截无权限/不存在if (!$post || $post['user_id'] != $_SESSION['user_id']) {    header('Location: list_posts.php', true, 302);    exit;}// CSRFif (empty($_SESSION['csrf_del'])) {    $_SESSION['csrf_del'] = bin2hex(random_bytes(32));}$err = '';if ($_SERVER['REQUEST_METHOD'] === 'POST') {    $token = $_POST['csrf_token'] ?? '';    if (!hash_equals($_SESSION['csrf_del'], $token)) {        $err = '非法操作';    } else {        try {            $del = $pdo->prepare("DELETE FROM posts WHERE id=:id");            $del->execute([':id' => $id]);            header('Location: list_posts.php', true, 302);            exit;        } catch (PDOException $e) {            $err = '删除失败,请重试';        }    }}?><!-- HTML部分:确认删除提示 + 确认/取消按钮 -->

访问 http://localhost/list_posts.php 看效果:

九、进阶:事务与分页

9.1 事务 Transaction

当一组操作必须全部成功或全部失败时(比如转账:A 扣钱、B 加钱,中间断了就完蛋),就要用事务:

<?php$pdo->beginTransaction();try {    $stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - 100 WHERE id = 1");    $stmt1->execute();    $stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + 100 WHERE id = 2");    $stmt2->execute();    $pdo->commit();  // 两步都成功,提交} catch (Exception $e) {    $pdo->rollBack();  // 任何一步失败,回滚到事务开始前    throw $e;}?>

9.2 分页查询

数据量大时一页显示不完,用 LIMIT 和 OFFSET 分页。注意 LIMIT/OFFSET 的占位符要用 bindValue 指定整数类型:

<?php$page    = max(1, (int)($_GET['page'] ?? 1));$perPage = 10;$offset  = ($page - 1) * $perPage;$stmt = $pdo->prepare("SELECT * FROM posts ORDER BY id DESC LIMIT :limit OFFSET :offset");$stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);$stmt->execute();$posts = $stmt->fetchAll();// 获取总数算总页数$totalStmt = $pdo->query("SELECT COUNT(*) FROM posts");$total     = $totalStmt->fetchColumn();$totalPages = ceil($total / $perPage);?>

9.3 SQL 注入的高级防御

• ORDER BY 和 LIMIT 后面不能用占位符,必须用白名单验证列名• IN (...) 查询需要动态生成占位符数量并逐个绑定• 数据库取出的内容输出到 HTML 前仍需 htmlspecialchars,防 XSS• 生产环境关闭 PDO 异常的详细信息输出,只记日志

十、总结

• MySQL 基础:数据库/表/行/列/主键/外键的概念,SQL 的 CREATE/INSERT/SELECT/UPDATE/DELETE• phpMyAdmin:可视化工具,建库建表看数据方便,但代码里操作数据库还是得写 SQL• PDO 连接:三个关键配置(异常模式、关联数组、关闭模拟预处理),单例模式复用连接• 预处理语句:SQL 模板 + 参数分离,从根本上防 SQL 注入,命名占位符和问号占位符二选一• 综合实战:注册登录系统数据库版(查重/哈希/自动登录),博客文章 CRUD(联查/权限校验/二次确认删除)• 进阶:事务保证操作原子性,分页用 LIMIT/OFFSET + bindValue 指定整数类型

本文基于作者实际学习与项目经验整理,代码示例均已本地测试可运行。文字整理过程中借助了 AI 工具辅助排版。

本文配套资料包

代码合集
速查手册
实战练习题
面试考点卡
公众号回复php06获取

资料下载

-END-

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 13:34:53 HTTP/2.0 GET : https://f.mffb.com.cn/a/506557.html
  2. 运行时间 : 0.495038s [ 吞吐率:2.02req/s ] 内存消耗:4,586.80kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=efa7182a27de72025acf4193d53a0f7b
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001052s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001524s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.035221s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.023986s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001706s ]
  6. SELECT * FROM `set` [ RunTime:0.010325s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001835s ]
  8. SELECT * FROM `article` WHERE `id` = 506557 LIMIT 1 [ RunTime:0.064035s ]
  9. UPDATE `article` SET `lasttime` = 1787290494 WHERE `id` = 506557 [ RunTime:0.061540s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.001018s ]
  11. SELECT * FROM `article` WHERE `id` < 506557 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.018834s ]
  12. SELECT * FROM `article` WHERE `id` > 506557 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.019551s ]
  13. SELECT * FROM `article` WHERE `id` < 506557 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.062784s ]
  14. SELECT * FROM `article` WHERE `id` < 506557 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.005740s ]
  15. SELECT * FROM `article` WHERE `id` < 506557 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.003693s ]
0.498566s