PHP项目怎么实现分销系统?

wen java案例 3

PHP项目如何实现分销系统?从零搭建多级分销架构的完整指南

📖 目录导读

  1. 分销系统核心概念与业务逻辑
  2. 数据库表结构设计(关键)
  3. PHP分销算法实现(佣金计算与层级关系)
  4. 用户绑定与关系链追踪方案
  5. 订单分账与结算系统开发
  6. 防止刷单与风控机制
  7. 高频问答汇总

分销系统核心概念与业务逻辑

在PHP项目中实现分销系统,本质上是构建一个基于用户关系的利益分配网络,最常见的模式是多级分销(MLM),但需要注意合规性(国内法律限制三级以内)。

PHP项目怎么实现分销系统?

核心业务逻辑

  • 用户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 + 注册落表

流程

  1. 用户A的推广链接:https://yourdomain.com/register?invite=uid_123
  2. 用户B点击链接后:
    • PHP检测 $_GET['invite'] 参数
    • 将该参数写入Cookie(setcookie('inviter', 123, time()+86400*7))
    • 页面显示“您由用户A推荐”
  3. 用户B注册时:
    • 从Cookie读取 inviter
    • 插入 user_relation 表(user_id=B, parent_id=A, level=1
    • 同时更新A的 pathA的path + ',' + B的id

防篡改方案

// 生成邀请码(含签名)
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进程),避免影响主业务流程。

抱歉,评论功能暂时关闭!