别从零写cms,因“简单”常跳过权限隔离、输入过滤等安全基础,易致服务器被上传shell;应优先用现成系统配置,若必须动手,仅做增删改查+模板分离,用sqlite、pdo预处理、原生php模板,并将数据库移出webroot、禁用uploads目录php执行。

别写——至少别从零开始写一个 CMS。
为什么「简单 CMS」在 PHP 里反而最危险
所谓“简单”,往往意味着跳过权限隔离、输入过滤、CSRF 防护、SQL 注入防御这些基础环节。你写的 index.php 可能三天后就被上传一个 shell.php 到服务器根目录。
真实场景中,95% 的“自己写 CMS”需求,其实是:需要快速改几个页面、加个表单、换下 banner —— 这些用现成系统配一配就能搞定,而不是重造轮子。
常见错误现象:mysqli_query($conn, "SELECT * FROM posts WHERE id = $_GET['id']") 这类代码一出现,系统就已经不算“简单”,而是“裸奔”了。
如果非得动手,只做三件事就够了
用最轻量方式满足“增删改查+模板分离”,不碰后台权限、不写路由分发、不搞插件机制。
- 用
SQLite替代 MySQL:免配置,数据库就是单个data.db文件,chmod 600 data.db就能防直接下载 - 所有数据操作封装进一个
Post::find()、Post::save()类,里面强制用sqlite_escape_string()或 PDO 预处理(哪怕只有一处 SQL) - 模板只用原生 PHP:
include 'templates/post.php';,禁止在模板里写$_POST或eval()
示例(安全底线):
// post.php
$id = (int)$_GET['id'] ?? 0;
$stmt = $pdo->prepare("SELECT * FROM posts WHERE id = ?");
$stmt->execute([$id]);
$post = $stmt->fetch();
比写代码更关键的两步
很多开发者花十小时写列表页,却忽略部署时两个硬性动作:
- 把
data.db放到webroot外(比如和index.php同级的../storage/data.db),确保 HTTP 无法直连 - 在
.htaccess或 Nginx 配置里禁掉php在uploads/目录的执行权限:deny from all+<files> Order Allow,Deny </files>
没有这两步,哪怕你用了 Laravel 的 Eloquent,上传一个 .php 文件照样 getshell。
真正卡住人的从来不是“怎么写”,而是“怎么不让它被当跳板”。CMS 的复杂度不在功能,在边界控制——而边界,是配置出来的,不是代码写出来的。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











