本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:WWW/plugins/invite/说明.md。
邀请注册(invite)插件说明
版本:1.7.0 | 作者:SoSite | 状态:⏸️ 未启用(注册后需后台启用)
功能:用户可用积分生成邀请码,被邀请用户凭码注册,注册成功后邀请码标记已用
一、功能简介
- 生成邀请码:用户消耗积分生成邀请码(
Points::deduct),可生成多个、分页查看使用情况 - 注册拦截:开启后注册页要求填写邀请码(
auth_register_before钩子校验) - 校验规则:邀请码必须存在、未被使用、未过期(
expires_at为空则永久有效) - 注册联动:注册成功后自动标记邀请码已使用(
auth_register_after钩子,绑定 used_by_user_id) - 注册页注入:
layout_head_end注入样式表、layout_body_end注入配置块 + 脚本(JS 动态插入输入框)
二、目录结构
plugins/invite/
├── plugin.json # 插件清单(hooks: init_after / route_register / auth_register_before / auth_register_after / nav_plugin_links / layout_head_end / layout_body_end)
├── Plugin.php # 生命周期(activate 建表 / uninstall 删表)
├── InviteController.php # 前台"我的邀请码"(index:列表/分页/生成/统计)
├── hook/
│ ├── init_after.php # 懒建表
│ ├── route_register.php # 路由(/invites)
│ ├── auth_register_before.php # 注册前校验邀请码(错误经 $GLOBALS['auth_register_error'] 传回)
│ ├── auth_register_after.php # 注册后标记邀请码已使用
│ ├── nav_plugin_links.php # 导航"邀请注册"入口
│ ├── layout_head_end.php # 注册页注入 style.css(<head>,只放 )
│ └── layout_body_end.php # 注册页注入 #inviteConfig 配置块 + script.js(</body> 前)
├── assets/
│ ├── style.css # 样式(输入框复用核心 .mn-input,暗色自适应)
│ └── script.js # 注册页动态插入邀请码输入框
└── views/index.php # "我的邀请码"页面(A+ 规则:视图在插件目录)三、数据表
| 表 | 用途 |
|---|---|
invites | 邀请码(code TEXT UNIQUE / creator_id / used_by_user_id / expires_at / created_at / used_at) |
- 建表:
activate()+init_after懒建(幂等 CREATE TABLE IF NOT EXISTS) - 卸载:
uninstall()删除表(符合核心「保留文件、插件自清数据」约定)
四、Hooks
| Hook | 用途 |
|---|---|
init_after | 懒建表 |
route_register | 前台路由(/invites) |
auth_register_before | 注册前校验邀请码:无效/过期/已用 → $GLOBALS['auth_register_error'] = '提示'; 拦截注册 |
auth_register_after | 注册成功后把邀请码标记已使用(读 $_SESSION['validated_invite_id']) |
nav_plugin_links | 导航"邀请注册"入口 |
layout_head_end | 注册页注入 style.css(只放 <link>) |
layout_body_end | 注册页注入 #inviteConfig + script.js(<div> 必须在 body) |
五、路由
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /invites | "我的邀请码":列表/分页/生成/已用统计 |
| POST | /invites | 生成新邀请码(消耗积分)→ 302 回跳 /invites(PRG) |
六、工作流程
注册页(layout_head_end 注入 CSS + layout_body_end 注入配置/脚本 → JS 插入输入框)
→ 提交注册 → auth_register_before 校验邀请码(统一大写比对)
→ 通过:$_SESSION['validated_invite_id'] = 邀请码 id
→ 注册成功 → auth_register_after 标记邀请码已使用(带 IS NULL 并发保护)七、注意事项
- 传错约定:注册前校验错误必须写
$GLOBALS['auth_register_error'],框架 hook 后读取非空即拦截 - 邀请码大小写:生成端
strtoupper存大写;校验端亦strtoupper归一 —— 两端必须对称,否则用户手输小写码会被误判无效 - PRG 必须:生成是写操作(扣积分),核心
Csrf::verify()不消费 token → POST 后必须 302,否则刷新会重复生成 + 重复扣分 - 并发保护:
auth_register_after的 UPDATE 带AND used_by_user_id IS NULL,防止同码被并发注册时后者覆盖前者 - 暗色适配:注册页注入的输入框带
class="mn-input",复用核心主题变量(含暗夜星辰);插件 CSS 不得再声明 background/color,否则.invite-field input(0,1,1) 会压掉.mn-input(0,1,0) 的适配 <div>不进<head>:#inviteConfig放在layout_body_end;layout_head_end只放<link>- 校验通过后邀请码 id 暂存 Session(
validated_invite_id),注册后消费并清理,防止跨会话滥用 - 生成邀请码消耗积分用
Points::deduct(防负保护),relatedId传真实邀请码 id 便于points_log追溯 - 邀请码有效期:
expires_at为空则永久有效;非空则过期后不可用;服务端上界 365 天 - 卸载删表会丢失全部邀请码数据,请谨慎