TP5支付逻辑应封装为独立函数,统一管理配置、签名、请求与验签;配置须从文件或模型读取并区分环境;微信金额单位为分,notify_url需外网可达且无参数;函数职责单一,回调须用原始POST数据验签并做幂等处理。

TP5 里写支付逻辑,不推荐直接在控制器里堆砌支付参数和请求代码——容易出错、难复用、回调验证也容易漏。真正可维护的做法是:把支付封装成独立函数,统一管理配置、签名、请求、验签逻辑。
自定义支付函数必须隔离配置与业务逻辑
配置(如 app_id、merchant_private_key、notify_url)不能硬编码在函数体里,也不能每次调用都重复读取。应统一从配置文件或模型中获取,且支持环境区分(沙箱/正式)。
- 支付宝建议用
alipay_config配置数组,字段名严格对齐官方 SDK 要求(比如sign_type必须是RSA2,不是RSA) - 微信支付的
total_fee单位是「分」,传入前必须intval($price * 100),漏这步会导致「金额格式错误」 - 回调地址
notify_url必须是外网可访问的完整 HTTP/HTTPS 地址,且不能带查询参数(如?id=123),否则支付宝/微信会拒绝通知
函数签名要明确区分支付类型和返回目标
一个函数只做一件事:生成支付跳转链接 or 返回预支付参数 or 处理异步通知。不要混在一起。例如扫码支付和 H5 支付的入口函数就该分开:
-
alipay_page_pay($out_trade_no, $subject, $total_amount, $body)→ 返回跳转用的完整 URL -
wxpay_scan_code($order_no, $price, $body)→ 返回code_url字符串,供前端渲染二维码 -
handle_alipay_notify()→ 只负责验签 + 解析 POST 数据 + 更新订单状态,不返回视图
所有函数开头加 if (!input('post.')) { exit('invalid request'); },避免被 GET 直接触发。
回调验签是最容易翻车的环节
微信和支付宝的验签逻辑完全不同,但共同点是:必须用原始 POST 数据(非 $_POST,因为 PHP 会自动 urldecode)、按字典序拼接、排除空值和 sign 字段,再用对应密钥计算签名比对。
- 支付宝验签要用
AlipayAopClient::verifyNotify()或手动调用openssl_verify(),不能只比对sign字符串 - 微信验签需用
md5($stringA.'&key='.$this->config['key']),其中$stringA是排序后拼接的 key=value 字符串,且不含sign和空值 - 验签失败时,必须返回
success或fail纯文本(微信) / 不返回任何内容(支付宝),不能输出 HTML 或 JSON,否则对方会重试多次
最常被忽略的是:异步通知可能重复到达,函数内部必须做幂等处理(比如先查订单状态,已是「已支付」就直接返回 success)。别指望前端防重提交——支付平台的重试机制才是真实压力源。

















