
简介面向ECShop商城站长与二次开发者的码支付免签约插件解决商家在未与支付宝、微信、财付通逐一签约的前提下快速为商城接入三种主流扫码支付渠道的问题。资源包共21个文件以14个php文件承担支付发起、回调与验签等核心逻辑5个xml用于接口参数与配置定义另有1份txt使用说明和少量IDE辅助文件整体仅33KB轻量易部署。已有649人学习下载。压缩包内附使用说明txt能帮助开发者理清码支付与ECShop的整合流程同时针对gb2312与utf-8两种字符集环境提供了对应的回调处理版本可直接对照放置到ECShop相应目录缩短二次开发排错时间。集成后用户扫码即可完成交易显著提升商城支付转化率与运营效率适合需要免签约支付方案、希望低成本扩展移动支付场景的商户与技术人员使用。1. 个人站也能接 ECShop 码支付先搞清楚这份插件包能解决什么问题ECShop 老站想上支付宝、微信、财付通第一个拦路虎就是官方支付接口的资质门槛营业执照、对公账户、企业认证个人卖家和小团队根本走不通。所以“ecshop码支付”“ecshop免签约”这类需求这些年一直没断过——大家要的就是一个能把个人收款通道聚合起来、在后台装上就能用的 ECShop 插件。这份 zip 里装的正是这么一套东西把码支付网关封装成 ECShop 标准支付模块上传后后台直接出现“码支付”支付方式填商户 ID 和密钥就能收款。适合不想折腾官方签约、能接受第三方聚合结算的 ECShop 站长不大适合对资金安全极其敏感、单笔金额偏大的正规业务那种场景还是老老实实走官方渠道。2. 拆开插件包码支付接入 ECShop 的文件结构与回调链路先说结论ECShop 的支付插件并不是什么高深框架它就是一个约定目录下的 PHP 类文件 语言包。码支付这类第三方支付插件之所以“装了就能用”是因为它把网关请求、签名、回调处理全封装在了同一个类里ECShop 在结算页只需要调用你实现的几个方法。2.1 支付插件在 ECShop 里的位置与三个必备文件打开这份 zip解压后的目录结构基本是ecshop_codepay.zip ├── codepay.php # 码支付主支付类放 includes/modules/payment/ ├── languages/ │ └── zh_cn/ │ └── payment/ │ └── codepay.php # 后台显示用的语言包 └── readme.txt # 一般带签名规则和配置说明ECShop 扫描支付方式时会遍历includes/modules/payment/目录下所有符合规范的文件。主支付类必须继承base_payment并实现get_code()、respond()、callback()这几个方法。核心骨架长这样?php // includes/modules/payment/codepay.php if (!defined(IN_ECS)) { die(Hacking attempt); } $payment_lang ROOT_PATH . languages/ . basename($_SERVER[HTTP_ACCEPT_LANGUAGE]) . /payment/codepay.php; if (file_exists($payment_lang)) { global $_LANG; include_once($payment_lang); } class codepay extends base_payment { public $code codepay; // 唯一标识后台据此扫描 public $name 码支付; // 后台支付方式列表显示名 public $description 码支付集成支付宝、微信、财付通; public $configure array( array(name codepay_pid, value ), // 商户ID array(name codepay_key, value ), // 商户密钥 ); function get_code($order, $payment) { // 生成支付请求参数与签名返回跳转HTML或二维码地址 } function respond() { // 接收码支付异步通知验签后更新订单状态 } } ?需要拆开说明$code是后台“支付方式”列表里识别插件的唯一 key不能和别的插件重名$configure数组里的name对应后台配置表单的字段名value是默认值安装后由站长在后台填写。这里的get_code()负责在订单结算页生成一个支付请求respond()则是异步回调的入口——码支付服务器把支付结果 POST 回来时ECShop 会执行它。2.2 码支付免签约网关的支付请求与异步通知流程码支付的免签约本质是聚合第三方个人收款用户其实是在向码支付商户付款支付成功后由码支付服务端通知你的 ECShop 站点。完整链路分四步用户在 ECShop 结算页点击“码支付”ECShop 调get_code()组装下单参数。浏览器跳转到码支付收银台或直接展示二维码。用户扫码/确认支付钱进入码支付商户账户。码支付服务器异步 POST 通知 ECShop 的notify_urlECShop 执行respond()验签并修改订单状态。get_code()里最关键的参数拼接和签名生成常见写法是这样function get_code($order, $payment) { $pid $payment[codepay_pid]; $key $payment[codepay_key]; $orderid $order[order_sn]; $money $order[order_amount]; $notify_url return_url(basename(__FILE__, .php), notify); // 异步通知地址 $return_url return_url(basename(__FILE__, .php), return); // 同步跳转地址 $type 1; // 1支付宝 2微信 3财付通可由配置控制 // 常见签名规则MD5(pid orderid money key) $sign md5($pid . $orderid . $money . $key); $param array( pid $pid, type $type, orderid $orderid, money $money, notify_url $notify_url, return_url $return_url, sign $sign, ); // 拼接跳转收银台地址 $url https://codepay.example.com/pay? . http_build_query($param); return a href . $url . 去支付/a; }这段代码里$sign是签名串把商户 ID、订单号、金额、密钥按固定顺序拼接后 MD5。注意不同版本的码支付接口签名规则略有差异有的要先对参数名排序再拼接所以拿到插件包先翻 readme 或者类文件里的注释别想当然。return_url()是 ECShop 封装好的回调地址生成函数你不必手写 URL。接收异步通知的respond()则是反着来function respond() { $pid intval($_POST[pid]); $trade_no trim($_POST[trade_no]); // 码支付流水号 $orderid trim($_POST[orderid]); // 商户订单号 $money trim($_POST[money]); // 实付金额 $sign trim($_POST[sign]); // 签名 // 验签 $check md5($pid . $orderid . $money . $payment[codepay_key]); if ($check ! $sign) { exit(fail); // 验签失败必须返回非success } // 修改订单状态 $order_sn $orderid; $sql UPDATE . $GLOBALS[ecs]-table(order_info) . SET pay_status 2, pay_time . time() . WHERE order_sn $order_sn AND pay_status 0; $GLOBALS[db]-query($sql); exit(success); // 告诉码支付服务器“收到别重发” }这里有两个坑提前说一、必须掉用exit(success)而不是返回字符串否则码支付服务器收不到确认会反复重发通知二、respond()里不要直接用$_POST[money]改订单实付款额正确做法是只把$_POST[orderid]当成可信订单号金额以 ECShop 订单表里的值为准否则中间人改金额回调你也会入账。后面避坑章节会展开。3. 在 ECShop 里启用码支付安装步骤、参数表与两台机器验证法目录结构看完下一步就是把插件放进去、填参数、跑通第一笔真实支付。别只图快安装过程中的路径、权限、缓存任何一环出问题后台就是不显示“码支付”三个字。3.1 上传插件文件并完成注册先把压缩包传到服务器上。以 Linux 服务器为例我一般直接解压到站点根目录再移动文件# 进入站点根目录假设是 /var/www/ecshop cd /var/www/ecshop # 解压 unzip ecshop_codepay.zip # 把主支付类放到支付模块目录 cp codepay.php includes/modules/payment/ # 创建语言包目录并复制语言文件 cp -r languages/zh_cn/payment/codepay.php languages/zh_cn/payment/ # 清理ECShop编译缓存和临时查询缓存 rm -rf temp/query_caches/* chmod -R 755 includes/modules/payment/目录和权限说三点includes/modules/payment/下的支付类文件必须可读权限 644 就够755 也行但要避免 777语言包缺失不会导致插件消失但后台显示会变成空白或英文所以务必一起放temp/query_caches/是 ECShop 的缓存目录不清理的话后台支付方式列表可能读不到新文件。文件就位后登录 ECShop 后台找到“支付方式”点“安装”旁边的下拉列表。正常情况下会出现一项“码支付”没有出现的话按顺序排查文件是否在正确目录、文件名是否带后缀隐藏比如codepay.php.txt、PHP 是否有语法错误。先做一次语法检查最省事php -l includes/modules/payment/codepay.php输出No syntax errors detected就说明语法没问题。老站常见的是 PHP 版本过高、插件用了废弃函数比如mysql_connect之类直接导致后台白屏所以先php -v看一眼版本再装更稳。3.2 后台配置项与参数说明支付方式列表里找到“码支付”点“安装”会弹出配置项。这里的每一项都对应$configure里定义的name我以最常用的一套参数为例配置项获取位置必填说明商户IDpid码支付后台的商户信息页是每个商户唯一回调验签时也要用商户密钥key码支付后台生成/重置是64位字符串泄露后任何人都能伪造回调务必保密支付渠道插件配置下拉是可选支付宝/微信/财付通对应下单参数里的 type异步通知URL插件自动生成是码支付服务器回调入口必须公网可访问同步跳转URL插件自动生成否用户支付完跳回站点的地址仅展示用调试日志手动开关否开启后每个回调写日志定位问题神器安装完成后不要急着关掉“异步通知URL”看一眼它一定是http://你的域名/respond.php?codecodepay这种形式。ECShop 的所有支付回调都走respond.php靠code参数区分是哪个支付方式。如果你启用了 CDN 或者宝塔的防盗链务必把respond.php加白名单否则回调被拦截用户付了钱你这边订单不动。3.3 先开日志再上线一分钟加回调调试日志我接支付插件从来不先测支付而是先加日志。给respond()入口加一段写文件日志的代码比事后翻数据库高效得多function respond() { // 调试验证把回调原文写盘 $log_file ROOT_PATH . data/codepay_callback.log; $log_data date(Y-m-d H:i:s) . . json_encode($_POST) . PHP_EOL; file_put_contents($log_file, $log_data, FILE_APPEND); // ……后续验签与改单逻辑…… }这段代码注意两点日志目录用data/而不是temp/因为temp/可能被定时清理file_put_contents前面加抑制警告避免回调地址返回 PHP 警告导致exit(success)前输出脏内容。日志可以帮你回答三个问题码支付到底有没有回调过来、回调参数带全了没有、验签到底卡在哪一步。日志验证完记得关掉不关的话高并发下文件锁会拖慢回调速度。4. 支付宝、微信、财付通三通道的差异type 参数、端上表现与回调字段你装的是“码支付”但用户最终拿到的收款方式有三种。很多站长以为三个渠道只是换个二维码实际在跳转逻辑、回调字段、用户端体验上差别不小值得单独拆开说。4.1 三渠道在同一个 type 参数下的选择逻辑码支付用一个type参数区分渠道常见映射是1支付宝、2微信、3财付通。插件在get_code()里拼参数时会从后台配置读当前选中的渠道$channel $payment[codepay_channel]; // 后台下拉配置 $type_map array(alipay 1, weixin 2, tenpay 3); $type isset($type_map[$channel]) ? $type_map[$channel] : 1;但这只解决了“用哪个渠道收款”没有解决“用户用什么设备打开”。实际落地时PC 端浏览器和手机端浏览器看到的收银台应该不一样。码支付网关一般会自己判断 UA但我建议插件层主动做一次分流避免用户体验断层$ua $_SERVER[HTTP_USER_AGENT]; if (strpos($ua, AlipayClient) ! false) { // 支付宝App内打开直接走支付宝H5收银台 $pay_mode h5; } elseif (strpos($ua, MicroMessenger) ! false) { // 微信内打开部分渠道限制H5改展示二维码引导右上角浏览器打开 $pay_mode qr; } else { // 其他浏览器PC扫码或手机跳转均可 $pay_mode qr; }这段逻辑判断放插件里并不复杂但直接影响支付转化率。微信内置浏览器对 H5 支付有严格限制很多聚合支付在微信内直接跳 H5 会白屏所以先识别 UA 再决定是展示二维码还是跳转比统一跳到收银台稳得多。4.2 三个渠道的用户端体验与回调差异渠道用户端典型表现回调特征最容易翻车的地方支付宝PC 扫二维码 / 支付宝App内直接收银台回调通常一次成功字段完整同步跳转和异步通知都会触发幂等没做好会被二次更新微信普通浏览器扫码 / 微信内有时只能展示二维码回调次数较多网络抖动会重发H5 跳转被微信拦截用户卡在空白页财付通主要覆盖 QQ 钱包场景PC 端扫码成功率一般字段一致但签名大小写最容易对不上很多人把它当成微信第二入口实际用户量极小对 ECShop 订单状态机来说不管哪个渠道respond()里修改订单的 SQL 都必须带pay_status0条件。原因是异步回调不是一次性通知码支付服务器可能发多次第一次改完订单第二次如果无条件更新就把支付时间、状态又刷新了一遍看起来好像没坏但审计对不上。4.3 财付通渠道的常见误区财付通这个渠道容易被误解。它不是微信支付而是腾讯体系里的另一个支付产品典型的使用场景是 QQ 钱包。如果你的商城用户主要来自微信没必要开财付通开了也基本收不到几单如果你的用户有大量 QQ 粉丝群导流才值得在支付方式里保留这个入口。而且财付通的回调签名串我崩过一次同样的拼接规则、同样的 MD5 函数支付宝微信都验签通过唯独财付通失败最后发现是财付通回调的sign是小写而插件里验签用的strtoupper()两边没对齐。任何渠道只要验签不过一律不进改单逻辑宁可让用户干等也别放行。5. 码支付插件实战避坑签名失败、订单未更新与重复通知的排查清单支付类插件的坑几乎都集中在回调链路。不夸张地说90% 的“用户付了钱订单没变”都是回调阶段出了问题。下面这五条是我拆这类插件时反复踩过的坑按“现象 → 原因 → 解决”给你一个可照抄的排查清单。5.1 支付成功但 ECShop 订单仍是待付款现象用户明明在支付宝/微信里付款成功了ECShop 后台订单状态却停在“待付款”。原因最常见三种——回调根本没有到达respond()被服务器防火墙或伪静态规则拦截、回调到了但验签没过、验签过了但更新 SQL 没生效。还有一种隐蔽情况ECShop 订单表里order_sn和码支付返回的orderid不一致插件传的是订单自增 ID回调拿到的是订单号两边对不上。解决先开 3.3 节里的回调日志确认 POST 里orderid到底长什么样然后去order_info表里手工查一下SELECT order_sn, order_status, pay_status FROM ecs_order_info WHERE order_sn 你的订单号;如果确认收到且字段能对上再看更新条件。我最常用的做法是把更新 SQL 改成带order_status0和pay_status0双条件只有未付款订单才允许回调改状态$sql UPDATE . $GLOBALS[ecs]-table(order_info) . SET pay_status 2, pay_time . time() . WHERE order_sn $order_sn AND order_status 0 AND pay_status 0;这样即使回调重发也不会把已发货的订单状态改乱。5.2 回调地址返回 HTTP 500码支付一直重发现象码支付后台能看到通知记录一直在重试每几分钟就来一次但 ECShop 这边日志停更。原因回调执行过程中抛了 PHP 错误。典型场景是 PHP 7 以上版本里用了mysql_*老函数或者openssl扩展没装导致签名函数报错。码支付服务器只要拿不到success就认为没送达会持续重发。解决看服务器 PHP error logtail -f /var/log/php-fpm/error.log或者临时在respond()开头加error_reporting(E_ALL); ini_set(display_errors, 1);看回调直接输出什么错误。修完语法问题后用 curl 模拟一次码支付回调curl -X POST http://你的域名/respond.php?codecodepay \ -d pid10001orderidTEST20240101money0.01trade_noTEST123sign测试值只要不 500能进入验签分支问题就缩小到了签名规则这一环。5.3 微信内打开 H5 收银台一直转圈现象用户通过微信会话里点开支付链接页面一直加载最后白屏或转圈。原因微信内置浏览器对部分 H5 支付有页面限制尤其是第三方聚合支付H5 支付链接必须在微信外部浏览器打开微信内直接访问会被拦截或无法唤起。这不是码支付特有的问题微信官方 H5 支付也有同样规则。解决在get_code()里检测MicroMessenger的 UA微信内一律不跳 H5而是展示二维码图片或提示用户“点击右上角用浏览器打开”。你需要在本机上用微信扫码验证一次别只在电脑浏览器测。5.4 重复回调导致订单状态被覆盖现象日志显示同一个订单回调了三次前两次成功第三次又把订单状态更新了一遍支付时间变了甚至出现重复发货。原因码支付服务器收不到确认时重发或者同步跳转return_url和异步通知notify_url都执行了。ECShop 的同步跳转和异步通知若都写了改单逻辑就会出现二次更新。解决统一改单逻辑只放respond()也就是异步通知里处理同步跳转return_url只做页面展示不改数据库。改单 SQL 里必须带pay_status0从根上保证幂等第一次执行成功第二次执行影响行数为 0。5.5 二维码图片加载失败或显示裂图现象PC 端结算页的支付二维码显示不出来F12 看到图片请求报 mixed content 错误。原因你的站点启用了 HTTPS但码支付接口返回的二维码图片链接还是http://浏览器安全策略直接拦截了站内 HTTPS 页面里的 HTTP 资源请求。解决拼接支付请求时把所有资源地址统一协议。在get_code()里加一层协议判断$scheme (isset($_SERVER[HTTPS]) $_SERVER[HTTPS] ! off) ? https : http; $codepay_api $scheme . ://codepay.example.com/qrcode?...;如果码支付网关不支持 HTTPS那就只能把二维码接口放在本地代理转发或者在服务器层面做一次反向代理。这个坑最隐秘线上开 HTTPS 的站点基本都会碰到。6. 进阶把回调链路做成可复验的调试闭环装好、跑通是第一层能定位问题才是第二层。我习惯在自己环境里搭一个“验签复算”脚本每次回调出问题把日志里的 POST 参数原样丢进去当场分辨是码支付没通知到位还是插件签名算法有偏差php -r $pid 10001; $orderid 20240101001; $money 0.01; $key 你的商户密钥; $sign_from_server 回调里的sign值; $calc md5($pid . $orderid . $money . $key); echo ($calc strtolower($sign_from_server)) ? 验签一致 : 验签失败; 跑这个命令时要注意先从日志里找到那笔回调的pid、orderid、money原样复制别自己重新从数据库查因为回调里金额的字符串格式比如0.01还是0.010会直接影响 MD5 结果。验证通过后再去查数据库整个排查链路就闭合了。顺手再分享一个检查清单我每次给老站接这类免签插件都照着走一遍检查项说明SSL 协议一致性站点 HTTPS 时回调 URL 必须能被码支付用 HTTPS 访问订单改单幂等更新 SQL 必带pay_status0回调日志开关上线后记得关闭避免高并发写日志金额单位与精度确保传参和回调比较都用同一精度别用浮点直接拼接最小真实单验证用 0.01 元真实订单走完 下单→支付→回调→改单 全链路我第一次给一个商城老站接这种聚合支付白天装的插件晚上就收到“客户付了钱订单没变”的反馈。当时第一反应查数据库结果订单状态确实没动又去翻日志才发现回调请求根本没打到服务器——是被伪静态规则重写了respond.php的路径。从那以后我每次接任何新支付渠道都强制先开回调日志用一笔 1 分钱的真实单把验签、改单、跳转全部走通再关日志收工。这套习惯救过我很多次希望也帮到你。本文还有配套的精品资源点击获取