ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

H5商城源码实战:PHP+易支付+MySQL打造轻量在线支付商城

H5商城源码实战:PHP+易支付+MySQL打造轻量在线支付商城 经常有人问我都2025年了还有必要折腾H5商城吗我的回答是——看场景。如果你只是想快速验证一个卖货想法、给公众号或者个人站点配一个下单入口、或者给客户交付一套“商品展示在线支付”的轻量方案那么一套结构清晰、带支付接口的H5迷你商城源码依然是最省力的选择。它不需要过应用商店审核不需要写两套客户端手机浏览器一开就能用。这套项目核心就是三个字轻、全、通。前端是移动端适配的H5页面后端是PHP写的标准MVC结构数据库用MySQL支付环节直接对接易支付接口一套下来从商品上架、购物车、下单支付到后台订单管理流程完整能跑通。尤其适合个人开发者、小团队和自由职业者拿来二次开发或者直接上线。下面我从设计思路、模块拆解、支付对接、部署运维到二次开发把整套东西的细节都摊开讲清楚。1. 整体设计思路为什么是H5 PHP 易支付1.1 H5形态解决的是“触达”问题选H5而不是小程序或者原生App最核心的原因就是触达成本低。用户点开你发的链接就能进商城不用下载App、不用跳转小程序在微信里聊着天就能把东西买了。对于一个迷你商城来说转化路径短一厘米订单量可能就差一个量级。从技术角度看H5商城还有一个隐藏优势跨端一致性。一套代码iOS Safari、安卓浏览器、微信内置浏览器、PC浏览器都能跑只是内核差异带来一些样式微调不需要像小程序那样考虑平台规则差异。当然代价也有比如微信内置浏览器里部分支付能力受限这个我在第三节讲支付对接时会详细说怎么处理。1.2 PHP后端最契合“小而快”的诉求后端选PHP不是因为它技术最先进而是因为它对这个小项目来说效率最高。PHP天然就是为Web而生的语言每次请求独立执行、生命周期短、部署简单配宝塔面板或者LNMP环境几分钟就能跑起来。在迷你商城这种并发不高的场景下PHP的IO模型完全够用强行上Go或者Java只会在开发效率上吃亏。目录结构上这套源码按函数模块拆分了文件我习惯是/ ├── index.php # 商城首页入口 ├── api/ # 小程序/H5接口层 ├── admin/ # 管理后台 ├── includes/ # 公共函数与数据库连接 ├── payment/ # 支付接口封装 └── templates/ # 前端模板这种扁平化结构的好处是你自己加一个功能模块时知道该往哪里放不用在一堆框架目录里迷路。1.3 易支付接口的本质把多种支付通道收敛成一套HTTP API易支付Epay并不是某一家公司的专有产品而是支付接口聚合模式的一种通用叫法。它做的事情很简单把微信、支付宝等不同支付通道的API再封装一层对外暴露统一的HTTP接口开发者只需要按照约定拼参数、做签名、发请求、处理回调就能完成收款通知的整个闭环。为什么要接这种中间层而不是直接对接原生支付接口因为原生支付通道对商户资质、企业认证、开发流程的要求都比较重个人开发者和小团队往往走不通。易支付这类聚合接口的价值在于把复杂度吸收掉了一大半让你专注在业务层。而且它的对接模式延续了原生支付的核心思路——预下单、请求签名、异步通知验签——学好这套逻辑以后接什么支付接口都是类似套路。2. 功能模块拆解商品、订单、用户三条主线2.1 商品模块别在最基础的环节偷懒商品模块是商城的脸面。这套源码里商品表的核心字段包括商品ID、分类ID、标题、主图、轮播图、价格、原价、库存、销量、详情描述、上下架状态。从实战看有四个细节很容易踩坑。第一个是价格字段。建议数据库里用整数类型存储“分”而不是浮点数比如19.99元存成1999。为什么因为浮点数在计算和比较时会有精度误差下单金额算错了是会出大问题的。PHP里可以用intval($price * 100)做转换注意别用float直接比较。第二个是图片处理。迷你商城的商品主图建议统一压缩到 750px 宽度以内体积控制在200KB左右否则微信里首屏加载会非常慢。图片要支持多张轮播至少兼容jpg、png、webp三种格式。第三个是库存扣减逻辑。要在提交订单的事务里做UPDATE goods SET stock stock - 1 WHERE id ? AND stock 0这种原子操作而不是先查出来判断再更新否则并发场景下会超卖。第四个是列表分页。H5页面下拉加载用id lastId LIMIT 10这种游标分页最省事因为SKU商品量级一般就几百上千个游标分页能避免深分页的性能问题。2.2 订单流程状态机设计决定了后续扩展的余地订单模块是整个系统的核心脉络。这套源码的订单状态我建议这么设计状态值含义触发条件0待支付用户提交订单成功1已支付支付回调验签通过且金额匹配2已发货管理员在后台操作发货3已完成用户确认收货或超时自动完成-1已取消用户主动取消或超时未支付-2已退款管理员后台退款操作用户提交订单时生成唯一订单号out_trade_no这是支付系统对接的关键标识。订单号建议用date(YmdHis) . mt_rand(1000, 9999)保证同一秒内的并发也不重复。下单之后把订单信息连同跳转支付参数一起返回给前端前端拿到参数后引导用户跳转支付。订单和支付状态要保持双写一致。核心思路是以支付回调为准。回调确认成功订单状态才从待支付翻转为已支付。前端展示的轮询结果只能做辅助提示不能直接改库否则用户关闭支付页面、轮询没跑到就可能出现假死状态。2.3 用户体系免登录优先收货信息兜底迷你商城的用户体系不需要做的很重。我的建议是非强制登录即可浏览、加购物车下单时提供“手机号验证码”或微信授权登录。如果口袋里没有稳定的微信授权能力就退一步用openid作为用户唯一标识配合手填手机号。这套源码默认的方案就是用户第一次提交订单时要求填手机号生成 user 记录后续下单自动带出。后台管理我建议单独拆出管理员表不要跟普通用户混在一起。管理员的登录用 session 管理密码字段必须用password_hash()加密这是最低限度的安全底线。3. 易支付接口对接全流程签名、请求、回调3.1 参数签名MD5也能做得安全易支付的接口对接遵循一个很常见的模式业务参数 签名。也就是把请求参数按k按字母排序拼成查询字符串再加上你的商户密钥一起做MD5用于防止参数被篡改。这整套流程里签名算法长这样// 商户ID和密钥在易支付后台获取 $pid 10000; $key 你的商户密钥; // 拼接请求参数 $params [ pid $pid, type alipay, // 支付方式alipay / wxpay out_trade_no 202501011200001234, notify_url https://yourdomain.com/payment/notify.php, return_url https://yourdomain.com/payment/return.php, name 测试商品, money 199.00, sign_type MD5 ]; // 按key升序排序拼接为 url string ksort($params); $signStr urldecode(http_build_query($params)) . $key; $params[sign] md5($signStr); // 发起跳转支付 $payUrl https://pay.example.com/submit.php? . http_build_query($params); header(Location: . $payUrl);这里重点在urldecode(http_build_query($params))它会生成a1b2c3这种纯字符串再拼上密钥做MD5。注意不要漏掉urldecode因为http_build_query默认会对参数值做URL编码拼进去以后签名永远对不上。我见过不下五个人在这里卡了半天。签名验证的逻辑完全一致收到回调后把除sign和sign_type以外的所有参数排好序拼出来md5比对是否一致。验证通过再处理业务。3.2 发起支付与异步通知谁才是权威消息源支付跳转有两种方式一种是用header(Location)直接302跳转到易支付收银台另一种是把payUrl返回到前端用window.location.href跳转。迷你商城推荐后者前端跳转更可控还能在跳转前弹出“正在拉起收银台”的提示。这里有个经验易支付在微信内置浏览器里跳支付宝会比较尴尬微信会拦截外部支付链接。做H5商城时我的常规处理是如果typealipay就让用户“点击右上角在浏览器中打开”或者干脆根据 UA 判断——如果User-Agent包含MicroMessenger默认引导走复制链接到外部浏览器。这个逻辑很值得写进支付模块里线上效果立竿见影。真正的支付结果权威来源是异步通知也就是notify_url。流程是这样的用户支付完成后易支付服务器向notify_url发起GET请求携带订单号、金额、trade_status、sign等参数服务器收到后验签、校验金额、校验订单号然后更新订单状态并返回字符串success告知易支付不要再重复回调。3.3 回调处理的幂等和安全防护回调处理这套代码是支付模块里最值得认真写的地方。直接上简化代码// notify.php $data $_GET; $sign $data[sign] ?? ; unset($data[sign], $data[sign_type]); if (md5Sign($data) ! $sign) { die(fail); // 验签失败绝不继续 } $orderNo $data[out_trade_no]; $money $data[money]; $status $data[trade_status]; // 查询订单 $order $db-find(SELECT * FROM orders WHERE out_trade_no ?, [$orderNo]); if (!$order) { die(fail); // 订单不存在 } // 金额校验数据库存的是分回调传的是元 if (PayHelper::yuanToFen($money) ! $order[amount]) { die(fail); // 金额不一致可能被篡改 } // 幂等处理订单已经是已支付状态直接返回success if (intval($order[status]) 1) { die(success); } // 更新订单状态 扣减库存 记录支付流水放在事务里 $db-transaction(function () use ($db, $orderNo) { $db-exec(UPDATE orders SET status 1, paid_at NOW() WHERE out_trade_no ?, [$orderNo]); $db-exec(UPDATE goods SET stock stock - 1 WHERE id ?, [$order[goods_id]]); }); die(success);这段代码有三个关键点第一是幂等。即使易支付因网络原因重复回调了十次订单状态是已支付后直接返回success不会第二次扣库存。第二是以回调为准。前端轮询、用户手动刷新页面看到的支付状态都应该以数据库的status为准而不是依赖用户浏览器里的session状态。第三是返回success必须原样输出且不输出任何多余字符。如果输出内容夹杂了HTML标签易支付可能识别不到合法返回会继续回调造成更频繁的服务器压力。4. 部署上线与日常运维从源码到线上商城4.1 环境准备与部署步骤这套源码对运行环境要求极低只要是PHP 7.0以上MySQL 5.7以上配Nginx或Apache都行。我强烈建议国内云服务器上直接用宝塔面板装LNMP十几分钟就能把环境搭好。部署的具体步骤拆成清单准备一台云服务器最低1核1G就能跑并发不大的话绰绰有余。安装PHP 7.4、MySQL 5.7、Nginx开启伪静态配置。创建数据库导入源码目录下的database.sql。修改includes/config.php填写数据库名、账号、密码以及易支付的商户ID和密钥。把源码上传到站点根目录设置运行目录为/站点使用HTTPS免费证书即可。到易支付平台后台把notify_url和return_url配置成你自己的域名地址。部署完成后先下个1元测试商品跑一遍真实支付这是验证支付链路最简单可靠的方式。4.2 常见问题排查速查表下面是这套源码上线后最常遇到的一批问题我把排查思路整理成一张速查表现象排查方向解决方案页面加载空白检查PHP错误日志、模板路径开启display_errors临时排查确认templates目录可读商品图片加载不出来检查图片路径/OSS域名图片地址要写绝对完整URL含http(s)://点击支付没反应检查跳转URL是否被拦截、UA判断用浏览器开发者工具观察Location响应确认外链正常可访问支付成功但订单未更新重点查notify_url是否外网可达服务器上用curl模拟get请求notify.php确认验签代码没有bug回调日志显示验签失败签名拼接顺序或密钥不对重新检查ksort、urldecode(http_build_query())拼接微信内打不开收银台外部浏览器跳转方案未实现增加UA判断提示用户用浏览器打开管理后台登录不上检查session配置、数据库连接确认PHP session目录可写检查config.php数据库密码排查支付问题有一个通用技巧在支付模块加入文件日志。每次发起支付和收到回调用file_put_contents记录一条带时间戳的日志线上出问题的时候翻日志定位比自己盲猜快一百倍。4.3 上线前的安全检查清单迷你商城虽然小安全底线不能省。我每次帮人部署这类系统必做四项检查改掉默认后台路径/admin换成不规则的目录名降低被扫描的风险。管理员密码强制用password_hash存储数据库泄露了也不能明文逆推。对所有查询用预处理PDO prepared statements防注入。支付宝/微信回调通知必须验签且对money、out_trade_no做校验。还有个小细节return_url只是用户支付完成后浏览器跳转的页面它不等同于支付成功凭证。很多新手会把业务逻辑写在里面这是不对的用户完全可以伪造这个跳转地址直接访问拿不到任何实际效果。所有支付成功的业务处理都必须放在notify.php异步回调里。5. 二次开发方向与我的实战体会5.1 这套源码最常见的改造方向验证跑通之后大多数人都会根据自己的业务做改造。从我接触过的案例看以下三个方向最热门加一个优惠券系统。在订单计算环节插入优惠券抵扣逻辑。需要新增coupon表面额、门槛、有效期、每人限领次数和user_coupon表领取记录、使用状态。下单时校验用户是否持有该券、是否满足金额门槛核销后锁定使用。接入分销裂变。在用户表加一个inviter_id支付成功后写一条分销记录把佣金以积分或者余额形式记入上级账户。注意分销体系的提现功能要格外设计好尤其是提现审核和流水记录否则财务对账会是一笔糊涂账。改成多商户模式。在前端增加店铺维度商品归属于商户订单按商户拆分结算。这个改造量就大了建议先理清数据模型再动手核心是给goods加merchant_id给订单加settle_status然后写商户端的结算模块。5.2 踩过几次坑之后的几点心里话这套H5迷你商城我从第一次部署到现在穿插着改造过不少版本最深的体会有三个。第一个是支付对接永远是第一优先级。商品、页面、用户都可以后续慢慢调但支付链路从第一天就必须端到端跑通。支付的逻辑看起来就那么几个参数真到线上环境https、外网可达、签名编码、重复回调一个问题叠一个问题最好预留一个下午专门调支付。第二个是数据库结构要先想清楚再写代码。迷你商城业务简单但订单、支付流水、商品库存这三张表的关联关系决定了后面所有功能的开发成本。比如想增加退款记录流水表的字段就至关重要——至少要有amount、type、order_no、created_at、status五个字段后面扩展时不需要回改表结构。第三个是H5商城的关键指标是转化率不是功能数量。微信里打开商品详情页2秒内能加载出首屏下单按钮永远在最顺手的位置支付引导没有多余的弹窗这比你在首页堆十个营销组件有用得多。商城是拿来卖货的每一个页面都在替你把用户往“付钱”这一步送。把链路精简到最短比任何花哨的功能都值钱。最后再分享一个小操作线上跑稳定以后把订单表按月归档不删数据只做冷热分离。这样后台查询历史订单依然很快数据库也不会一直膨胀。别问我为什么强调这个等你订单量上来、后台卡到怀疑人生的时候你会回来谢谢我的。
返回列表