商业视频打赏系统源码落地:双支付与代理分账实战
简介这是一套面向企业或个人运营者的商业视频打赏平台源码基于完整可编译的前后端工程构建适合具备一定开发基础、希望快速搭建自定义打赏系统的技术人员二次开发。压缩包共2001个文件以1766个js脚本、134个html页面、23个css样式及少量json、sql、md文档为主整体约57.45MB涵盖用户模块、视频管理、双支付接口、打赏逻辑、代理打赏、数据统计与安全机制等核心组成。系统集成支付宝、微信等多种支付渠道支持代理打赏与收益分配便于运营者分析用户行为与收入情况。已有625人学习下载购买者可获得底层源码按需修改、优化或扩展功能快速落地具备双支付与代理打赏能力的视频平台。1. 商业视频打赏系统从“双支付代理分账”看一套源码的真实落地门槛你拿到一个压缩包名字叫“最新商业视频打赏系统源码 打赏平台 视频打赏双支付系统 含代理打赏源码.zip”第一反应大概率是解压、配数据库、跑起来然后接支付、开代理、上线收钱。但真正做过这类系统的人都知道视频打赏平台的核心难点从来不是“能不能播放视频”而是钱怎么进、怎么分、怎么对账、怎么防刷。双支付系统意味着你要同时对接至少两条支付通道比如微信原生支付支付宝当面付或者易支付码支付代理打赏则要求每一笔打赏都能按代理层级实时分润且不能出现超卖、重复分账、掉单不补。这套源码适合谁适合有一定 PHP/MySQL 基础、想快速搭建垂直视频打赏平台如才艺直播切片、短剧打赏、私域视频互动的开发者或小团队。如果你连 Composer 和 Nginx 伪静态都没配过建议先补课否则后面每一步都是血泪坑。本章不堆概念只帮你判断这套东西值不值得投入时间以及你会在哪几个环节被卡住。2. 双支付系统怎么接从通道选型到异步回调的完整链路2.1 双支付不是“两个按钮”而是两套独立回调逻辑很多新手以为双支付就是在打赏页放两个支付图标用户点哪个就走哪个。实际代码里微信支付和支付宝支付的异步通知签名算法、报文格式、重试策略完全不同。以常见的 PHP 实现为例微信 V3 支付用 SHA256-RSA 验签支付宝用 RSA2 验签且支付宝回调是application/x-www-form-urlencoded微信是 JSON。如果你把两套回调写在一个notify.php里用if($typewx)硬分支后期加通道会非常痛苦。我一般会拆成notify_wxpay.php和notify_alipay.php各自独立验签、独立写订单状态只共用同一个order表和user表。// notify_wxpay.php 核心片段验签后处理业务 $wechatPay new WeChatPayV3($mchId, $serialNo, $privateKey); $body file_get_contents(php://input); $verifyResult $wechatPay-verifyNotify($body, $_SERVER[HTTP_WECHATPAY_SIGNATURE] ?? ); if (!$verifyResult) { exit(sign fail); } $data json_decode($body, true); $outTradeNo $data[resource][ciphertext][out_trade_no] ?? ; // 查本地订单防止重复分账 $order $db-get(orders, *, [out_trade_no $outTradeNo, status 0]); if (!$order) { exit(order not found or already paid); } // 开启事务更新订单 写分账记录 加代理佣金 $db-action(function($db) use ($order, $data) { $db-update(orders, [status 1, pay_time time()], [id $order[id]]); $db-insert(commission_log, [ order_id $order[id], agent_id $order[agent_id], amount $order[price] * $order[agent_rate], created_at time() ]); }); echo json_encode([code SUCCESS, message OK]);上面代码的关键点有三个第一验签必须在业务处理之前否则伪造回调直接改订单第二查订单要带status0条件微信会重复通知不加条件会重复分账第三分账和改状态必须在同一个数据库事务里否则改完状态但分账失败代理会来找你。参数方面$mchId和$serialNo从微信商户平台获取$privateKey是apiclient_key.pem的内容不要用公钥。支付宝那边类似但注意trade_status必须是TRADE_SUCCESS或TRADE_FINISHED才处理TRADE_CLOSED要忽略。2.2 支付通道的“降级开关”与订单超时关单双支付系统最怕一种情况微信通道临时维护用户点微信支付一直转圈但页面没有提示用户以为打赏成功了实际上订单没支付。我一般会在后台加一个pay_channel_status配置表每个通道有enabled字段前端渲染时只显示启用的通道。同时订单创建后写入expire_time通常 5 分钟用计划任务每分钟扫描status0 AND expire_time now()的订单调用微信/支付宝的关单接口并把本地订单标记为status2已关闭。这样能避免用户过半小时又去支付一个已关闭的订单导致回调回来找不到有效订单。# crontab 每分钟执行关单脚本 * * * * * /usr/bin/php /www/wwwroot/your_domain/cron/close_order.php /tmp/close_order.log 21close_order.php里循环查 100 条过期订单逐条调用closeOrder接口。注意微信关单接口要求订单未支付且未关闭如果已经支付成功但回调延迟关单会返回错误此时应跳过并记录日志不要强行改状态。这个逻辑写不好就会出现“用户付了钱但订单被关”的玄学问题对账时非常头疼。2.3 代理分账的层级计算与防超卖代理打赏源码通常支持无限级代理但实际落地时我建议最多三级因为层级越深分账计算越容易出错且代理之间容易产生纠纷。数据库设计上agent表要有parent_id和path字段如1,3,7这样查上级代理不用递归查询。每笔打赏订单创建时根据用户绑定的代理 ID 向上追溯把每一级的佣金比例和金额算好写入commission_log表状态为pending。等支付回调成功再把pending改为settled。这里有一个关键参数代理佣金比例不能超过平台总抽成否则平台亏钱。我一般会在后台加校验所有上级代理佣金之和 平台抽成 100%如果配置超过 100%保存时直接报错。-- 查询某代理的所有上级按层级从近到远 SELECT id, parent_id, rate FROM agent WHERE FIND_IN_SET(id, (SELECT path FROM agent WHERE id ?)) ORDER BY FIELD(id, REVERSE(SUBSTRING_INDEX(REVERSE(path), ,, 1))) DESC;上面 SQL 利用了path字段快速取上级但注意FIND_IN_SET在数据量大时性能一般代理表通常几千行以内没问题。如果代理超过 1 万建议用闭包表或递归 CTE。防超卖方面打赏本身不涉及库存但代理佣金余额不能为负。提现时先扣减agent.balance如果扣减后小于 0直接拒绝。不要用“先提现再扣款”的逻辑否则代理可以提现后立刻打赏把余额花掉平台垫钱。3. 视频打赏业务侧从播放器埋点到防刷打赏的工程细节3.1 视频播放器与打赏按钮的联动埋点视频打赏系统的前端通常是一个 H5 页面嵌入video标签或第三方播放器。打赏按钮不是一直显示而是在视频播放到特定时间点比如高潮片段才弹出。实现方式有两种一种是用timeupdate事件监听当前播放进度当currentTime进入预设区间如 30s-35s时显示打赏浮层另一种是后端在视频元数据里标记reward_points前端拉取后动态插入。我倾向于第一种因为不需要改视频文件运营可以随时在后台调整时间点。// 视频播放到指定区间显示打赏按钮 const video document.getElementById(myVideo); const rewardPoints [30, 60, 90]; // 秒 let shown {}; video.addEventListener(timeupdate, function() { const t Math.floor(video.currentTime); rewardPoints.forEach(point { if (t point t point 5 !shown[point]) { document.getElementById(rewardLayer).style.display block; shown[point] true; } }); });这段代码的逻辑是每到一个打赏点显示浮层并用shown对象防止同一区间重复弹出。参数rewardPoints从后端接口获取不要硬编码。注意移动端浏览器可能限制自动播放打赏浮层出现时如果视频暂停用户体验会割裂建议浮层出现时不暂停视频只覆盖半屏。3.2 防刷打赏频率限制、金额校验与黑名单没有防刷的打赏系统上线当天就会被羊毛党盯上。最常见的攻击方式是用脚本批量注册账号每个账号打赏 0.01 元刷代理佣金。防御手段分三层第一层同一用户 ID 打赏间隔不少于 10 秒用 Redis 的SETNX加过期时间实现第二层单笔打赏金额最低 1 元低于 1 元直接拒绝因为支付通道手续费可能都不止第三层同一 IP 注册账号数超过 5 个禁止打赏这个在注册时就要限制。// 打赏频率限制10 秒内同一用户只能打赏一次 $redis new Redis(); $redis-connect(127.0.0.1, 6379); $key reward_limit: . $userId; if (!$redis-set($key, 1, [nx, ex 10])) { exit(json_encode([code 429, msg 操作太频繁请稍后再试])); } // 继续后续打赏逻辑set的nx表示 key 不存在时才设置ex是过期秒数。如果返回 false说明 10 秒内已经打过赏。这个逻辑要放在创建订单之前而不是支付回调里否则用户频繁创建订单但不支付也会拖垮数据库。另外黑名单表blacklist要支持按用户 ID、IP、设备指纹三个维度封禁封禁后前端直接隐藏打赏按钮后端接口也返回 403。3.3 打赏记录的实时推送与对账文件生成用户打赏成功后前端需要立即看到“打赏成功”提示和排行榜更新。如果只靠轮询延迟高且费服务器。我一般用 WebSocket 或 SSE 推送。PHP 环境下Workerman 是比较常见的选择。打赏成功后在支付回调里向 Workerman 推送一条消息Workerman 再广播给对应房间的所有客户端。对账方面每天凌晨生成前一天的order表和支付通道账单的对比文件重点核对三个字段订单号、金额、状态。差异记录写入reconcile_diff表人工介入。不要小看对账双支付系统最容易出的问题就是“微信显示成功本地显示未支付”没有对账文件你根本不知道丢了多少钱。4. 避坑与排查代理分账、回调、数据库的五个血泪教训4.1 现象代理佣金重复到账提现时余额多了一倍原因支付回调没有做幂等微信重复通知时每次都对commission_log插入新记录且没有唯一索引约束。解决在commission_log表上建唯一索引UNIQUE KEY order_agent (order_id, agent_id)插入时用INSERT IGNORE或ON DUPLICATE KEY UPDATE。同时订单表status更新要加AND status0条件影响行数为 0 说明已处理过直接返回成功。4.2 现象支付宝回调偶尔收不到订单一直未支付原因支付宝异步通知要求返回纯文本success如果 PHP 文件有 BOM 头或额外输出支付宝会认为通知失败并重试重试几次后不再通知。解决检查notify_alipay.php文件编码为 UTF-8 无 BOM且?php前不能有任何空格或换行。处理完业务后echo success; exit;不要输出 JSON 或 HTML。4.3 现象代理提现时余额扣成负数平台垫钱原因提现逻辑先查余额再扣减但两个操作之间没有加锁代理同时发起两笔提现都查到足够余额都扣成功。解决用数据库行锁SELECT ... FOR UPDATE或 Redis 分布式锁。我一般用UPDATE agent SET balance balance - ? WHERE id ? AND balance ?根据影响行数判断是否扣减成功影响行数为 0 说明余额不足。4.4 现象视频打赏按钮在 iOS 上点击无反应原因iOS Safari 对click事件在video标签上的冒泡处理有差异且如果打赏按钮是绝对定位覆盖在视频上z-index不够或父元素有pointer-events: none。解决给打赏按钮单独设置z-index: 9999并确保父元素没有pointer-events: none。如果还是不行改用touchstart事件并preventDefault。4.5 现象数据库连接数暴涨页面 502原因每个支付回调都新建数据库连接且没有及时关闭或者用了pconnect长连接但 PHP-FPM 进程数配置过高。解决检查代码里是否用了new PDO后没有置空建议用单例模式封装数据库连接。同时调整php-fpm.conf的pm.max_children根据内存计算一般 2GB 内存的服务器设 20-30 即可。不要盲目调大否则 MySQL 先崩。5. 进阶技巧用对账脚本反推支付通道的“掉单率”并自动补单最后一章不讲虚的讲一个我实际用了两年的技巧用对账脚本自动补单。双支付系统最怕掉单用户付了钱但回调没来订单一直是未支付。常规做法是人工查支付平台账单手动补。但你可以写一个脚本每天凌晨拉取微信和支付宝的对账单和本地orders表比对找出“支付平台成功但本地未支付”的订单自动调用内部补单接口把订单状态改为已支付并补发代理佣金。// reconcile.php 核心逻辑拉取微信账单比对本地订单 $bill $wechatPay-downloadBill(date(Ymd, strtotime(-1 day))); foreach ($bill as $row) { $outTradeNo $row[out_trade_no]; $order $db-get(orders, *, [out_trade_no $outTradeNo]); if ($order $order[status] 0) { // 支付平台成功但本地未支付触发补单 $db-action(function($db) use ($order, $row) { $db-update(orders, [status 1, pay_time strtotime($row[time_end])], [id $order[id]]); // 补发代理佣金注意幂等 $db-insert(commission_log, [ order_id $order[id], agent_id $order[agent_id], amount $order[price] * $order[agent_rate], created_at time() ], IGNORE); }); // 记录补单日志方便后续审计 file_put_contents(/tmp/reconcile_fix.log, date(Y-m-d H:i:s) . fixed order: {$outTradeNo}\n, FILE_APPEND); } }这段代码的关键参数downloadBill的日期是前一天因为当天账单可能不完整commission_log插入用IGNORE防止重复补单日志必须写否则你永远不知道系统自动补了多少单。运行一段时间后你可以统计补单率如果超过 0.5%说明回调接口不稳定需要检查服务器网络或支付通道配置。我一般会把这个脚本放在 crontab 每天凌晨 3 点执行执行完发一封邮件给自己邮件里包含补单数量和总金额。这个习惯帮我发现过一次微信回调域名被误封及时换了备用域名避免了更大损失。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →