HuoNiu Credits System - 积分系统

付费/Paid HuoNiu Credits System - 积分系统 2.3.7.3

欢迎客人!

• 开始前请阅读社区规则确保您顺利的熟悉本社区。注册用户可以提交资源,如果您有已发布资源的新版本,您可以随时更新版本!

• 文件链接损坏请在文件下方留言,我们将会及时更新来自备份服务器的新链接。如有其它问题请 提交工单 和我们联系!【加入Telegram】【QQ群:5977983】

• 我们拥有多账户检测系统,对于重复注册我们将采取严厉措施!快速获得积分

  • 🧧 领取红包积分 · Claim Red Envelope Points

功能增加/修复清单

  • XenForo 2.3 兼容性修复
    • 修复 Call to undefined method XF::logModerator() 等 XF 2.3 API 变更导致的报错
    • 替换/兼容旧用法:例如 \GuzzleHttp\json_encode、getEventRepo 等相关调用点
  • “资源过期后下载控制”功能(XFRM)
    • 新增三种过期后下载策略(后台可选)
      • permanent_old_versions(默认):过期后仍可下载“过期前/有效期内发布”的旧版本
      • no_download:过期后完全禁止下载
      • grace_period:过期后宽限期内允许下载旧版本(可配置天数)
    • 新增后台选项
      • hnExpiredDownloadPolicy
      • hnExpiredDownloadGraceDays
  • 前台状态展示与按钮逻辑(XFRM 资源页)
    • 新增/完善购买状态计算与展示:激活中、已过期但可下旧版、宽限期、已过期不可下载等
    • 调整主按钮逻辑:过期用户显示购买/续费,而不是继续访问/下载
    • 补充/修正相关短语与 XML 编码问题
  • 历史版本页“逐版本下载权限”一致性(修复漏洞)
    • 修复问题:过期后发布的新版本在历史版本页仍显示“下载”
    • 实现方式:在 add-on 中直接覆盖 public:xfrm_resource_history 模板
    • 模板侧实现逻辑
      • 下载列显示:使用 canAccessHistoryDownloads()
      • 每行下载按钮:使用 canDownloadVersion($versionId) 判断是否允许下载
    • 处理模板导入限制
      • 修正 xf:if 内不允许的结构
      • 将模板可调用方法名改为 can* 前缀以满足白名单限制(从 hn* 调整为 canDownloadVersion() 等)
  • 下载后端强校验(防直链绕过)
    • 在版本下载 action 中增加版本级校验,防止仅靠 URL 直接下载绕过前台限制
    • 统一使用资源的购买记录获取逻辑 getUserPurchaseRecord(),确保积分/真钱/手动授权路径一致
    • 放行作者/具备绕过权限的用户(避免误伤)
  • “旧版下载仍提示过期”的修复
    • 修复根因:资源 canDownload() 之前固定按 current_version_id 做校验,下载旧版本也会被当作“当前版本”拦截
    • 改为优先从请求参数读取“正在下载的版本 ID”(兼容 resource_version_id / version_id),再做版本级判断
    • 前台历史页展示与后端下载校验逻辑统一
  • 购买记录与版本门控算法修复/增强(积分 + 真钱 + 两者)
    • 修复问题
      • resource_version_id=0、真钱购买不记录版本等导致“过期仍可下载所有版本”的漏洞
      • 版本 ID 与发布时间不严格单调时,用“ID 大小比较”会误判
    • 新策略:统一按 ResourceVersion.release_date <= cutoff 判断
      • cutoff 优先用 expire_date,否则用 purchase_date
    • 积分购买与真钱购买实体均实现同一套“按发布时间门控”的判断方法,并修复真钱购买实体中的异常逻辑(曾存在重复 return 之类问题)
  • phrases.xml 重复键值修复
    • 清理 _data/phrases.xml 中重复的短语 title,保证导入/构建不再报“重复键值”
  • 红包 openBonus 报错修复(游客 user_id=0)
    • 修复问题:triggerEvent failed: Invalid target user ID: 0 / Bonus open failed for user #0
    • 修复方式:在 actionOpenBonus() 开头强制要求登录($visitor->user_id > 0),游客直接返回“需要登录”,不会触发事件
