HuoNiu 易支付(XenForo 2 支付提供商)重磅发布!面向中文站点的稳定支付方案,开箱即用、对齐官方流程、快速提升转化。
本插件适配以下源代码 v3096-2025/11/10:
GitHub
GitHub - maajiko/Epay: Epay彩虹易支付源码分享
核心特性
🔐 双接口支持
V1 接口:支持传统MD5签名(MD5/MD5K/MD5U/MD5UK四种变体)
V2 接口:全面支持RSA-SHA256签名,安全性更高
智能切换:根据配置自动选择接口版本
🛡️ 企业级安全
RSA双向认证:商户私钥签名 + 平台公钥验证
时间戳防护:防重放攻击,可配置时间窗口
完整性校验:所有文件SHA-256哈希验证
调试支持:详细日志记录,快速定位问题
🎯 易支付生态对齐
服务端兼容:完全对齐主流易支付源码实现
参数构建:使用与服务端相同的签名算法
格式处理:支持多种RSA密钥输入格式
错误处理:完善的异常捕获和用户提示
📦 安装配置
系统要求
XenForo 2.3.0+
PHP 8.0+
OpenSSL 扩展(V2接口必需)
核心:
接入简单:选择“易支付”提供商,填入商户 ID/密钥即可开通
更稳回调:官方 payment_callback.php 标准回调 + 自定义直连回调(绕过 CDN/WAF)
兼容更强:支持 MD5 / MD5K / MD5U / MD5UK/RSA-SHA256 多签名风格
全链路可观测:详尽日志,问题定位不再靠猜
安全可靠:金额严格校验、幂等防重复入账
What's New in Version 2.1.7
Released
致命修复 - 未定义常量导致 PHP Fatal Error:
- 移除 `CallbackState::PAYMENT_PENDING` 和 `CallbackState::PAYMENT_REJECTED` 的使用——这两个常量在 XenForo 中根本不存在(仅有 `PAYMENT_RECEIVED` 等4个常量),运行时触发 PHP `Error` 导致所有回调处理崩溃
- 对非 `TRADE_SUCCESS` 状态改为记录 info 日志,不执行订单操作
🐛 致命修复 - `<xf:form>` 自动注入 `_xfToken` 破坏签名:
- `easypay_payment_redirect` 模板原使用 `<xf:form>` 标签,XenForo 会自动向表单注入 CSRF Token 字段 `_xfToken`,该字段被一并 POST 给易支付服务端,导致服务端验签时包含此未知字段而**百分百失败**
- 改为普通 `<form>` 标签(向第三方服务器提交无需 XF CSRF 保护)
🐛 严重修复 - 多支付类型时预签名过期导致支付失败:
- `easypay_payment_initiate` 原将含预计算签名的数据直接 POST 给易支付;当用户在页面切换支付类型(如支付宝→微信),签名仍是旧类型的,服务端验签**必然失败**
- 重构支付发起流程:表单改为提交至 XF 内部路由 `purchase/process`,由 `processPayment()` 用用户实际选择的类型**重新签名**后再跳转易支付
- `initiatePayment()` 新增 `$processUrl` 变量传入模板;表单使用 `<xf:form>` 带 CSRF 保护;仅传 `request_key` 和 `type`,无需传递预签名的全量参数
🐛 严重修复 - 命名空间缺失 `\` 导致异常无法捕获:
- `generateCallbackV2Sign()` 中 `catch (Exception $e)` 未加命名空间前缀,在 `HuoNiu\EasyPay\Payment` 命名空间下实际捕获的是根本不存在的 `HuoNiu\EasyPay\Payment\Exception`,OpenSSL 异常会从 try 块直接逃逸
- 修正为 `catch (\Throwable $e)
🐛 修复 - PHP 8 Error 对象无法被 catch 捕获:
- 三处回调入口(控制器 `Callback.php`、传统回调 `epay_callback.php`)的顶层 `catch` 均使用 `catch (\Exception $e)`,PHP 8 中 `\Error`(未定义常量、类型错误等)不继承 `\Exception`,异常逃逸后返回未知错误且无精确日志
- 全部改为 `catch (\Throwable $e)`,覆盖 `Error` 与 `Exception` 两棵继承树
🐛 修复 - 签名字段 null 值处理与源码不一致:
- `generateV1Sign()` 仅跳过空字符串 `''`,不跳过 `null`;`buildSignQuery()` 未过滤数组类型值——与易支付服务端 `isEmpty()` 行为不完全一致,特定参数下可能产生签名差异
- `generateV1Sign` 补充 `|| $v === null` 判断;`buildSignQuery` 添加 `!is_array($v)` 前置过滤
🛠️ 修复 - 回调请求实体类查找错误(前版遗留):
- `Callback.php` 原使用 `XF:PaymentProfile`(支付配置实体)查找支付提供商,应为 `XF:PaymentProvider`(支付提供商实体,主键为字符串 `provider_id`),导致回调 404
- 已更正实体类名
🛠️ 修复 - 调用不存在的方法(前版遗留):
- `Callback.php` 原调用 `$handler->processCallback()`,该方法在 XF 支付框架中不存在,改为完整的 XF 标准验证调用链:`setupCallback → validateCallback → validateTransaction → validatePurchaseRequest → ... → getPaymentResult → completeTransaction`
🛠️ 修复 - `_xfProvider` 参数污染签名(前版遗留)**:
- 回调 URL 携带的 `_xfProvider` 参数被混入签名计算,与易支付服务端签名字段集不一致导致验签失败
- 新增 `stripXfParams()` 方法在签名前剔除所有 XF 内部参数(`_xfProvider` 及含 `/` 的路由键)
🛠️ 修复 - `getInputRaw()` 返回字符串非数组(前版遗留):
- `setupCallback()` 原使用 `$request->getInputRaw()` 获取回调数据,该方法返回原始请求体字符串而非参数数组,导致后续所有字段读取均为空
- 改为 `array_merge($_GET, $_POST)` 兼容易支付 GET 或 POST 两种回调方式
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.