支付对接 1
更新于 2026-10-13
支付渠道对接
文枢CMS 官网的支付模块采用驱动化设计:一个渠道 = 一条数据库记录 + 一个驱动类。后台可随时新增渠道,无需改代码。
一、支持的协议
| 驱动 | 标识 | 说明 |
|---|---|---|
| 码支付(多财) | duocai | 官方对接渠道,接口地址 https://pay.1kexiu.xyz/ |
| 易支付(通用) | epay | 兼容标准易支付协议,只需填网关地址 + PID + KEY |
| 码支付(通用) | codepay | 兼容常见码支付平台,字段名可在扩展参数中映射 |
| 余额支付 | balance | 站内余额直接扣款,即时到账 |
| 本地沙箱 | sandbox | 仅开发调试,不产生真实资金 |
二、签名算法(易支付 / 码支付通用)
- 把本次实际发送的全部参数按参数名 ASCII 升序排列
- 排除
sign、sign_type、a、c、m、s,以及值为空字符串或null的字段
- 按
key=value用&连接(值保持原样,不要 URL 编码)
- 在参数串末尾直接追加支付对接密钥
- 计算 32 位小写 MD5
function makeSign(array $params, string $key): string
{
unset($params['sign'], $params['sign_type'],
$params['a'], $params['c'], $params['m'], $params['s']);
$params = array_filter($params, fn($v) => $v !== '' && $v !== null);
ksort($params, SORT_STRING);
$pairs = [];
foreach ($params as $name => $value) {
$pairs[] = $name . '=' . $value;
}
return md5(implode('&', $pairs) . $key);
}
⚠️ 末尾是直接拼接密钥,不是
&key=密钥。
官方测试向量
用这组参数校验你的实现是否正确:
pay_key = test_pay_key_20260813
pid = M1234567890
type = alipay
out_trade_no = ORDER202608130001
notify_url = https://shop.example.com/pay/notify?channel=alipay&version=2
return_url = https://shop.example.com/pay/return?order=ORDER202608130001&source=pay
name = 测试订单
money = 1.00
正确结果:
beddd35092c3afea54c5218de0872502
注意:notify_url / return_url 里的 & 必须原样参与签名,不要先转成 &;验签时也不要 trim、不要格式化金额、不要二次 URL 解码。
三、下单接口
3.1 页面支付(推荐)
服务端签名后渲染自动提交表单,跳到收银台:
<form id="payForm" action="https://pay.1kexiu.xyz/submit.php" method="post">
<input type="hidden" name="pid" value="M1234567890">
<input type="hidden" name="type" value="alipay">
<input type="hidden" name="out_trade_no" value="WS20261010ABCDEF">
<input type="hidden" name="notify_url" value="https://example.com/pay/notify/duocai">
<input type="hidden" name="return_url" value="https://example.com/pay/return/duocai">
<input type="hidden" name="name" value="墨白 · 极简博客模板">
<input type="hidden" name="money" value="9.90">
<input type="hidden" name="sign" value="SERVER_GENERATED_SIGN">
<input type="hidden" name="sign_type" value="MD5">
</form>
3.2 API 下单
POST {网关}mapi.php,成功返回:
{ "code": 1, "msg": "下单成功", "trade_no": "5090058146920009728",
"payurl": "https://pay.1kexiu.xyz/gateway/Submit/pay?trade_no=..." }
或二维码模式:
{ "code": 1, "msg": "下单成功", "trade_no": "...", "qrcode": "https://qr.alipay.com/..." }
接入端应同时兼容 payurl 与 qrcode,优先取实际非空字段。
失败时 code = -1,响应里会带请求编号,便于向服务商排查。
四、参数说明
| 参数 | 必填 | 说明 | |
|---|---|---|---|
pid | 是 | 商户 PID | |
type | 是 | alipay / wxpay / qqpay | |
out_trade_no | 是 | 商户订单号,仅允许字母、数字及 `. _ - \ | `,同 PID 内唯一 |
notify_url | 是 | 异步通知地址,必须公网可访问的 HTTPS,允许带查询参数 | |
return_url | 是 | 同步跳转地址,新版必须传 | |
name | 是 | 商品标题 | |
money | 是 | 金额(元),0.01 ~ 99999999.99,建议固定两位小数字符串 | |
sign | 是 | 32 位小写 MD5 | |
sign_type | 是 | 固定 MD5 | |
param | 否 | 业务扩展参数,回调时原样返回,不要放敏感信息 | |
clientip | 否 | 付款用户 IP,非空时参与签名 | |
device | 否 | pc / mobile / wechat / alipay / qq,发送时参与签名 |
五、异步通知(发货依据)
支付成功后平台会 POST 到 notify_url:
| 参数 | 说明 |
|---|---|
pid | 商户 PID |
trade_no | 平台订单号 |
out_trade_no | 商户订单号 |
type | 支付方式 |
name | 商品名称 |
money | 金额,固定两位小数(如 1.00) |
trade_status | 只有精确等于 TRADE_SUCCESS 才表示成功 |
param | 下单时的扩展参数 |
sign / sign_type | 验签字段 |
处理顺序(务必按这个顺序)
1. 先验签 用收到的原始参数验签,失败立即拒绝
2. 再核订单 核对 PID、订单号、金额与本地待支付记录
3. 幂等入账 以 trade_no 或 out_trade_no 加唯一约束,重复通知不重复发货
4. 最后应答 成功返回纯文本小写 success(不要附带 HTML 或 JSON)
PHP 骨架:
$params = array_replace($_GET, $_POST); // POST 覆盖同名 GET
if (!hash_equals(makeSign($params, $payKey), (string) ($params['sign'] ?? ''))) {
http_response_code(400);
exit('fail');
}
if (($params['trade_status'] ?? '') !== 'TRADE_SUCCESS') {
http_response_code(400);
exit('fail');
}
// 事务中锁定订单 → 核对金额 → 只把「未支付」改为「已支付」
// 处理成功后才 return 'success'
严禁只凭浏览器跳转发货。
return_url可能被关闭、重复访问甚至伪造,同步页只用于展示结果。文枢CMS 的Core\Pay\Pay::settle()已按上述顺序实现幂等入账。
六、订单查询
POST {网关}api.php,用 pid + 支付对接密钥鉴权:
| 动作 | 参数 | 返回 |
|---|---|---|
| 商户状态 | act=query&pid=&key= | code、active、money、username、type |
| 单笔订单 | act=order&pid=&key=&out_trade_no= | trade_no、status、money、pay_time |
| 订单列表 | act=orders&pid=&key=&limit=20&page=1 | total、data |
status 含义:0 未支付 / 1 支付成功 / 2 已超时。
curl --request POST 'https://pay.1kexiu.xyz/api.php' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'act=order' \
--data-urlencode 'pid=M1234567890' \
--data-urlencode 'key=YOUR_PAY_KEY' \
--data-urlencode 'out_trade_no=WS20261010ABCDEF'
请求超时不要盲目重复下单:先用原
out_trade_no查单,查到就继续用原平台订单;查不到等几秒再查。当前接口不承诺下单幂等。
七、在官网后台配置渠道
后台 → 支付渠道 → 新增/编辑:
| 字段 | 说明 |
|---|---|
| 渠道标识 | 唯一 code,用于回调地址 /pay/notify/<code> |
| 驱动 | 选择协议类型 |
| 网关地址 | 如 https://pay.1kexiu.xyz/(保留末尾斜杠) |
| 商户 PID | 商户中心显示的 PID |
| 支付对接密钥 | 仅用于签名与验签,不要用登录密码或软件密钥 |
| 支付方式 | 可用通道,逗号分隔 |
| 扩展参数 | JSON,如 {"mode":"api"} 切换为 API 下单 |
配置保存后可在列表点「检测」按钮,程序会调用 act=query 校验商户状态与可用通道。
八、安全红线
- 密钥只存服务端,绝不下发到浏览器、不可写入日志
- 生产环境务必开启「强制回调验签」
notify_url不能填localhost或内网地址,且路由不要 301/302 跳转
- 回调应答只能是纯文本
success
- 汇率 / 金额一律用整数分存储与比对,避免浮点误差