[OKSGO.COM] HuoNiu Credits System - 积分系统


[OKSGO.COM] HuoNiu Credits System - 积分系统

[OKSGO.COM] HuoNiu Credits System - 积分系统

[OKSGO.COM] HuoNiu Credits System - 积分系统

[OKSGO.COM] HuoNiu Credits System - 积分系统

修复的错误:​

  1. [Service/Transfer/Handler.php:236] - 将不存在的 XF::logModerator() 改为正确的 \XF::app()->logger()->logModeratorAction()
  2. [Pub/Controller/Credit.php:271] - 将不存在的 \GuzzleHttp\json_encode() 改为标准 PHP 的 json_encode()
  3. [Pub/Controller/Credit.php:712] - 修复了调用不存在的 getEventRepo() 方法,改为使用 repository('HuoNiu\Credits:Event') 并添加了 getEventRepo() 辅助方法

其他验证通过的内容:​

✅ XF::logError() - 正确方法
✅ XF::logException() - 正确方法
✅ XF:😛hrase() - 正确方法
✅ XF::db() - 正确方法
✅ XF:😱ptions() - 正确方法
✅ $this->app->stringFormatter() - 正确方法
✅ Controller 方法 (assertNotFlooding, assertValidCsrfToken, assertRecordExists 等) - 均为标准 XenForo 方法

本次更新项目总结​

1.​

  • ✅ 为所有积分菜单选项添加Font Awesome图标
    • 购买积分:fa-shopping-cart
    • 账单:fa-file-invoice
    • 交易大厅:fa-store
    • 发送积分:fa-paper-plane
    • 兑换:fa-exchange-alt
    • 处罚:fa-gavel

2.​

  • ✅ 积分显示卡片化:使用CSS Grid网格布局,支持多货币展示
  • ✅ 账单和交易大厅:2列网格,横排图标+文字布局
  • ✅ 购买积分区域:全宽卡片,统一视觉风格
  • ✅ 隐藏弹窗顶部"积分"标题文字

3.​

  • ✅ 使用XenForo CSS变量系统(适配明暗模式)
    • var(--xf-contentAltBg) - 卡片背景
    • var(--xf-paletteNeutral3) - hover状态
    • var(--xf-textColorFeature) - 强调色
    • var(--xf-borderRadiusMedium) - 圆角
  • ✅ 统一卡片样式:圆角、内边距、hover动画、阴影效果
  • ✅ 响应式设计:移动端自动单列布局

4.​

  • ✅ 设置积分图标透明度为0.6,与其他图标协调
  • ✅ 添加hover效果:悬停时透明度变为1

5.​

  • ✅ 将购买积分从扩展点注入改为直接在模板定义
  • ✅ 删除template_modifications.xml中的hn_paygate_wallet_popup注入
  • ✅ 移除所有中文注释,保持代码整洁

6.​

  • templates.xml - hn_wallet_popup模板(主要弹窗UI)
  • templates.xml - hn_credits_app_nav.less模板(导航图标样式)
  • template_modifications.xml - 删除了购买积分的扩展点注入

7.​

  • 现代化卡片设计
  • 平滑过渡动画
  • 明暗模式自适应
  • 整体视觉统一

🔧 1. 修复积分转账反垃圾检查错误

  • 修复了 XF\SubContainer\Spam::checker() 不存在导致的致命错误
  • 改用数据库查询实现防刷机制(10次/小时限制)

⚠️ 2. 购买记录完整迁移系统

问题: 旧版迁移工具只迁移用户积分和资源定价,不迁移购买记录,导致用户丢失已购资源的下载权限

解决方案:
  • ✅ 自动迁移 xf_mjrcp_resource_purchase → xf_hn_resource_purchase
  • ✅ 保留所有购买历史记录
  • ✅ 保留过期日期设置
  • ✅ 支持用户继续下载已购资源
  • ✅ 插件升级时自动执行,无需手动操作
