# pycms **Repository Path**: mo3408/pycms ## Basic Information - **Project Name**: pycms - **Description**: 盘云CMS 是一款采用 「核心 + 插件 + 主题」 架构的轻量内容管理系统。内核只负责后台管理、权限、用户、内容与系统设置,前台模板和业务能力通过主题包、插件包独立扩展;内置 Web 安装向导与远程应用市场,可在线安装/升级插件、主题和核心。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: http://pycms.snowytime.cn - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-11-14 - **Last Updated**: 2026-11-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: PHP, 自研, 轻量, 建站 ## README # 盘云CMS(pycms) 盘云CMS 是一款采用 **「核心 + 插件 + 主题」** 架构的轻量内容管理系统。内核只负责后台管理、权限、用户、内容与系统设置,前台模板和业务能力通过主题包、插件包独立扩展;内置 Web 安装向导与远程应用市场,可在线安装/升级插件、主题和核心。 - 英文名称:pycms - 中文名称:盘云CMS - 当前版本:1.0.2 - 技术栈:原生 PHP 8.x + MySQL 5.7/8.0,无 Composer 依赖 - 运行方式:nginx / Apache + PHP-FPM 或 PHP-CGI ## 功能一览 | 模块 | 能力 | | --- | --- | | 安装向导 | 环境检测 → 数据库测试 → 管理员/站点 → 一键安装,自动建库建表、写入演示数据并生成 `config/install.lock` | | 后台 UI | 自研现代 UI、iframe 多标签工作区、响应式侧栏、动态菜单、顶栏站点开关 | | 权限 | 角色权限勾选、超级管理员 `["*"]`、菜单按权限自动隐藏、403 拦截 | | 内容 | 文章、分类(树形)、文档属性(置顶/推荐/热门/头条)、标签、SEO、上下架、搜索、浏览量 | | 模型 | 内容模型与字段定义管理,内置文本、富文本、数字、日期、下拉、单选、多选、图片、文件、开关、颜色等 13 种字段类型 | | 用户 | 后台账号、角色分配、启停、登录记录 | | 系统 | 站点配置、动态/伪静态 URL 规则(各 5 种内置风格 + 自定义)、验证码、上传、文件管理、操作日志、站点一键关闭 | | 留言 | 内置表单模型留言板,前台 `{pycms:guestbookform /}` 调用,后台来源栏目与图形验证码开关 | | 语言 | 前台 / 后台独立语言包,后台全部界面文案支持 `py_t()` 翻译与中英文切换 | | 扩展 | `plugins/` 与 `themes/` 双目录、Hook、插件路由、插件后台菜单、插件启停/卸载 | | 应用市场 | 远程清单、插件/主题在线安装与升级、核心在线升级,升级前自动备份 | | 安全 | PDO 预处理、CSRF、HTML 白名单净化、验证码、上传类型/大小限制、路径白名单、操作留痕 | ## 环境要求 - PHP 8.0 – 8.5,扩展:`pdo_mysql`、`mbstring`、`gd`、`zip`、`curl`、`fileinfo`、`openssl` - MySQL 5.7 或 8.0 - Web 服务器:nginx 或 Apache(需支持 URL 重写 / PATH_INFO) - 可写目录:`config/`、`storage/`、`uploads/`(安装时需创建 `config/database.php` 与 `config/install.lock`) ## 安装 1. 将项目上传到站点根目录,确认上述目录可写。 2. 浏览器访问 `/install/index.php`,按四步向导操作: - 环境检测:检查 PHP 版本、扩展与目录权限; - 数据库配置:填写主机、端口、账号、密码、库名与表前缀,可先「测试连接」; - 管理员创建:设置管理员账号、密码、昵称与站点名称,可选安装演示数据; - 一键安装:自动创建数据库/表、写入角色/菜单/配置/演示文章,并锁定安装。 3. 安装完成后访问 `/admin/login` 登录后台;建议立即删除 `install/` 目录并修改管理员密码。 > 数据库默认:库名 `pycms`,表前缀 `py_`,字符集 `utf8mb4`。 ## Web 服务器配置 ### nginx 参考 `docs/nginx.conf.example`。关键点: - `try_files $uri $uri/ /index.php?$query_string;` 让 `/list/news`、`/show/1.html` 进入内核路由; - PHP location 使用 `fastcgi_split_path_info` 并传递 `PATH_INFO`; - 禁止直接访问 `config/`、`core/`、`app/`、`storage/`、`docs/` 以及 `themes|uploads` 下的 PHP 文件。 ### Apache 根目录已提供 `.htaccess`: - 开启 `mod_rewrite`,所有非静态请求重写到 `index.php`; - 禁止目录列表与敏感目录直接访问; - 若站点在子目录,请把 `RewriteBase /` 改为对应子目录。 ## 目录结构 ``` cms/ ├── app/ │ ├── admin/ 后台控制器与视图(controller/、view/) │ └── home/ 前台控制器(主题渲染) ├── assets/admin/ 后台自研 UI 的 CSS/JS/图标 ├── config/ config.php、database.php(安装生成)、install.lock ├── core/ 内核:App/Router/Db/View/Auth/Menu/Market/Upgrader 等 ├── install/ Web 安装向导 ├── plugins/ 插件目录(每个插件一个子目录) ├── themes/ 主题目录(default、aurora、magazine…) ├── storage/ cache、logs、backups、market 清单与安装包 ├── uploads/ 上传附件 ├── docs/ 部署示例与开发文档 ├── index.php 统一入口 └── .htaccess Apache 重写与安全规则 ``` ## 路由约定 | 路由 | 说明 | | --- | --- | | `/` | 首页 | | `/list/{slug}` | 分类列表 | | `/show/{id}.html` | 文章详情 | | `/search?keyword=...` | 搜索 | | `/tag/{tag}` | 标签聚合 | | `/admin/{controller}/{action}` | 后台模块 | | `/admin/plugin/{code}/{method}` | 插件后台路由 | | `/market/api/list` | 应用市场清单接口 | | `/market/download/{zip}` | 应用市场安装包下载 | ## 插件开发 一个插件目录示例: ``` plugins/demo/ ├── info.ini 插件信息(必须) ├── Demo.php 入口类(必须,首字母大写) ├── controller/ 插件控制器 ├── view/ 插件视图(view/{控制器}/{方法}.html) ├── taglib/ 自定义标签 ├── route.php 前台路由 ├── config.php 插件配置 ├── install.sql 安装 SQL └── install/ 安装时部署的附加文件 ├── app/ → 项目 app/ ├── template/ → 项目 themes/ ├── static/ → 项目 assets/ └── public/ ├── static/ → 项目 assets/ └── 其它文件 → 项目 public/ ``` 插件安装、导入与升级时,会按上表把 `install/` 内容写入 CMS 现有目录;目标子目录不存在时会自动创建,不再使用不存在的 `template/` 或根级 `public/static/`。 `info.ini`: ```ini name = "demo" type = "addon" title = "示例插件" description = "插件说明" author = "your-name" version = "1.0.0" status = 1 ``` `Demo.php`: ```php '示例插件', 'name' => 'demo/index', 'icon' => 'puzzle', 'weigh' => 60], ]; public function register(): bool { Hook::add('front.footer', function () { return '