一套基于 ThinkPHP 后端 + Uniapp 前端的轻量知识付费系统技术解析与部署指南,适用于课程售卖、会员订阅、音频图文专栏、直播回放、分销裂变等场景。
源码:zx.xcxyms.top
一、项目定位:为什么选 ThinkPHP + Uniapp
知识付费系统的本质不是“做个商城”,而是把内容资源和访问权限绑定起来:用户付钱 → 订单状态变更 → 服务端开通课程权限 → 前端按权限拉取视频/音频/图文。
选 ThinkPHP 做后端,是因为它在国内中小型商业项目里生态成熟,自带路由、验证器、中间件、ORM、缓存、命令行任务,适合快速交付。
选 Uniapp 做前端,是因为课程列表、课程详情、订单中心、个人中心这些页面在微信小程序、H5、App 上结构高度一致,一套 Vue 代码编译多端能省掉大量重复开发。
典型适用对象:
- 个人博主 / 自媒体:卖专栏、卖音频课
- 培训机构:录播课 + 直播回放 + 题库
- 社群变现:会员卡 + 分销海报
- 资源站:文档、网盘资料、卡密兑换
二、整体系统架构
采用前后端分离结构,后端只负责三件事:鉴权、内容输出、订单与支付状态流转;前端负责页面渲染与接口调用。
┌──────────────┐ │ 微信小程序端 │ │ H5 网页端 │─── JSON API ───▶ ThinkPHP 接口层 │ App(可选) │ ├─ 用户/会员/权限 └──────────────┘ ├─ 课程/章节/资源 ├─ 订单/支付回调 MySQL ◀── ORM ────────────────────┤ Redis ◀── 缓存/Token/限流 ─────────┤ OSS/COS ◀── 音视频/图片资源 ───────┘技术栈建议
| 层级 | 技术选型 |
|---|---|
| 后端框架 | ThinkPHP 5.1 / 6.0(以源码 composer.json 为准) |
| 数据库 | MySQL 5.7+,InnoDB |
| 缓存 | Redis(Token、热点课程、分销关系) |
| 前端框架 | Uni-app(Vue2/Vue3 视版本而定) |
| UI 组件 | uView / TDesign Uni / 自封装业务组件 |
| 管理后台 | Vue3 + Element Plus / Arco(或 FastAdmin) |
| 音视频 | HLS 切片 + 播放器 SDK + Token 签名 |
| 部署 | 宝塔 / 1Panel + Nginx + PHP-FPM |
三、数据库与内容模型设计
知识付费最核心的表不是订单表,而是**“课程—章节—资源—购买关系”**这四张表的设计。
3.1 课程四级结构
常见模型是:
分类 category └─ 课程 course └─ 章节 chapter └─ 资源 resource(视频/音频/图文/PDF)course:标题、封面、原价、会员免费标识、讲师ID、上架状态chapter:排序、试看章节、购买解锁resource:类型(1图文/2音频/3视频/4专栏)、url、试看秒数、排序user_course:用户已购课程关系表order:订单状态机member:会员有效期
3.2 订单状态机
标准流转:
待支付 → 已支付 → 已完成 ↓ 已取消 ↓ 已退款最容易出问题的不是下单,而是支付回调:
- 回调丢失 → 用户扣款但没开通
- 重复回调 → 订单被重复处理
- 前端自行改状态 → 脱离服务端真相
正确做法:前端支付成功只做“轮询订单”或“跳转待开通页”,最终权限以 ThinkPHP 回调落库为准。
四、核心功能模块拆解
4.1 内容端
- 视频课程:HLS 分片、倍速、断点续播、试看
- 音频课程:后台播放、定时关闭
- 图文专栏:试读、PDF、附件
- 直播课:直播、伪直播、回放
- 题库考试:章节练习、自动判分、证书
4.2 用户与权限端
角色分三类:
- 学员:购买、学习、打卡、提问
- 讲师:传课、看收益、管学员
- 管理员:审核、财务、平台配置
权限建议用 RBAC:auth_rule+auth_group+auth_group_access,按钮级控制。
会员体系不要只存level字段,要存权限快照缓存:
// 支付成功回调里Cache::delete('auth_'.$uid);下次请求重新算课程访问权,避免“钱付了但页面还提示未购买”。
4.3 交易端
- 单课购买
- 专栏打包
- 会员卡(月/季/年)
- 优惠券、拼团、秒杀
- 微信支付 / 支付宝
- 余额支付
4.4 营销端
- 分销推广(注意合规,建议二级以内)
- 海报分享
- 邀请返佣
- 签到积分
- 卡密兑换
五、ThinkPHP 后端关键设计
5.1 统一接口返回
前端 Uniapp 统一封装$api,后端建议固定格式:
{"code":0,"msg":"success","data":{"course_id":88,"is_paid":1,"progress":320}}code=0成功,非 0 业务失败,前端弹msg。
5.2 内容解锁必须用中间件
错误写法:
publicfunctionplay(){if(!$this->isBuy){$this->error('请购买');}}问题:只挡了控制器入口,静态资源、直链、接口绕过都能漏。
正确思路:
- 路由组挂
Auth中间件 - 中间件里查
user_course是否有有效记录 - 视频/PDF 不走物理路径直链,走
/resource/sign?token=xxx - Token 带 uid + resource_id + expire,校验后流式输出
5.3 静态资源防盗
别把文件放/uploads/course/123.mp4直接暴露。
应改为:
/resource/video/123?sign=md5(secret+uid+expire)&t=1700000000后端校验签名 → 判断是否已购 → 允许播放或拒绝。
配合 HLS 分片 + Referer 白名单 + 水印,能提高盗用门槛(但不能百分百防录屏)。
5.4 支付回调幂等
Db::transaction(function(){if($order->status==='paid')return;// 防重复$order->status='paid';$order->save();UserCourse::grant($order);Cache::delete('auth_'.$order->user_id);});六、Uniapp 多端适配要点
6.1 一套代码编多端
npminstallnpmrun dev:h5npmrun dev:mp-weixinnpmrun build:mp-weixin小程序产物用微信开发者工具导入dist/build/mp-weixin,并改manifest.json的 appid。
6.2 rpx 与样式适配
- 小程序用
rpx没问题 - H5 宽屏会拉伸 → 加
max-width:750px居中兜底 - 状态栏高度用
uni.getSystemInfo()动态 padding - 长列表别用
scroll-view渲几百条,用分页或虚拟列表
6.3 条件编译处理平台差异
分享示例:
// #ifdef MP-WEIXINonShareAppMessage(){return{title,path}}// #endif// #ifdef H5wx.updateAppMessageShareData({...})// #endif支付示例:
// #ifdef MP-WEIXINuni.requestPayment({...})// #endif// #ifdef H5if(isWechat()){WeixinJSBridge.invoke('getBrandWCPayRequest',{...})}else{location.href=order.h5PayUrl}// #endif6.4 小程序包体积
- 主包 ≤ 2M,分包 ≤ 20M
- 图片传 CDN,别塞本地
- tabBar 放主包,课程详情/订单/分销放分包
- 开代码压缩
七、“开源”与“一键部署”到底是什么
7.1 开源范围要写清楚
市面所谓“知识付费源码开源”通常分三种:
- 前端 Uniapp 开源:小程序/H5 代码可改
- 后端部分开源:控制器可读,核心服务加密
- 全开源:前后端都在仓库里,可自由二开
买源码前一定看授权协议:
- 是否允许商用
- 是否允许去掉版权
- 是否限域名
- 是否含微信支付主体绑定
- 后期升级收不收费
7.2 一键部署不是零配置
“一键部署”一般指:
- 自带安装向导
- 导入 SQL 自动建表
- 环境变量
.env模板 - 宝塔/1Panel 一键建站脚本
- 伪静态规则自带
但下面几项仍要人工配:
- 微信小程序 appid
- 微信支付商户号
- HTTPS 证书
- OSS/COS 桶
- 短信接口密钥
八、服务器部署流程(宝塔实战)
环境要求
- PHP 7.4 / 8.0(以源码要求为准,别默认最新)
- MySQL 5.7+
- Nginx
- Redis
- 放行 443 / 80
步骤
1. 建站
宝塔 → 网站 → 添加站点 → 绑域名 → 选 PHP 版本
2. 上传源码
解压到/www/wwwroot/域名
注意根目录别选错,否则访问要带子路径
3. 配置数据库
新建库,字符集utf8mb4
导入源码包里的.sql
改配置:
DB_HOST=127.0.0.1 DB_NAME=knowledge DB_USER=knowledge_user DB_PASS=密码 DB_PORT=33064. 伪静态(ThinkPHP)
Nginx 示例:
location / { if (!-e $request_filename){ rewrite ^(.*)$ /index.php?s=$1 last; } }不配会只有首页能开,其他 404。
5. 目录权限
chmod-R755runtimechmod-R755uploadschmod-R755cache6. 配置小程序端
Uniapp 的.env或config.js里改:
BASE_API='https://api.你的域名.com'小程序后台配置 request 合法域名。
7. 访问安装向导
打开域名 → 填管理员账号 → 初始化数据 → 进后台
九、常见部署报错排查
| 现象 | 原因 | 解决 |
|---|---|---|
| 空白页 | PHP 版本不对 / 短标签 | 换版本、开short_open_tag |
| 500 | 缺扩展 | 装fileinfo、redis、gd |
| 404 除首页 | 伪静态没配 | 加 ThinkPHP 重写规则 |
| 数据库连接失败 | 账号密码/端口错 | 填 127.0.0.1 而非 localhost |
| 502 | PHP-FPM 挂了 | 重启 PHP、看慢脚本 |
| 图片不显示 | 域名没配 APP_URL | 改.env |
| 小程序请求失败 | 没配 HTTPS 合法域名 | 后台加域名 |
十、二次开发示例
示例 1:新增“试看前 60 秒”
resource表加字段trial_seconds
播放器请求时:
if(!$isPaid&&$playTime>$resource['trial_seconds']){returnjson(['code'=>403,'msg'=>'试看结束,请购买']);}示例 2:会员免费课判断
functioncanView($uid,$courseId){if(UserCourse::has($uid,$courseId))returntrue;if(Member::valid($uid)&&$course['member_free']==1)returntrue;returnfalse;}示例 3:分销绑定
user (pid 字段) ├─ invite_code ├─ relation_path下单时算佣金比例,支付成功后写commission_log,提现走审核。
合规提醒:分销层级、佣金比例要符合平台规则和广告法口径,别做成多层返利盘。
十一、安全与内容保护
知识付费最怕三件事:盗链、录屏、退款薅课。
建议叠加:
- 接口签名 + Token 过期
- 视频 HLS 加密
- 播放水印(UID 跑马灯)
- Referer 防盗链
- 试看秒数服务端校验
- 退款后回收课程权限
- 敏感接口限流
- 管理后台开二次验证
但实话实说:
没有前端方案能彻底防录屏,只能提高破解成本。
十二、选型前检查清单
拿一套 ThinkPHP/Uniapp 知识付费源码前,先对照:
- 后端框架版本是否透明(TP5.1 / TP6)
- 是否前后端分离、接口格式是否规范
- 是否支持视频/音频/图文/直播
- 支付是否是服务端回调开通
- 权限是否走中间件而非前端隐藏
- 是否带 RBAC 后台
- Uniapp 是否支持 H5 + 微信小程序
- 是否有 SQL 安装文件
- 是否有伪静态规则
- 是否带部署文档
- 授权是否允许商用
- 分销是否合规可关
- 后期 bug 谁修
十三、总结
ThinkPHP + Uniapp 的组合在知识付费场景里属于性价比很高的一档:
- 后端用 ThinkPHP,订单、权限、支付回调好落地
- 前端用 Uniapp,小程序+H5 一套代码
- 配合宝塔部署,半天能跑起 demo
- 配合 RBAC + 资源签名,能做正规内容付费