迁移数据包括:
  • 购买用户ID
  • 资源ID和版本ID
  • 购买日期和过期日期
  • 支付金额和净价
  • 购买状态(active → purchased)

🌐 3. 迁移验证界面新增购买记录统计

  • 显示购买记录总数
  • 显示涉及用户数和资源数
  • 显示迁移成功率
  • 未迁移时显示红色警告提示

📋​

迁移执行方式:
  • 自动触发:插件升级时自动执行
  • 手动触发:管理后台"迁移工具"页面查看状态
数据安全:
  • 使用 INSERT IGNORE 防止重复迁移
  • 完整日志记录迁移过程
  • 事务保护确保数据一致性

🚀​

  1. 上传新版插件文件
  2. 后台点击"升级"
  3. 系统自动迁移购买记录
  4. 用户无需任何操作,继续下载已购资源
本次更新包含迁移文档MD说明文件

增加的功能​

1.​

  • ✅ 积分销售文件:创建 ResourcePurchase 记录
  • ✅ 真实货币销售文件:创建/更新 ResourceMoneyPurchase 记录
  • ✅ 同时支持两种 (both):智能判断创建类型
  • ✅ 自定义过期时长:支持天/月/年单位
  • ✅ 永久授权:设置0表示永久有效
  • ✅ 更新已过期记录:不会报唯一键冲突

2.​

  • ✅ 积分购买:设置 purchase_status = 'revoked'
  • ✅ 真实货币购买:设置 expire_date = 过去时间
  • ✅ 同时撤销两种类型
  • ✅ 记录撤销信息:revoked_by 和 revoked_date

3.​

  • ✅ 购买按钮逻辑:有任一购买记录则隐藏所有购买按钮
  • ✅ 下载按钮显示:只显示1个下载按钮
  • ✅ 过期时间显示:优先显示购买记录的实际过期时间
  • ✅ 动态倒计时:实时计算剩余天数
  • ✅ 智能单位:>=365天显示年,>=30天显示月

4.​

  • ✅ checkRequirePurchase():检查两种购买类型
  • ✅ getUserActivePurchase():返回最新的有效购买记录
  • ✅ canDownload():正确处理下载权限
  • ✅ 过期自动失效:isActive() 方法验证

5.​

  • ✅ 权限控制:只有有 hnCredits 权限的管理员可操作
  • ✅ 菜单集成:在资源"更多选项"中显示
  • ✅ 用户搜索:支持自动完成
  • ✅ 表单验证:用户存在性检查、重复授权检查
  1. ResourceItem.php - 表名修正
  2. content_type_fields.xml - 添加 content type 注册
  3. ResourcePurchase.php - 恢复通知功能

新增功能​

  1. 资源过期时间单位支持 - 支持天/月/年三种单位(新增 hn_expiration_unit 字段)

Bug修复​

  1. 表单字段名修复 - hn_expiration_amount → hn_expiration_days
  2. 单位字段接收 - Category.php 和 ResourceItem.php 控制器添加单位字段处理
  3. 过期权限验证 - getUserActivePurchase() 添加过期检查

优化改进​

  1. 显示逻辑增强 - 根据单位动态显示 "购买后 X 天/月/年过期"
  2. 语言短语更新 - 支持 {amount} 和 {unit} 参数

数据库变更​

  • 新增字段:xf_rm_resource.hn_expiration_unit (VARCHAR(10), default='day')
  • 自动升级:upgrade2031006Step1() 方法

一、管理后台修复(Admin Panel)​

  1. 积分标签导航修复
    • 位置:后台用户积分管理页面
    • 问题:点击"积分"标签无法跳转
    • 修复:添加 id="user-credits" 到标签元素

二、货币系统修复(Currency System)​

  1. 货币列访问错误防护
    • 位置:多个模板中的货币显示代码
    • 问题:访问未启用的货币导致报错
    • 修复:添加 $currency 存在性检查
    • 影响范围:所有显示货币信息的模板

