简介这是一套基于PHP开发的代理分销型商城系统面向中小型电商企业、创业团队及PHP学习者解决多级代理管理、佣金自动结算与分销渠道拓展等核心运营需求。系统采用MVC架构前后端功能完备前端支持用户注册登录、商品展示、购物车与订单全流程后端涵盖商品管理、代理审核与等级设定、订单履约、数据统计及第三方支付支付宝/微信与物流接口集成。资源包为11.5MB的RAR压缩文件含完整可运行代码主要包含PHP业务逻辑文件、MySQL数据库脚本、HTML/CSS/JS前端页面及配置文档结构清晰便于二次开发与功能定制。目前已有1349人学习下载读者可直接部署调试深入理解电商分销模型实现、PHP安全防护防SQL注入/XSS、佣金计算逻辑及高复用模块设计思路。1. 这不是个“代理后台”而是一套能跑通三级分润、自动结算、实时查佣的 PHP 商城分销闭环系统你手上有款自营商品想让朋友帮你卖但又怕对账扯皮、佣金算错、下级代理拉人没动力——别急着写 Excel 表格或手动打款。这个 PHP 代理分销系统从注册即生成专属推广链接、下单自动绑定上级、订单完成触发多级分润计算支持一级、二级、三级到后台实时查看各级代理的团队规模、成交额、待结佣金、已提现记录全部走完完整业务流。它不依赖 SaaS 平台代码全开源数据库结构清晰核心逻辑集中在app/Logic/Commission.php和app/Model/Agent.php里没有黑匣子调用也没有隐藏的第三方服务钩子。适合中小团队快速部署一个可控、可审计、能二次开发的分销底座尤其适合已有 PHP 技术栈、想把分销模块嵌入现有商城的开发者。如果你正卡在“怎么让代理关系链自动建模”“怎么避免重复结算”“怎么让下级代理看到自己能赚多少”这三个问题上这个项目就是为解这三道题写的。2. 环境准备与一键部署从 Nginx PHP 7.4 到后台可登录的完整路径2.1 基础运行环境PHP 版本、扩展与目录权限硬性要求该项目基于 Laravel 8.x 框架封装非原生 PHP 写就因此必须满足 Laravel 的底层约束。常见翻车点在于 PHP 版本和扩展缺失——它不兼容 PHP 8.0实测 PHP 7.4.33 是最稳版本PHP 扩展中mbstring、openssl、pdo_mysql、tokenizer、xml、ctype、json必须启用缺一不可。特别注意bcmath扩展分润计算中所有金额运算如 0.01 × 0.15都强制使用bcadd()/bcmul()若未开启会导致佣金归零。Nginx 配置需启用try_files $uri $uri/ /index.php?$query_string;不能简单用 Apache 的.htaccess替代。部署时 Web 根目录必须指向public/而非项目根目录否则路由全部 404。# 检查 PHP 环境是否达标执行后应无报错且返回版本号 php -v php -m | grep -E (mbstring|openssl|pdo_mysql|tokenizer|xml|ctype|json|bcmath)提示若用宝塔面板PHP 设置页中「禁用函数」列表里务必删掉putenv和pcntl_exec——Laravel 的 Artisan 命令行工具依赖它们否则php artisan migrate会静默失败。2.2 数据库初始化表结构设计意图与关键字段说明项目使用 MySQL 5.7共 12 张核心表其中agents代理主表、agent_relations上下级关系表、orders订单主表、commission_logs分润流水表四张是业务心脏。agent_relations表采用「单向父子」设计每条记录存parent_id和child_id并带level字段值为 1/2/3不冗余存储整条关系链靠递归查询构建团队树。commission_logs表中type字段区分order_settle订单结算、withdraw_apply提现申请、withdraw_success提现成功三类动作status字段控制状态机流转0待处理1已完成2已驳回这是后续做财务对账的唯一可信源。-- 创建代理关系表关键联合索引加速上级查下级、下级查上级双向查询 CREATE TABLE agent_relations ( id bigint unsigned NOT NULL AUTO_INCREMENT, parent_id bigint unsigned NOT NULL COMMENT 上级代理ID, child_id bigint unsigned NOT NULL COMMENT 下级代理ID, level tinyint unsigned NOT NULL DEFAULT 1 COMMENT 层级1直推2间推3再间推, created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_parent_child (parent_id,child_id), KEY idx_child (child_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;2.3 安装流程五步走完从解压到登录后台上传并解压将源码包上传至服务器/var/www/distribution/确保storage/和bootstrap/cache/目录可写chmod -R 775 storage bootstrap/cache配置.env复制.env.example为.env修改DB_DATABASE、DB_USERNAME、DB_PASSWORD关键一步设置APP_URLhttp://your-domain.com必须带协议和域名不能是 localhost否则推广链接生成异常安装依赖在项目根目录执行composer install --no-dev --optimize-autoloader跳过 dev 包减少体积执行迁移php artisan migrate --force--force是必须参数生产环境默认禁止生成密钥 清缓存php artisan key:generate php artisan config:clear php artisan cache:clear完成后访问http://your-domain.com/admin/login初始账号密码均为admin / admin123首次登录后强制修改。3. 核心模块拆解分润引擎、代理关系链、推广链接生成三大主干逻辑3.1 分润引擎Commission::calculateForOrder()如何保证金额不溢出、不漏算分润不是简单乘法而是带规则的条件计算。核心方法位于app/Logic/Commission.php入口是calculateForOrder(Order $order)。它接收一个订单对象返回一个Collection每项含agent_id、amount、level、rule_key。关键设计有三点精度控制所有金额以「分」为单位存入数据库orders.total_amount是整数计算时先转元再乘比例最后round(bcmul($base, $rate, 2), 0)回到分避免浮点误差累积层级穿透按agent_relations表反查该订单买家的全部上级但只取 level ≤ 3 的记录并去重防止 A→B→C→D 中 C 同时是 A 的二级和 B 的一级被重复计规则隔离不同商品类目可配置不同分润率$order-product-category-commission_rate优先于全局默认率且支持「满 1000 元额外加 1%」这类阶梯规则由CommissionRuleManager类动态加载。// app/Logic/Commission.php 节选核心计算片段 public function calculateForOrder(Order $order): Collection { $buyerId $order-user_id; // 1. 反查 buyer 的所有上级代理含层级 $uplines DB::table(agent_relations) -where(child_id, $buyerId) -where(level, , 3) -get([parent_id, level]); return $uplines-map(function ($upline) use ($order) { $rate $this-getEffectiveRate($order, $upline-level); $baseAmount bcmul((string)$order-total_amount, 0.01, 2); // 转元 $amountInCents round(bcmul($baseAmount, $rate, 2), 0) * 100; // 转回分 return (object)[ agent_id $upline-parent_id, amount (int)$amountInCents, level $upline-level, rule_key $this-currentRuleKey ]; }); }注意$amountInCents必须是整数类型因为数据库字段是BIGINT若传 float 会触发 MySQL 截断导致分润变 0。3.2 代理关系链Agent::buildTeamTree()怎么高效查出三级团队结构前端「我的团队」页面要展示我A→ 直推 5 人 → 每人再推若干 → 最多展开到三级。如果每次请求都递归查 3 层MySQL 会瞬间变慢。本项目采用「预生成 缓存」策略当新代理注册并绑定上级时触发Agent::syncTeamAncestors()将该代理的所有祖先最多 3 级写入agent_ancestors表结构agent_id,ancestor_id,distance。查团队时只需一条 JOINSELECT u.*, a.distance FROM users u JOIN agent_ancestors a ON u.id a.agent_id WHERE a.ancestor_id ? AND a.distance 3 ORDER BY a.distance, u.created_at;agent_ancestors表在代理注册、上级变更、关系删除时由 Observer 自动维护避免运行时计算开销。这也是为什么项目要求 MySQL 5.7——需要窗口函数支持ROW_NUMBER()做距离去重。3.3 推广链接生成ShareLinkGenerator::make()如何防刷、防篡改、带来源追踪每个代理的推广链接形如https://yoursite.com/register?refabc123其中ref参数不是代理 ID而是加密字符串。生成逻辑在app/Services/ShareLinkGenerator.php使用hash_hmac(sha256, $agentId . $timestamp, config(app.key))生成签名将$agentId、$timestamp、$signature三者拼接后 base64url 编码非标准 base64/替换为-_链接过期时间设为 7 天解码后校验 timestamp 是否超时、signature 是否匹配任一失败则拒绝注册。这样设计杜绝了「手动改 ref 参数绑定任意上级」的漏洞也避免了代理 ID 泄露带来的信息风险。4. 避坑指南上线前必须验证的 4 个致命细节4.1 现象后台显示「今日新增代理 0」但实际有用户通过推广链接注册原因.env中APP_URL未配置为真实域名或 Nginx 未透传X-Forwarded-Proto头导致URL::full()生成的注册链接是http://localhost/register?refxxx用户点击后跳转失败前端 JS 捕获不到 ref 参数。解决确认APP_URL为https://your-domain.com并在 Nginx 配置中加入proxy_set_header X-Forwarded-Proto $scheme;。4.2 现象订单完成但commission_logs表无记录代理后台「待结算佣金」始终为 0原因订单状态变更事件未正确触发。项目监听OrderStatusUpdated事件但默认队列驱动为sync同步执行若APP_DEBUGfalse且日志级别设为error事件内异常会被静默吞掉。解决临时切到database队列.env中设QUEUE_CONNECTIONdatabase运行php artisan queue:work --once观察failed_jobs表是否有报错或打开APP_DEBUGtrue查看具体异常。4.3 现象代理 A 推荐 BB 又推荐 C但 C 下单后A 的二级分润未到账原因agent_relations表中缺少 A→C 的 level2 记录。系统只在 B 注册时自动生成 A→Blevel1但不会自动补全 A→Clevel2需靠Agent::syncTeamAncestors()在 C 注册时补全。若该方法未被调用如注册流程绕过AgentRegisterService关系链就断了。解决检查注册控制器是否调用AgentRegisterService::handle($request)或手动执行php artisan agent:sync-ancestors补全历史数据。4.4 现象提现申请提交后状态卡在「审核中」财务后台无通知原因提现审核依赖App\Observers\WithdrawalObserver但该 Observer 未在AppServiceProvider::boot()中注册或withdrawals表的status字段默认值为pending但 Observer 的updating方法只监听status从pending变更为approved/rejected若数据库默认值写错如写成processing事件不触发。解决确认withdrawals.status默认值为pending并在AppServiceProvider中添加Withdrawal::observe(WithdrawalObserver::class);。5. 二次开发实战如何接入微信支付回调、增加邀请返现、导出代理业绩 Excel5.1 接入微信支付回调复用现有订单模型只改三处微信支付成功后会 POST 通知到你的notify_url。本项目已预留/api/payment/wechat/notify路由但控制器空实现。你需要在app/Http/Controllers/Api/Payment/WechatNotifyController.php中解析微信 XML 回调校验签名根据out_trade_no查orders表确认订单存在且status unpaid调用OrderService::markAsPaid($order, wechat)—— 此方法内部会触发OrderStatusUpdated事件自动完成分润结算。// app/Services/OrderService.php 中补充 public function markAsPaid(Order $order, string $channel): void { DB::transaction(function () use ($order, $channel) { $order-update([ status paid, paid_at now(), payment_channel $channel ]); // 关键触发事件让 Commission 逻辑自动跑 event(new OrderStatusUpdated($order, unpaid, paid)); }); }提示微信回调地址必须在微信商户平台配置为https://your-domain.com/api/payment/wechat/notify且域名需备案。测试时用「微信支付沙箱环境」避免真金白银扣款。5.2 增加邀请返现在注册流程中插入现金奖励逻辑需求新用户通过代理链接注册除建立代理关系外再给邀请人上级发 5 元现金红包。不走分润池单独记账。新增表invitation_bonusesid,inviter_id,invitee_id,amount_cents,status,created_at在AgentRegisterService::handle()的末尾添加if ($referrerId) { DB::table(invitation_bonuses)-insert([ inviter_id $referrerId, invitee_id $user-id, amount_cents 500, // 5元500分 status pending, created_at now() ]); // 同时更新 inviter 的 wallet_balance 字段需提前在 users 表加此字段 DB::table(users)-where(id, $referrerId)-increment(wallet_balance, 500); }5.3 导出代理业绩 Excel用 PhpSpreadsheet 替换原生 CSV原项目导出用fputcsv格式简陋。升级为 Excel 需composer require phpoffice/phpspreadsheet新建app/Exports/AgentPerformanceExport.php继承Maatwebsite\Excel\Concerns\FromCollection在导出控制器中调用Excel::download(new AgentPerformanceExport($agentId), agent-performance.xlsx)。关键点AgentPerformanceExport的collection()方法应返回一个包含name,team_size,total_orders,total_commission的集合数据来自联表查询而非多次 DB 请求。// app/Exports/AgentPerformanceExport.php public function collection() { return DB::table(agents) -select( users.name, DB::raw(COUNT(DISTINCT ar2.child_id) as team_size), DB::raw(COUNT(DISTINCT o.id) as total_orders), DB::raw(SUM(cl.amount) as total_commission) ) -join(users, agents.user_id, , users.id) -leftJoin(agent_relations as ar1, agents.user_id, , ar1.parent_id) -leftJoin(agent_relations as ar2, ar1.child_id, , ar2.parent_id) -leftJoin(orders as o, ar2.child_id, , o.user_id) -leftJoin(commission_logs as cl, ar2.child_id, , cl.agent_id) -where(agents.user_id, $this-agentId) -groupBy(users.name) -get(); }从那以后我每次接手分销类项目都会先翻app/Logic/Commission.php和database/migrations/*commission*迁移文件确认分润精度处理、关系链存储方式、事件触发时机这三点是否对齐业务需求。哪怕只是加个「满 1000 返 50」的活动我也强制走一遍php artisan tinker手动调用Commission::calculateForOrder()打印出每级金额盯着小数点后两位——这比写十遍单元测试更能暴露浮点陷阱。希望帮到你。本文还有配套的精品资源点击获取