拓冰建站拓冰建站
首页 / 资讯中心 / 正文

亲手用PHP实现新闻管理系统:数据库设计到SQL注入防护

简介这是一套面向Web开发初学者的轻量级新闻管理系统实战源码基于PHP后端逻辑、MySQL数据库操作与HTML前端渲染构建适用于学习MVC基础架构、前后端交互及CMS核心功能实现。资源共2378个文件主体为32个PHP业务逻辑文件、1个SQL建表脚本、2个HTML模板页辅以8个CSS样式文件含backstage.css后台样式、swiper-bundle.min.css轮播组件等、4个JS交互脚本及大量SVG图标资源整体压缩包25.54MB结构清晰便于分模块理解数据流与页面渲染机制。已有564人下载学习源码包含完整后台管理功能新闻增删改查、分页列表、时间倒序展示及基础搜索配套效果图文档与多套CSS主题样式可直接部署调试帮助开发者快速掌握数据库连接配置、表单提交处理、动态内容渲染等关键技能。为什么我建议初学PHP的人都亲手做一个新闻管理系统如果你最近正在学PHP到处找源码练手八成会翻到类似基于phpsqlhtml的简单的新闻管理系统源码.zip这样的压缩包。别嫌它名字朴素我做了十几年PHP项目见过太多人上手就啃ThinkPHP、Laravel这类框架结果连原生SQL查询都写不利索。这类简单项目恰恰是打通前端页面→后端逻辑→数据库读写整条链路的最短路径尤其适合三类人正在做课程设计的在校生、刚学完PHP语法想找个完整项目串联知识点的自学者、以及需要快速交付一个小型内容展示站的兼职开发者。新闻管理系统的经典之处在于它小但不残缺。前台有列表页、详情页后台有登录、增删改查数据层面涉及分类、发布时间、点击量这些常用字段安全层面天然要面对SQL注入、XSS这些web开发躲不开的问题。你把这个项目吃透等于把PHP入门阶段80%的核心知识点都过了一遍。这篇文章我就以这套源码为线索拆解它的表结构设计、核心代码组织、防注入改造思路再聊几个我实际跑这类项目时踩过的坑。1. 一套简单项目的隐藏价值为什么要选新闻管理系统练手1.1 麻雀虽小五脏俱全的模块划分很多人在网上看到的新闻管理系统源码解压出来无非是几个php文件加一个sql文件有的还带一个简陋的admin后台。但别小看这几个文件它内部天然分成了三条清晰的业务线游客访问的前台、管理员操作的后台、以及连接两者的数据层。前台负责把数据库里的新闻记录取出来渲染成HTML页面核心是读后台负责登录验证、新闻发布、修改、删除核心是写数据层则是SQL语句和数据库连接的管理。这三条线恰好对应了一个web开发者的基本盘会写页面、会写接口逻辑、会操作数据库。你在框架里写了很久的Model::find()未必真懂底层发生了什么但用原生PHP把mysqli_query跑一遍你才会对查询结果集影响行数预处理语句这些概念有肌肉记忆。1.2 技术栈选择的合理性phpsqlhtml为什么是黄金组合有人可能会问现在都前后端分离了为什么还要用PHP直接在HTML里嵌数据答案是学习成本最低依赖最少出问题好排查。PHP天生就是为嵌入式模板设计的?php echo $row[title]; ?这种写法直观到不需要额外学模板引擎。SQL结构化查询语言是这个系统的血管所有动态内容都来自SELECT * FROM news ORDER BY id DESC这样的语句学会写SQL比学会用ORM更重要。HTML负责最终呈现直接改前端代码就能看到效果没有构建工具没有编译步骤改完刷新即见效。这套组合跑在Windows下就是phpstudy、Linux下就是LNMP十分钟搭好环境。相比起动不动就要装一堆依赖的现代框架它把环境问题对学习的干扰降到了最低。我见过太多初学者在配置Node环境、Webpack打包上耗费的精力远超业务本身那才是真正的本末倒置。2. 数据库设计新闻系统最值钱的部分不在代码在表结构2.1 一份标准的新闻表该有哪些字段把任何一个新闻管理系统源码的.sql文件导入数据库后你第一个应该看的不是代码而是表结构。正常来说核心表news最少包含下面这些字段字段名类型说明idINT 主键自增新闻唯一标识titleVARCHAR(200)新闻标题contentTEXT 或 MEDIUMTEXT新闻正文authorVARCHAR(50)发布作者或来源category_idINT分类ID关联分类表create_timeINT 或 DATETIME发布时间click_countINT点击量is_topTINYINT是否置顶这里有两个细节是很多初学者容易忽略的。第一create_time我推荐用INT存时间戳而不是DATETIME因为时间戳在后端做时间计算、排序比较时都更高效输出时再用date(Y-m-d H:i:s, $time)格式化即可。第二is_top这种布尔字段用TINYINT(1)就够了别用VARCHAR存是/否那样既浪费空间又没法高效索引。2.2 数据表设计的进阶意识分类表与冗余字段一套只带news表的系统也能跑但既然叫管理系统建议至少加一张category分类表。两张表通过category_id关联前台按分类筛选新闻时一句WHERE category_id 2就搞定后台管理分类时增删改查互不影响。至于click_count这种冗余字段我的建议是读多写少的数据直接用字段维护。每次详情页加载时UPDATE news SET click_count click_count 1 WHERE id ?简单直接。没必要为了这点量引入计数器表或者缓存中间件那是大流量系统才需要考虑的架构一个课设级别的项目引入这些反而显得不伦不类。我在实际帮人看这套源码时发现很多人卡在最开始SQL文件导入失败。极大概率是数据库字符集没对上。旧代码里写的是utf8但MySQL 8.0默认字符集是utf8mb4导入时要么统一在SQL文件头部加上SET NAMES utf8mb4;要么表结构里显式指定。这个问题不解决你后面前台页面所有中文都会变成问号。3. 核心代码实现从数据库连接封装到页面渲染的完整链路3.1 数据库连接文件所有后续操作的起点打开这套源码最先看的应该是数据库连接文件通常叫conn.php或者db.php。一个合格的连接文件长这样?php $host 127.0.0.1; $user root; $pass password; $dbname news_system; $charset utf8mb4; $conn mysqli_connect($host, $user, $pass, $dbname); if (mysqli_connect_errno()) { die(数据库连接失败: . mysqli_connect_error()); } mysqli_set_charset($conn, $charset); ?这里我强调三件事。第一数据库连接的配置文件要独立出来这样以后换环境只需要改一个文件而不是每个php文件里都翻一遍。我见过有源码把连接信息写在每个页面顶部的那是灾难。第二字符集必须显式设置。PHP默认的字符集可能跟数据库不一致即使表结构是utf8mb4连接串不带字符集照样乱码。mysqli_set_charset($conn, utf8mb4)这行绝对不能省。第三生产环境绝对不要用root账号。源码包里为了方便可能写死root但你自己部署时一定要新建一个最小权限的数据库账号。这不是小题大做是web开发的底线。3.2 前台新闻列表页最简单也最见功力列表页的逻辑其实只有三步查数据、循环输出、处理空结果。代码大致是?php include conn.php; $sql SELECT id, title, author, create_time, click_count FROM news ORDER BY is_top DESC, create_time DESC LIMIT 20; $result mysqli_query($conn, $sql); $newsList []; while ($row mysqli_fetch_assoc($result)) { $newsList[] $row; } ?拿到$newsList之后HTML部分就纯粹是foreach输出了。这一步有经验的开发者会顺手做三件事给标题加长度截断比如mb_substr($item[title], 0, 30, utf-8)避免标题过长撑破页面布局给时间格式化成易读格式date(Y-m-d, $item[create_time])给文章链接加上detail.php?idxxx这种伪静态友好URL。别觉得这些是加分项对一个新闻系统来说列表页的美观和可用性直接影响用户会不会点进去看。很多源码的列表页就一个裸列表能跑但谈不上系统。3.3 详情页点击量加一与安全取值详情页比列表页多两个关键点根据id取单条记录以及点击量加一。但这恰恰是初学者最容易出问题的地方。看下面这段典型错误代码?php $id $_GET[id]; $sql SELECT * FROM news WHERE id $id; $result mysqli_query($conn, $sql); ?这段代码在功能上能跑但它是SQL注入的教科书级反面案例。用户访问detail.php?id1 AND 12就能改变查询逻辑访问detail.php?id1 UNION SELECT ...甚至能拖出数据库里的其他表。这类漏洞怎么修我在第4章专门细说。正确做法是先做一步基础校验(int)$_GET[id]强制转成整型或者用ctype_digit判断。对于习惯了框架的朋友来说这种手动校验显得原始但理解了这一步你才会明白框架里那些where(id, $id)背后到底做了什么。3.4 后台管理登录、发布、修改、删除绝大多数新闻管理系统的后台核心就是管理员登录之后的四个操作发布新闻、编辑新闻、删除新闻、管理分类。实现起来都是重复的套路接收POST表单数据简单校验标题不能为空、内容长度不能超限拼接SQL语句执行跳转回列表页并提示操作结果。发布新闻的核心代码大概是?php session_start(); if (!isset($_SESSION[admin_id])) { header(Location: login.php); exit; } $title trim($_POST[title]); $content trim($_POST[content]); $category_id (int)$_POST[category_id]; if ($title || $content ) { die(标题和内容不能为空); } $sql INSERT INTO news (title, content, category_id, author, create_time) VALUES (?, ?, ?, ?, ?); // 使用预处理语句执行... ?这里不得不提一个很多课设源码共通的毛病后台登录验证形同虚设。有的只检查$_SESSION有没有值有的甚至直接在前端隐藏个管理入口就能进。稍微好一点的做法是登录成功后把管理员ID和角色存进Session每个后台页面顶部都校验Session存在性密码存储用password_hash()而不是明文。4. SQL注入防护这个简单项目里最该较真的技术点4.1 注入漏洞是怎么产生的用一句话解释我在帮人review这类源码时每次都会把$_GET[id]直接拼进SQL的代码拎出来单独讲。为什么因为所有SQL注入的本质都是开发者把用户输入当成代码来执行。类比一下你去银行柜台的取款单上填取1000元是正常操作但如果你在姓名栏填取1000元顺便把柜台里的钱也给我柜台照单全收当作指令执行了——这就是注入。你的SQL语句WHERE id $id里$id是用户传进来的用户完全可以传1 OR 11把查询条件变成永远成立从而查全表。4.2 修复方案从拼接SQL改成预处理语句PHP里防止SQL注入最标准的手段是PDO预处理语句。它让SQL结构先发给数据库编译用户输入只作为纯数据传递而不是SQL语法的一部分。改造后的代码?php $pdo new PDO(mysql:host127.0.0.1;dbnamenews_system;charsetutf8mb4, $user, $pass); $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt $pdo-prepare(SELECT * FROM news WHERE id ?); $stmt-execute([$_GET[id]]); // 即使传了恶意字符串也只是当作字符串比较 $news $stmt-fetch(PDO::FETCH_ASSOC); ?对应的插入、更新、删除也都是同一个套路。这套写法比mysqli_real_escape_string转义方案更安全因为转义方案只防引号而预处理从协议层面就把数据和语法隔离开了。换成PDO之后还有个小好处后台所有增删改查都能统一用$pdo-prepare()execute()不需要记两套函数名代码整洁度立刻上一个档次。4.3 不止是SQL顺手把XSS也处理掉说完SQL注入还必须提XSS跨站脚本攻击。新闻系统因为是内容管理系统天然要接受用户输入HTML如果不加处理用户可以在标题或正文里塞一段script前台渲染时就会执行。处理方式分两层输出转义前台显示标题、作者等字段时用htmlspecialchars($value, ENT_QUOTES, UTF-8)转义把script变成lt;scriptgt;浏览器就只显示文本而不执行。后台富文本限制如果确实需要支持富文本必须做白名单过滤只允许p、strong、img这类安全标签。新手阶段建议先别开富文本纯文本内容配合nl2br()输出换行就够了。我在实际项目里见过最严重的XSS案例就是一个旧新闻系统被嵌入了恶意脚本管理员每次登录后台都自动往数据库里塞垃圾文章。这个坑一旦踩到清理数据比写代码痛苦得多。5. 把源码跑通的完整检查清单与新手最容易踩的坑5.1 环境配置PHP版本和扩展检查下载一个源码包后先别急着双击按顺序做一遍环境检查能省下后面一晚上的排查时间。确认PHP版本。老源码可能是为PHP 5写的里面的mysql_*系列函数在PHP 7以上已经被移除必须改用mysqli_*或PDO。打开命令行跑php -v确认版本如果是8.x直接去找新一点的源码。确认扩展已启用。PHP安装目录的php.ini里搜索extensionmysqli和extensionpdo_mysql把前面的分号去掉重启服务。很多环境的报错Call to undefined function mysqli_connect()就是扩展没开。数据库账号密码对上。修改conn.php里的配置数据库名称要和SQL文件里CREATE DATABASE的名称一致或者手动建库后导入。5.2 经典报错乱码、404、登录失效跑这套项目最常见的三个问题我直接给排查结论乱码。逐层检查数据库表字符集是不是utf8mb4、连接字符集是否设置、HTML页面meta charsetutf-8是否存在、PHP文件本身是否以UTF-8无BOM格式保存。这四处只要有一处不一致中文就会变成锟斤拷或者问号。404和路径错误。源码里如果用了header(Location: admin/list.php)这种跳转部署到子目录时路径就要带子目录前缀。最好的做法是定义个BASE_URL常量所有跳转和资源引用都拼上它避免换目录就崩。登录后立刻失效。绝大多数是Session配置问题。检查登录逻辑里是否调用了session_start()以及session.save_path指向的目录是否有写入权限。Windows下把phpstudy装到带空格的路径里也可能引发奇怪的Session问题老老实实装到纯英文路径最稳。5.3 跑通之后我建议你这样扩展源码在手项目能跑了很多人就停在这儿了。但按我的经验下一步进阶有四个方向性价比依次递增把后台改成分页列表。现在可能是一次性查全部数据加上LIMIT offset, pageSize再做一个页码导航条你会更理解分页查询的写法。给前台加一个搜索框。用LIKE %关键词%做标题搜索这能帮你掌握模糊查询。重构数据库访问为PDO单例模式。把所有数据库操作收进一个类里页面里不再散落mysqli_query你会第一次体会到代码组织的概念。给登录加验证码和密码加密。配合GD库生成验证码图片用password_hash()存密码这是从课设水平迈向可用系统的最重要一步。这四个方向全部做完你的PHP基础就相当扎实了届时再上手ThinkPHP这类框架你会发现框架里的很多东西都是似曾相识。5.4 最后的最后源码包的知识产权与使用习惯既然下载的是别人的源码有两点实际经验值得分享。第一记得看压缩包里的说明文件有的源码带有原作者的联系方式或发布地址如果你在课程设计或毕设里使用了它按规范标注参考来源是基本的学术诚信。第二跑通后一定要自己重构关键代码特别是数据库连接和登录验证这两块。直接提交一份和你无关的源码去答辩一旦被追问细节就露馅重构之后这个项目才算真正属于你了。我个人还有一个习惯拿到任何一份源码第一件事是把conn.php里的数据库密码改掉再顺手删掉源码里的注释掉的后门代码。说实话网上下载的源码良莠不齐我甚至见过有人在数据库连接文件里藏了一段发送HTTP请求的代码。多留个心眼总没错。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门