
简介一份PHP留言板项目源码配套MySQL数据库文件面向正在学习PHP与Web开发的初学者或需要快速搭建互动留言模块的开发者。压缩包共131个文件包含49个PHP脚本、16个CSS样式、16个JavaScript脚本及Bootstrap前端组件另有SQL建库脚本、字体图标文件和对应的map映射文件整体仅746KB便于本地部署和二次修改。核心学习价值在于完整呈现留言板从数据库设计到前端交互的实现链路connect.php与config.php演示数据库连接与配置login.php和register.php覆盖用户认证与会话管理add.php展示表单提交、数据校验和防SQL注入处理messages表结构清晰方便对照学习同时还能看到XSS、CSRF防护思路、错误处理与日志记录等安全实践。对于希望深入理解PHPMySQL经典开发模式的开发者这套源码提供了可直接运行的样例包含用户登录注册、留言增删、分页展示等常见功能模块适合以此为基础扩展成更完整的Web应用。目前已有1670人学习值得作为入门实践项目边阅读边调试逐步掌握Web开发的完整链路和常见安全策略。1. 拆一份 PHP 留言板源码它到底能帮你解决什么问题留言板这类 PHP MySQL 的经典组合几乎是每个做 Web 的人迟早要碰一遍的东西。这份资源不是花架子就是一份能跑起来的 PHP 留言板源码外加一个建表用的 MySQL 数据库文件。你下载之后要面对的核心问题很简单把 sql 导进数据库改好连接参数页面就能提交留言、展示留言。它适合拿来练手、改造成自己的第一个交互式应用也适合新手用来理解 PHP 是怎么和 MySQL 配合的。别小看这份老代码留言板虽然功能少但表单提交、入库、列表查询、分页、字符集这些坑一个都不少踩一遍比看十遍教程都管用。2. 环境与数据导入PHP 版本、MySQL 5.7/8.0 和 sql 文件的正确打开方式2.1 PHP 版本选择先看代码调了哪些函数再决定用 7.4 还是 8.x很多人在这一步翻车。下载源码后不先看代码直接装最新版 PHP 8.3然后打开页面就是一片 Fatal error。原因很简单PHP 8 移除了mysql_*那一整组老函数如果你手上的留言板源码还在用mysql_connect()那只会在 PHP 7.4 及以下版本里正常跑。我拿到任何一份老 PHP 源码第一件事是打开根目录的 PHP 文件全局搜索mysql_这个前缀。搜出来的是mysql_connect、mysql_query开头的写法那就老老实实用 PHP 7.4搜出来是mysqli_或者PDO那 PHP 8.x 基本没压力。这份资源里的留言板多数实现会用mysqli扩展但你也可能碰到历史版本用了老 API不能靠猜。环境选择上本地练手我一般直接上 XAMPP 或者 phpStudy它们把 Apache、PHP、MySQL 打包在一起版本可以切换。如果你是拿这份源码做课程设计或者交给别人部署建议统一用 PHP 7.4 MySQL 5.7这是老 PHP 代码兼容性最稳的组合。MySQL 8.0 也能跑但要注意 8.0 默认的密码认证插件改成了caching_sha2_password后面第四章会细说这个坑。版本对应关系可以参考下面这张表源码中的数据库扩展推荐 PHP 版本备注mysql_*老函数PHP 5.6 / 7.0PHP 7.0 以上已弃用8.0 直接移除不推荐硬跑mysqli_*PHP 7.4 / 8.x最常见这份资源大概率是这个写法PDOPHP 7.4 / 8.x新代码主流安全性最好提示如果页面打开直接白屏或者抛错先把php.ini里的display_errors打开错误信息会告诉你到底死在哪个函数上这是排查这类问题最快的一条路。2.2 建库建表导入 sql 前先花两分钟把表结构和字符集读明白sql 是这份资源里最有价值的部分。它不只包含CREATE TABLE通常还带着CREATE DATABASE、USE语句和几条示例数据。很多人拿到手就往 phpMyAdmin 里点导入然后看到「成功」就以为完事了实际上表名、字段名、字符集都没看后面写代码时连nickname还是name都对不上。我的习惯是双击打开 sql 文件用编辑器看一遍。重点看三处一是表名是什么二是主键和字段类型三是ENGINE和DEFAULT CHARSET。留言板核心表长这样字段名可能略有差异但结构八九不离十CREATE TABLE messages ( id int(11) NOT NULL AUTO_INCREMENT, nickname varchar(50) NOT NULL DEFAULT , content text NOT NULL, create_time datetime NOT NULL, PRIMARY KEY (id), KEY idx_create_time (create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;AUTO_INCREMENT让 id 自增不需要手动维护nickname用varchar(50)控制长度content用text是因为留言内容长短不可控varchar(255)可能不够用create_time用datetime而不是时间戳排序和展示都更直观。CHARSETutf8mb4是重中之重utf8mb4 才是真正完整的 UTF-8 支持能存 emoji也能避免中文乱码。导入方式有两种选一个就行。第一种用 phpMyAdmin先新建一个空数据库名字随意比如message_board然后选中它点「导入」选择 sql 文件执行。第二种用命令行适合你已经在用终端工作流的情况mysql -u root -p message_board message_board.sql-u root指定用户-p提示输入密码message_board是目标数据库名把文件内容重定向给 mysql 命令执行。如果一个 sql 文件里本身带了CREATE DATABASE message_board你也可以先不进库直接全量导入但我更倾向于拆开只导表避免数据库重名的尴尬。2.3 连库配置文件四行参数改完就能跑留言板源码里几乎必然有一个数据库连接文件名字可能是db.php、conn.php或者config.php。打开它核心就四行配置。你把上一节建好的库名、用户名、密码填进去应用就能连上数据库?php $host localhost; // 数据库地址XAMPP 默认 localhost $user root; // 数据库用户名本地环境默认 root $pass ; // 数据库密码XAMPP 默认空phpStudy 默认 root $dbname message_board; // 库名和导入 sql 时用的库保持一致 $conn new mysqli($host, $user, $pass, $dbname); $conn-set_charset(utf8mb4); if ($conn-connect_error) { die(数据库连接失败: . $conn-connect_error); }new mysqli()四个参数依次是地址、用户名、密码、库名顺序别记反很多人把用户名和密码写反了就开始怀疑人生。set_charset(utf8mb4)这行是防中文乱码的关键PHP 连接 MySQL 时的字符集和建表字符集必须一致否则入库的数据看着是好的查出来就是一遍乱码。改完这份配置文件后先别急着直接访问首页。单独写一个test.php内容只有一行?php require db.php; echo ok;浏览器访问一下能输出ok说明数据库连接这条路通了。这一步能帮你把问题和后面的代码逻辑隔离开。3. 留言板核心逻辑写留言、读留言、渲染列表的完整拆解3.1 写留言入库为什么我建议你用预处理而不是直接拼 SQL留言板的「写」操作本质上就三步接收用户提交的nickname和content写入数据库然后跳回列表页。很多老源码在这里直接做了字符串拼接比如INSERT INTO messages (nickname, content) VALUES ( . $_POST[name] . , . $_POST[content] . )。这种写法短平快但有一个致命问题只要用户在留言内容里输入一个单引号SQL 语句的语法就被破坏轻则报错重则被塞进一段恶意 SQL这就是典型的 SQL 注入。我建议你把写留言的代码改成预处理语句改动量不大安全性完全不一样?php require db.php; if ($_SERVER[REQUEST_METHOD] POST) { $nickname trim($_POST[nickname] ?? ); $content trim($_POST[content] ?? ); if ($nickname || $content ) { die(昵称和留言内容都不能为空); } $stmt $conn-prepare(INSERT INTO messages (nickname, content, create_time) VALUES (?, ?, NOW())); $stmt-bind_param(ss, $nickname, $content); $stmt-execute(); header(Location: index.php); exit; } ?$conn-prepare()把 SQL 结构提前发给 MySQL 服务器?是占位符bind_param(ss, ...)里的s表示参数类型是字符串两个s对应两个占位符。用户输入无论包含什么特殊字符都会被当作纯文本处理不会改变 SQL 语义。create_time直接用 MySQL 的NOW()生成省去了 PHP 端格式化时间的步骤时区问题也留给数据库统一处理。$_POST[nickname] ?? 是 PHP 7 以上才有的语法作用是当这个键不存在时返回空字符串避免提交表单缺字段时直接抛未定义索引警告。如果你要跑在老 PHP 5.x 上需要换成isset($_POST[nickname]) ? $_POST[nickname] : 。3.2 列表页读取与渲染HTML 混排和纯 PHP 输出怎么选留言板的「读」比「写」复杂一档因为它涉及循环输出和 HTML 混排。主流的写法有两种一种是把 PHP 标签直接嵌进 HTML 模板里另一种是用 PHP 拼接字符串然后统一echo。新手更推荐前者结构清楚改样式方便。列表页核心代码长这样?php require db.php; $result $conn-query(SELECT id, nickname, content, create_time FROM messages ORDER BY id DESC); while ($row $result-fetch_assoc()) { $nickname htmlspecialchars($row[nickname], ENT_QUOTES, UTF-8); $content htmlspecialchars($row[content], ENT_QUOTES, UTF-8); ? div classmessage span classname?php echo $nickname; ?/span span classtime?php echo $row[create_time]; ?/span p classtext?php echo nl2br($content); ?/p /div ?php } ?$conn-query()适合这种没有用户输入参与查询的固定 SQL不需要预处理。ORDER BY id DESC让最新留言排在最前面符合留言板的阅读习惯。fetch_assoc()每次取一行返回关联数组字段名就是表的列名循环到没有数据为止。这里最关键的是htmlspecialchars()。用户提交的内容里如果带有script标签直接原样输出这段脚本会在其他访客的浏览器里执行也就是 XSS 攻击。htmlspecialchars把转成lt;转成gt;脚本就变成了纯文本。ENT_QUOTES让单引号双引号都转义UTF-8告诉函数按 UTF-8 处理字符这两个参数很容易漏写漏了在某些特殊字符下会出乱码或者转义不完全。nl2br()把用户输入里的换行转成br否则用户按回车换的行在 HTML 里会挤成一行。少数的老源码没有这一步留言内容密密麻麻一团体验很差。4. 常见问题与避坑排查这份留言板最容易翻车的五个现场现象 1导入 sql 后页面和数据库里中文全部变成???或者乱码。原因建表语句里的字符集是latin1或者db.php里少了set_charset(utf8mb4)。我遇到过一份 sql 文件建表时只写了DEFAULT CHARSETutf8表面看没问题但utf8在 MySQL 里是utf8mb3的别名不支持四字节字符部分中文和 emoji 入库就变成问号。解决打开 sql 文件把CHARSETutf8全局替换成CHARSETutf8mb4重新导入然后确认 PHP 连接也设置了 utf8mb4。记住一个原则库、表、连接三处字符集必须统一。现象 2打开页面直接白屏或者报Fatal error: Uncaught Error: Call to undefined function mysql_connect()。原因源码用的是 PHP 5 时代的mysql_*函数你装的是 PHP 7.4 以上这个函数已经被移除了。解决先全局搜索确认是不是这种情况。如果是mysqli_connect那就是另一个问题——php.ini里extensionmysqli没启用。Windows 上用的 XAMPP打开php.ini把这行前面的分号去掉如果是新代码用了mysqli类的写法确认类是原生存在的。PHP 8 下没有mysqli类通常是因为环境没配好而不是代码错了。现象 3数据库密码明明是 root但页面一直提示Access denied for user rootlocalhost。原因MySQL 8.0 默认用caching_sha2_password密码认证老版本的 PHP mysqli 驱动默认只认mysql_native_password两边握手失败。解决最省事的方式是把 MySQL 用户认证插件改回老格式执行以下 SQL 命令ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;如果你用的是 phpStudy 这类集成环境注意区分它内置 MySQL 的端口。很多时候端口是 3306 而不是默认的 3306连接配置里的$host要写成127.0.0.1:3307这种格式否则connect_error报的是无法连接而不是密码错。现象 4留言提交后页面变成下载文件或者直接显示 PHP 源码。原因Apache 没有正确解析 PHP 文件PHP 模块没加载。这个问题几乎和代码无关纯环境问题。解决在项目根目录放一个info.php里面写?php phpinfo(); ?浏览器访问如果能看到 PHP 信息页说明解析正常如果还是下载或显示源码检查 Apache 的httpd.conf里有没有加载 PHP 模块或者.htaccess里加了奇怪的AddType配置。卸载重装环境的事我干过不止一次后来学乖了先看info.php再决定动不动环境。现象 5用户留言里带了img标签页面排版直接崩掉。原因输出时没有做htmlspecialchars()转义HTML 标签被浏览器当成了真实标签解析。这个比有人想象中严重得多不只是个表情图片的事完全可以塞入script或者iframe挂马。解决回头检查列表页的输出代码所有从数据库取出来的用户内容一律经过htmlspecialchars($value, ENT_QUOTES, UTF-8)再输出。这个函数是留言板的最后一道防线每次改模板都要记得带上。5. 进阶技巧分页与基础校验把留言板改成能拿得出手的版本5.1 分页参数的计算LIMIT 别写死留言多了以后一个页面全部渲染出来数据库压力和白屏风险都上来了。分页的数学很简单但细节决定体验。每页显示条数建议提取成变量方便后续调整?php $perPage 10; $page isset($_GET[page]) ? max(1, (int)$_GET[page]) : 1; $totalSql SELECT COUNT(*) AS cnt FROM messages; $totalResult $conn-query($totalSql); $totalCount $totalResult-fetch_assoc()[cnt]; $totalPages max(1, (int)ceil($totalCount / $perPage)); $page min($page, $totalPages); $offset ($page - 1) * $perPage; $result $conn-query(SELECT nickname, content, create_time FROM messages ORDER BY id DESC LIMIT $perPage OFFSET $offset); while ($row $result-fetch_assoc()) { // 渲染逻辑与之前一致 } ?max(1, (int)$_GET[page])防止负数页码min($page, $totalPages)防止用户手输一个超出范围的页码把数据库查空。OFFSET是跳过的行数LIMIT是取多少行LIMIT 10 OFFSET 20表示跳过前面 20 条取第 21 到 30 条。这里有个新手容易犯的错把$perPage直接写进 SQL 字符串没有问题但如果哪天改成从用户输入取$perPage那就必须强制转成整数否则又是注入点。5.2 提交校验后端比前端更值得信任很多留言板源码只在前端写了required后端收到数据直接就入库了。这个做法在本地练手没问题但你要认清一个现实前端的限制随时可以被绕过真正可靠的校验必须放在 PHP 端。除了前面代码里的空值判断建议再加两个约束留言长度限制和提交频率限制。if (mb_strlen($content) 500) { die(留言内容不能超过 500 字); } if (isset($_SESSION[last_post]) time() - $_SESSION[last_post] 10) { die(留言太频繁请稍后再试); } $_SESSION[last_post] time();mb_strlen是按字符数统计的如果你用strlen一个中文字符在 UTF-8 下占 3 字节500 字的中文会被误判成 1500 的长度所以多字节字符必须用mb_系列函数。频率限制是防止有人拿着脚本刷留言板简单的 session 时间戳就能挡住大部分情况。这两处加上之后这份源码的可用性基本到了可以直接拿去做课设或者个人站点的程度。做这套改造的时候我又踩了一次老代码的坑第一次只加了前端maxlength想着后端反正有 js 限制结果用 Postman 一测5000 字的长文本照样进了库整个列表页排版直接崩了。从那以后我每次接手这类 PHP 老源码都强制先做四件事打开错误显示、读建表语句、核对字符集、用脚本把每个输入字段都灌一次超长数据。前三件事帮我定位环境问题第四件事帮我看清代码的真实底线。这四步下来留言板能不能跑、能扛住多恶劣的输入基本心里有数了。希望帮到你。本文还有配套的精品资源点击获取