三、折扣系统修复(Discount System)​

  1. 折扣计算逻辑修正
    • 位置:折扣百分比计算代码
    • 问题:折扣计算错误(使用 100-discount)
    • 修复:改为直接使用 discount 值
    • 示例:设置80折应显示80%而非20%
  2. 折扣显示同步
    • 位置:前端显示与后端设置
    • 问题:前后端折扣显示不一致
    • 修复:统一折扣显示逻辑
  3. 折扣计算TypeError修复
    • 位置:折扣计算表达式
    • 问题:数值类型不匹配导致TypeError
    • 修复:添加 float() 类型转换

四、红包系统全面改版(Red Envelope System)​

  1. 红包卡片UI完全重设计
    • 位置:templates.xml hn_bonus_list 模板(2105-2300行)
    • 设计特点:
      • 320px宽度红包卡片容器
      • 顶部金色"福"字印章(带脉冲动画)
      • 用户头像(中号,白色边框+金色光环+浮动动画)
      • 发送者祝福语显示
      • 大型金色"开"按钮(脉冲动画)
      • 底部传统祝福文字
      • 6种CSS3动画效果
      • 响应式移动端支持
  2. 红包领取者头像修复
    • 位置:红包卡片和领取者列表
    • 问题:头像显示问号/问号方块
    • 原因:模板使用 $user.TriggerUser 但实体只定义了 User 关系
    • 修复:
      • 将所有 $user.TriggerUser 改为 $user.User
      • 添加 .purchaser-extra .avatar flexbox居中样式
  3. 红包相关语言国际化
    • 位置:phrases.xml
    • 移除硬编码:删除所有中文硬编码文本("福"、"恭喜发财 大吉大利"等)
    • 新增语言键:
      • hn_red_packet_seal_text: "福"
      • hn_red_packet_blessing: "恭喜发财 大吉大利"
      • hn_you_have_received_a_red_envelope: "您已经领过红包了"
      • hn_red_packet_received_message: "领取了您的红包获得了"
      • hn_you_have_already_sent_a_red_envelope: "您已经发过红包了"
      • hn_red_packet_open: "开"
  4. 红包错误消息修正
    • 位置:Post.php 第580行
    • 问题:语言键名称错误
    • 修复:hn_credits_you_have_received_a_red_envelope → hn_you_have_received_a_red_envelope
  5. 帖子列表红包标识
    • 位置:template_modifications.xml 第192-210行
    • 功能:
      • 帖子标题后添加 🎁 礼物图标(Font Awesome fa-gift)
      • 红色高亮(#ff6b6b)
      • 16px尺寸
      • 帖子状态区域也添加标识
    • 目标模板:thread_list_macros

五、积分显示增强(Points Display)​

  1. "您将收到"积分提示增强
    • 位置:templates.xml 第4894行
    • 元素ID:receive-amount-text
    • 增强效果:
      • 字号增大30%(font-size: 1.3em)
      • 文字加粗(font-weight: bold)
      • 绿色文字(#27ae60)
      • 渐变背景(浅绿到白)
      • 圆角边框(border-radius: 6px)
      • 左侧绿色强调线(border-left: 4px solid)
      • 内边距10px,上下边距8px
修复若干错误
增加兼容性规范
提升代码性能
  • 添加了 protected $events = []; 属性声明
  • 修复了 "Undefined property: $events" 错误
🔴 致命问题修复(4项)
| # | 问题类型 | 修复文件 | 修复内容 |
|---|---------|---------|---------|
| 1 | **SQL注入** | `Repository/Credit.php` | 添加 `validateCurrencyColumn()` 白名单验证,修复9个方法 |
| 2 | **并发竞态** | `Service/Transfer/Handler.php` | 添加 `FOR UPDATE` 锁,事务内二次验证余额 |
| 3 | **权限绕过** | `Pub/Controller/Credit.php` | 添加 CSRF、Flooding、输入验证、XSS 防护 |
| 4 | **PHP 8.3兼容** | `Service/Transfer/Handler.php` | 添加完整的参数和返回类型声明 |
🟠 高风险问题修复(4项)
| # | 问题类型 | 修复方式 |
|---|---------|---------|
| 5 | XSS防护 | 添加 `stringFormatter()->censorText()` 过滤所有用户输入 |
| 6 | 资源购买并发 | 确认已有 `GET_LOCK()` 分布式锁保护 |
| 7 | N+1查询 | 添加 `with()` 预加载关联数据 |
| 8 | Flooding攻击 | 添加 `assertNotFlooding()` 频率限制 |
---
🔧 具体修复内容
1. SQL注入防护
**修复的方法**:
- `getUserBalance()` - 白名单验证货币ID
- `getUserBalances()` - 白名单验证货币ID
- `updateBalance()` - 白名单验证货币ID
- `setBalance()` - 白名单验证货币ID
- `getTotalSupply()` - 白名单验证货币ID
- `getUserCount()` - 白名单验证货币ID
- `getRichestUsers()` - 白名单验证货币ID
- `getUserRank()` - 白名单验证货币ID
- `hasEnoughBalance()` - 间接修复(调用 getUserBalance)
**新增方法**:
- `validateCurrencyColumn(int $currencyId): string` - 货币列名白名单验证
- `clearCurrencyCache(): void` - 清除缓存
---
2. 并发竞态防护
**修复的方法**:
- `transfer()` - 添加事务锁和余额二次检查
- `transferWithFee()` - 添加事务锁和余额二次检查
**新增机制**:
- 使用 `FOR UPDATE` 锁定发送者和接收者的数据行
- 在事务内二次验证余额(防止 TOCTOU 攻击)
- 完整的 try-catch 异常处理和事务回滚
---
3. 权限和输入验证
**修复的方法**:
- `actionTransfer()` - 完整的安全检查
- `actionBonus()` - Flooding 防护
- `actionRedEnvelope()` - CSRF + XSS + Flooding 防护
- `actionRedEnvelopeGrab()` - Flooding 防护
**新增验证**:
- CSRF Token 验证
- Flooding 防护(转账60s、奖励30s、红包120s、抢红包5s)
- 金额范围验证(必须 > 0)
- 接收者状态验证(user_state 必须为 'valid')
- 防止转账给自己
- 消息长度限制(500字符)
- XSS 过滤(使用 censorText())
---
4. PHP 8.3 类型声明
**修复的方法**:
- `validate(): bool`
- `transfer(string $message = ''): bool`
- `transferWithFee(float $taxPercent, string $message = '', string $feePayer = 'sender'): bool`
- `createTransaction(...): bool`
- `sendTransferAlert(): void`
- `refundPurchase(...): bool`
- `getErrors(): array`
- `hasErrors(): bool`
---
🛡️ 安全增强总结
| 安全层面 | 实施措施 | 效果 |
|---------|---------|------|
| **SQL注入** | 白名单验证 + 参数化查询 | ✅ 完全防护 |
| **并发控制** | FOR UPDATE 锁 + 分布式锁 | ✅ 防止双花和竞态 |
| **CSRF** | Token 验证 | ✅ 所有 POST 请求受保护 |
| **XSS** | 输入过滤 + 长度限制 | ✅ 防止脚本注入 |
| **Flooding** | 频率限制 | ✅ 防止滥用 |
| **权限** | 多层验证 | ✅ 细化访问控制 |
---
⚡ 性能优化
- ✅ 货币列名白名单使用静态缓存
- ✅ 预加载关联数据避免 N+1 查询
- ✅ 精准行锁减少锁竞争
- ✅ 提前验证减少无效数据库操作
---
✅ 修复验证
- [x] 所有修复文件无语法错误
- [x] 符合 XenForo 2.3 开发规范
- [x] 符合 PHP 8.3 严格类型标准
- [x] 完整的错误处理和日志记录
- [x] 向后兼容,不影响现有功能
后退
顶部