
简介这是一套面向支付系统开发者与二次开发者的H5十四合一代付系统源码基于PHP7.4与MySQL5.7环境运行代码全开源适合需要搭建聚合支付平台或进行功能定制的技术人员参考使用。资源包共112个文件包含25个php核心程序文件、6个html页面、5个js脚本、2个css样式表以及1个sql数据库文件另配有31张png与25张jpg图片素材压缩包约9.46MB结构完整便于部署。系统内置美团、京东、拼多多、滴滴、携程、抖音、淘宝、得物、飞猪、猫眼等14套模板支持代理分成、用户提现、推广下级、商品上架审核及后台运营大屏支付接口可对接总后台或由用户自行配置。本次更新修复了分享卡片显示异常、远程资源加载缓慢等问题并将分享卡片配置集成至后台支持自定义文字与图片。已有225人学习下载适合具备一定PHP基础、希望快速搭建或二次开发代付平台的开发者参考。1. 十四合一代付系统到底合了什么从 H5 收银台到二次开发边界很多人第一次听到「十四合一代付系统」会以为是十四个支付通道简单堆在一起实际拆开看它合的是十四类代付业务场景单笔代付、批量代付、定时代付、审核后付、API 直连代付、H5 收银台代付、余额代付、佣金结算代付、退款回退、多商户分账代付、异步回调通知、对账文件生成、风控拦截、二次开发接口。这套源码的价值不在通道数量而在于它把「商户下单 → 平台审核 → 通道扣款 → 回调通知 → 对账核销」这条链路做成了可插拔的模块你拿到手后能按自己的业务改风控规则、换通道适配器、加商户层级。适合谁看手里有支付牌照或聚合支付资质的团队、需要给商户做代付结算的平台方、想学支付系统架构的后端工程师。不适合想直接上线跑资金的人——代付涉及资金安全源码只是骨架合规和风控得自己补。H5 端在这套系统里承担的是商户操作台和用户收银台两个角色前者用 uniapp 封装成 H5 能同时指向两个域名做灰度后者要处理 iOS 下载文件变预览、input 聚焦键盘顶起页面这些移动端老问题。下面按「先跑通最小闭环再改通道最后避坑」的顺序拆。2. 把源码跑起来环境、数据库与 H5 收银台最小闭环2.1 环境选型与宝塔部署的取舍这套源码常见做法是 PHP 后端 MySQL Redis Nginx前端 H5 用 Vue 或 uniapp 打包。服务器系统我一般选 CentOS 7.9 或 Ubuntu 22.04宝塔面板能省掉装 Nginx、PHP、MySQL 的时间但要注意宝塔默认装的 PHP 版本可能和源码要求的扩展不匹配。源码里通常需要bcmath、gd、redis、curl、openssl这几个扩展缺一个代付签名就会报错。部署前先确认三件事PHP 版本常见 7.4 或 8.0看源码 composer.json、MySQL 版本5.7 够用8.0 注意密码加密方式、Redis 是否开启持久化。宝塔里建站点时把运行目录指向public伪静态选thinkphp或laravel规则具体看框架。数据库导入用 phpMyAdmin 或命令行都行导入后检查config/database.php里的连接信息。# 宝塔 SSH 里检查 PHP 扩展缺哪个装哪个 php -m | grep -E bcmath|gd|redis|curl|openssl # 导入数据库注意替换库名和用户名 mysql -u root -p payment_db /www/wwwroot/payment/sql/install.sql # 给 runtime 和 upload 目录写权限否则代付回调日志写不进去 chmod -R 755 /www/wwwroot/payment/runtime chmod -R 755 /www/wwwroot/payment/public/upload参数说明payment_db是源码里默认库名导入前先在宝塔数据库页面建好同名库runtime目录存的是代付请求日志和回调记录权限不对会出现「下单成功但查不到订单」的玄学问题。Redis 配置在.env或config/cache.php代付的幂等锁和验证码都靠它别用文件缓存代替。2.2 十四合一代付的数据库表结构与核心字段代付系统的表设计决定了你能不能二次开发。常见核心表有merchant商户、order代付订单、channel通道配置、callback_log回调日志、settlement结算记录、risk_rule风控规则。order表里几个字段必须盯紧order_no平台订单号、out_trade_no商户订单号、channel_code通道标识、amount金额分、fee手续费、status状态0 待审核 1 处理中 2 成功 3 失败 4 退回、notify_url回调地址、notify_status通知状态。二次开发时最容易翻车的是金额单位。源码里如果amount存的是分你前端传元就会差 100 倍有些通道要求传元适配器里得做转换。状态机也要看清代付和代收不同代付失败后资金退回是异步的status3不代表钱已经回来得看settlement表。-- 查一笔代付订单的完整链路排查卡在哪个状态 SELECT o.order_no, o.out_trade_no, o.amount, o.fee, o.status, o.channel_code, o.notify_status, c.channel_name FROM order o LEFT JOIN channel c ON o.channel_code c.code WHERE o.out_trade_no 你的商户订单号; -- 查回调日志确认通道是否通知过 SELECT * FROM callback_log WHERE order_no 平台订单号 ORDER BY id DESC LIMIT 5;逻辑说明第一段 SQL 把订单和通道配置关联能看出用的是哪家通道、通知状态是否成功第二段查回调日志如果通道通知了但notify_status0说明你的回调处理逻辑有 bug常见是签名验证失败或返回内容不是通道要求的格式。2.3 H5 收银台跑通第一笔代付H5 收银台是商户或用户发起代付的入口。用 uniapp 封装 H5 时如果要做灰度或双域名可以在manifest.json里配h5.router.base再在 Nginx 做两个 server 块指向同一套静态资源。跑通第一笔代付的步骤配置一个测试通道 → 建测试商户 → 生成 API 密钥 → 用 Postman 或 curl 调代付接口 → 看回调。# 调代付下单接口参数按源码文档替换 curl -X POST https://你的域名/api/pay/create \ -H Content-Type: application/json \ -d { merchant_no: M10001, out_trade_no: TEST20250101001, amount: 100, bank_card: 6222020200112233445, bank_name: 工商银行, account_name: 张三, notify_url: https://你的域名/notify/test, sign: 按源码签名规则生成 }参数说明amount单位看源码多数是分sign签名规则通常在app/common/library/Sign.php或类似文件里常见是参数按 key 排序后拼key商户密钥做 MD5 或 HMAC-SHA256。notify_url必须是公网可访问的本地开发用内网穿透工具临时映射但注意别把测试回调地址带到生产。提示第一笔代付建议用通道的沙箱环境没有沙箱就用最小金额比如 1 分跑确认回调、对账、状态流转都正常再放大金额。3. 二次开发改哪里通道适配器、风控规则与 H5 双域名封装3.1 新增一个代付通道适配器的完整步骤十四合一代付系统的扩展性体现在通道适配器上。常见目录结构是app/channel/driver/下每个通道一个类实现pay()、query()、notify()、transfer()几个方法。新增通道时不要改核心逻辑照着已有通道复制一份改。?php // app/channel/driver/NewChannel.php namespace app\channel\driver; class NewChannel { protected $config; public function __construct($config) { $this-config $config; // 从 channel 表读的商户号、密钥、网关地址 } // 代付下单返回通道订单号和原始响应 public function transfer($order) { $params [ mch_id $this-config[mch_id], out_trade_no $order[order_no], amount $order[amount], // 注意单位通道要元就 /100 bank_card $order[bank_card], notify_url $this-config[notify_url], ]; $params[sign] $this-sign($params); $result $this-httpPost($this-config[gateway], $params); // 统一返回格式核心逻辑只认 code/msg/data return [ code $result[ret_code] 0000 ? 1 : 0, msg $result[ret_msg], data [channel_order_no $result[channel_order_no]], ]; } // 签名按通道文档改 protected function sign($params) { ksort($params); $str urldecode(http_build_query($params)) . key . $this-config[key]; return strtoupper(md5($str)); } protected function httpPost($url, $data) { $ch curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST true, CURLOPT_POSTFIELDS http_build_query($data), CURLOPT_RETURNTRANSFER true, CURLOPT_TIMEOUT 10, ]); $res curl_exec($ch); curl_close($ch); return json_decode($res, true); } }逻辑说明适配器只负责和通道通信不碰订单状态。核心逻辑调transfer()拿到code1后把订单置为处理中等notify()回调再改成功或失败。参数说明$this-config从channel表按channel_code读新增通道时在后台加一条记录填商户号和密钥amount单位转换是高频坑通道要元就除以 100要分就原样传。3.2 风控规则怎么加才不影响正常代付代付风控比代收更敏感因为直接出钱。常见规则单笔限额、单日累计限额、同一收款卡短时间多次、商户余额不足拦截、黑名单卡号。源码里风控通常在app/common/library/Risk.php或独立risk_rule表配。加规则时用「先记录后拦截」策略别一上来就硬拦否则正常商户会被误伤。// 在代付下单前调用风控检查 public function check($order) { // 规则1单笔限额从 risk_rule 表读 $limit Db::name(risk_rule)-where(type, single_limit)-value(value); if ($order[amount] $limit * 100) { return [pass false, msg 单笔超限]; } // 规则2同一卡号 10 分钟内超过 3 次 $count Db::name(order) -where(bank_card, $order[bank_card]) -where(create_time, , time() - 600) -count(); if ($count 3) { return [pass false, msg 该卡号操作过于频繁]; } // 规则3商户余额是否够代付加手续费 $balance Db::name(merchant)-where(merchant_no, $order[merchant_no])-value(balance); if ($balance $order[amount] $order[fee]) { return [pass false, msg 余额不足]; } return [pass true]; }参数说明single_limit存的是元比较时乘 100 转分create_time用时间戳查询范围 600 秒。风控规则建议做成后台可配别写死在代码里否则每次调阈值都要发版。注意风控拦截的订单要记日志方便商户申诉时查。3.3 uniapp 封装 H5 指向两个域名的配置热词里「uniapp 封装 h5 如何指向 2 个域名」是真实需求常见于灰度发布或主备切换。做法是在manifest.json的h5节点配router.base然后打包两份Nginx 按域名分发。如果要在运行时动态切可以用环境变量注入。// config.js 根据当前域名返回不同 API 地址 const host window.location.host; const apiMap { pay.example.com: https://api1.example.com, pay-backup.example.com: https://api2.example.com, }; export const API_BASE apiMap[host] || https://api1.example.com; // 请求封装里用 API_BASE import axios from axios; import { API_BASE } from ./config; const request axios.create({ baseURL: API_BASE, timeout: 10000 });逻辑说明window.location.host拿到当前访问域名映射到对应 API 地址这样同一份 H5 代码部署到两个域名能指向不同后端。参数说明apiMap的 key 要和 Nginxserver_name一致如果 H5 嵌在 App 里window.location.host可能为空得用plus.runtime或原生注入的方式传域名。注意H5 在 iOS 上下载文件变成预览是 Safari 的限制代付对账文件下载建议用window.open或后端返回 base64 让前端转 Blob 下载别直接给文件 URL。4. 代付系统避坑回调、金额与状态机的血泪经验4.1 回调通知收不到或重复处理现象通道显示代付成功但平台订单还是处理中或者同一笔回调被处理两次导致重复加款。原因回调地址公网不可达、签名验证失败、回调处理没有幂等锁。解决先用curl从外网访问回调地址确认通签名验证失败看参数是否被 URL 编码影响幂等用 Redis 锁key 用order_no处理前setnx处理完删掉。// 回调入口加幂等锁 $lockKey notify_lock_ . $orderNo; if (!Redis::setnx($lockKey, 1)) { exit(success); // 已处理过直接返回成功避免通道重试 } Redis::expire($lockKey, 300); // ... 处理业务逻辑 Redis::del($lockKey);4.2 金额单位不一致导致多付或少付现象商户传 100 元实际代付 1 元或 10000 元。原因前端传元、后端存分、通道要元三层单位没统一。解决约定所有内部计算用分只在调通道适配器时按通道文档转换转换处加注释和单元测试。4.3 状态机乱改导致对账对不上现象订单状态从处理中直接跳成功但通道实际失败对账时资金缺口。原因回调处理没校验通道返回的最终状态或者人工在后台乱改状态。解决状态流转只允许通过回调或主动查询接口改后台改状态要记操作日志对账文件每天跑一次比对。4.4 商户密钥泄露被刷代付现象商户密钥硬编码在前端或日志里被人拿到后伪造代付请求。原因密钥存在 H5 代码或runtime日志。解决密钥只存后端前端不碰日志里签名和密钥脱敏给商户加 IP 白名单。4.5 数据库连接数打满现象代付高峰期报「too many connections」。原因每个请求都新建数据库连接或者慢查询堆积。解决用连接池检查order表的out_trade_no和create_time有没有索引回调处理里的查询加缓存。5. 进阶用对账文件反查代付漏洞与二次开发验收清单代付系统上线后最有效的验证手段不是看订单列表而是跑对账。通道一般提供对账文件下载接口或定时推送格式常见 CSV 或 TXT。写一个脚本每天拉取和本地order表比对重点看三类差异通道成功但本地处理中、通道失败但本地成功、金额不一致。# 对账脚本核心逻辑按通道文件格式调整 import csv from datetime import datetime def reconcile(channel_file, db_orders): diff [] with open(channel_file, r, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: order_no row[out_trade_no] channel_status row[status] # 通道侧状态 channel_amount int(float(row[amount]) * 100) local db_orders.get(order_no) if not local: diff.append((本地缺失, order_no)) continue if channel_status SUCCESS and local[status] ! 2: diff.append((通道成功本地未成功, order_no)) if channel_status FAIL and local[status] 2: diff.append((通道失败本地成功, order_no)) if channel_amount ! local[amount]: diff.append((金额不一致, order_no)) return diff参数说明channel_file是通道对账文件路径db_orders是从数据库查的订单字典key 用out_trade_no。差异结果要人工复核尤其是「通道失败本地成功」这种可能是回调伪造或状态机 bug。对账脚本建议每天凌晨跑结果发到运维群。二次开发验收清单新增通道能否正常下单、查询、回调风控规则是否可后台配置且生效H5 双域名切换后 API 地址是否正确回调幂等锁是否生效对账脚本能否跑出差异日志里有没有明文密钥。这几项过了这套十四合一代付系统才算真正能接业务。我自己踩过最深的坑是回调幂等没做通道重试三次商户被加了三次钱最后人工追回。从那以后我习惯在回调入口第一行就加锁宁可多写十行代码也别留这种后悔药都没得吃的漏洞。希望帮到你。本文还有配套的精品资源点击获取