PHP项目如何实现分销系统?从零搭建多级分销架构的完整指南
📖 目录导读
分销系统核心概念与业务逻辑
在PHP项目中实现分销系统,本质上是构建一个基于用户关系的利益分配网络,最常见的模式是多级分销(MLM),但需要注意合规性(国内法律限制三级以内)。

核心业务逻辑:
- 用户A分享推广链接给用户B
- 用户B注册并下单
- 系统根据预设规则,将佣金分给用户A(以及可能的上级A1、A2)
- 佣金记录进入账户余额,支持提现
💡 :推广链路、佣金比例、分账周期、结算门槛
数据库表结构设计(关键)
合理的表结构是分销系统稳定的基础,以下是5张核心表:
用户关系表 user_relation
CREATE TABLE `user_relation` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '用户ID', `parent_id` int(11) DEFAULT NULL COMMENT '上级推荐人ID', `level` tinyint(4) DEFAULT '1' COMMENT '层级深度(1-3)', `path` varchar(255) DEFAULT NULL COMMENT '关系路径,如1,5,12', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `parent_id` (`parent_id`), KEY `path` (`path`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
佣金配置表 commission_config
CREATE TABLE `commission_config` ( `id` int(11) NOT NULL AUTO_INCREMENT, `level` tinyint(4) NOT NULL COMMENT '分销层级', `rate` decimal(5,2) NOT NULL COMMENT '佣金比例(如15.00表示15%)', `status` tinyint(1) DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
佣金记录表 commission_log
CREATE TABLE `commission_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order_id` int(11) NOT NULL, `from_user_id` int(11) NOT NULL COMMENT '下单用户', `to_user_id` int(11) NOT NULL COMMENT '获得佣金用户', `level` tinyint(4) NOT NULL COMMENT '当前层级', `amount` decimal(10,2) NOT NULL COMMENT '佣金金额', `status` tinyint(1) DEFAULT '0' COMMENT '0待结算 1已结算', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
设计要点:
- 使用
path字段实现快速查询所有下级(LIKE '1,%') level字段限制最大层级,避免无限递归- 佣金配置与订单解耦,支持按商品独立设置
PHP分销算法实现(佣金计算与层级关系)
核心算法:递归找上级
<?php
class DistributionService
{
private $db;
private $maxLevel = 3; // 最大分销层级
/**
* 计算订单佣金
* @param int $orderUserId 下单用户ID
* @param float $orderAmount 订单金额
* @param int $orderId 订单ID
*/
public function calculateCommission($orderUserId, $orderAmount, $orderId)
{
// 1. 获取下单用户的上级链路
$parents = $this->getParentChain($orderUserId);
// 2. 获取佣金配置
$configs = $this->db->query("SELECT * FROM commission_config WHERE status=1 ORDER BY level ASC");
$configMap = [];
foreach ($configs as $cfg) {
$configMap[$cfg['level']] = $cfg['rate'];
}
// 3. 逐级计算佣金(最多3级)
$level = 1;
foreach ($parents as $parentId) {
if ($level > $this->maxLevel) break;
if (!isset($configMap[$level])) break;
$rate = $configMap[$level];
$commissionAmount = round($orderAmount * $rate / 100, 2);
// 插入佣金记录
$this->db->insert('commission_log', [
'order_id' => $orderId,
'from_user_id' => $orderUserId,
'to_user_id' => $parentId,
'level' => $level,
'amount' => $commissionAmount,
'status' => 0
]);
$level++;
}
}
/**
* 获取上级链路(从近到远)
*/
private function getParentChain($userId)
{
$chain = [];
$current = $userId;
while (true) {
$parent = $this->db->getOne("SELECT parent_id FROM user_relation WHERE user_id=?", [$current]);
if (!$parent || $parent['parent_id'] == 0) break;
$chain[] = $parent['parent_id'];
$current = $parent['parent_id'];
if (count($chain) >= $this->maxLevel) break;
}
return $chain;
}
}
算法优化技巧:
- 使用
while循环代替递归函数,避免深度递归导致内存溢出 - 将佣金配置缓存到Redis,减少数据库查询
- 采用延迟结算(订单确认收货后触发)
用户绑定与关系链追踪方案
推荐实现:URL参数 + Cookie + 注册落表
流程:
- 用户A的推广链接:
https://yourdomain.com/register?invite=uid_123 - 用户B点击链接后:
- PHP检测
$_GET['invite']参数 - 将该参数写入Cookie(
setcookie('inviter', 123, time()+86400*7)) - 页面显示“您由用户A推荐”
- PHP检测
- 用户B注册时:
- 从Cookie读取
inviter值 - 插入
user_relation表(user_id=B, parent_id=A, level=1) - 同时更新A的
path为A的path + ',' + B的id
- 从Cookie读取
防篡改方案:
// 生成邀请码(含签名)
function generateInviteCode($userId) {
$secret = 'your_secret_key';
$token = md5($userId . $secret);
return base64_encode($userId . '|' . $token);
}
// 验证邀请码
function verifyInviteCode($code) {
$decoded = base64_decode($code);
list($userId, $token) = explode('|', $decoded);
if (md5($userId . 'your_secret_key') !== $token) return false;
return $userId;
}
订单分账与结算系统开发
分账时机(推荐:确认收货后)
// 订单状态变更事件监听
public function onOrderCompleted($orderId) {
$order = $this->db->getOne("SELECT user_id, total_amount FROM orders WHERE id=?", [$orderId]);
// 启动事务
$this->db->beginTransaction();
try {
// 计算佣金
$this->calculateCommission($order['user_id'], $order['total_amount'], $orderId);
// 更新订单分账状态
$this->db->update('orders', ['distribution_status' => 1], ['id' => $orderId]);
$this->db->commit();
} catch (Exception $e) {
$this->db->rollback();
// 记录错误到日志
}
}
提现模块关键字段
user_balance:用户余额表,包含frozen_amount(冻结中)和available_amount(可提现)withdraw_log:提现记录,审批流
注意:佣金状态从 0待结算 -> 1已结算 -> 增加用户余额,提现需要人工审核。
防止刷单与风控机制
| 风险类型 | 解决方案 |
|---|---|
| 自己注册小号刷佣金 | 同一IP/设备注册限制,实名认证 |
| 虚假订单 | 订单必须支付成功后才计算佣金 |
| 恶意退款 | 退款时自动扣除已发佣金(回滚机制) |
| 层级过深 | 硬限制 level <= 3,后端校验 |
代码示例 - 退款扣佣:
public function refundCommission($orderId) {
$commissions = $this->db->getAll("SELECT * FROM commission_log WHERE order_id=? AND status=1", [$orderId]);
foreach ($commissions as $item) {
// 扣除用户余额
$this->db->update('user_balance',
"available_amount = available_amount - ?",
[$item['amount'], $item['to_user_id']]
);
// 更新状态
$this->db->update('commission_log', ['status' => -1], ['id' => $item['id']]);
}
}
高频问答汇总
Q1:分销系统最多支持几级?法律上有风险吗?
A:国内电商平台建议控制在三级以内(包含三级),超过三级可能涉及传销风险,建议只设两级分销(直接推荐+间接推荐),或采用团队计酬模式(按业绩计算,而非拉人头)。
Q2:佣金计算时如何避免浮点数精度问题?
A:使用 round() 函数保留两位小数,或者改用 整型存储(单位:分)。$amount = (int)($orderAmount * $rate / 100),显示时再除以100。
Q3:用户关系链很长,查询下级性能差怎么办?
A:采用路径枚举法(path 字段存储完整祖先ID链),查询“所有下级”时直接使用 WHERE path LIKE '1,5,%',如果数据量超过百万级,推荐使用 Redis 有序集合 维护关系树。
Q4:分销系统是否应该实时结算佣金?
A:不建议,推荐延迟结算,触发条件可以为:
- 订单确认收货(7天无理由退货期后)
- 手动批量结算(后台控制)
- 达到最低提现金额后统一结算
Q5:如何实现跨商品的分销比例不同?
A:在 order_items 表增加 commission_rate 字段,或者在商品表中增加 is_distribution 字段,佣金计算时按商品行计算,而非按订单总额。
Q6:用户退出后,之前绑定的关系是否失效?
A:不应失效,用户关系一旦建立,永久生效,可以在用户注销时,将其推广收益冻结,但不影响历史佣金。
PHP实现分销系统,关键在于合理的数据表设计、高效的佣金计算算法以及严格的风控措施,多级分销请务必遵守法规,控制层级在3级以内,对于高并发场景(如秒杀分销),建议将佣金计算异步化(Redis队列+Worker进程),避免影响主业务流程。