yii对接支付的核心是确保签名、回调、订单状态三者严丝合缝;应使用官方sdk封装组件、统一回调入口、强制验签逻辑,避免90%线上故障。

Yii 对接支付功能,核心不是“能不能做”,而是**怎么让签名、回调、订单状态三者严丝合缝**。直接上结论:用官方 SDK 封装的组件 + 统一回调入口 + 强制验签逻辑,才能避开 90% 的线上故障。
支付宝支付:别直接 new AopClient,用组件封装调用
很多人把支付宝 SDK 文件丢进 vendor 或 common/libs 后,就在控制器里 require_once 然后 new AopClient,这会导致配置分散、无法复用、测试困难。
正确做法是封装成 Yii 组件:
- 在
config/web.php的components中注册alipay组件,类指向自定义的app\components\Alipay -
Alipay类内部初始化AopClient,并统一注入appId、merchantPrivateKey、alipayPublicKey、gatewayUrl(沙箱用https://openapi.alipaydev.com/gateway.do,正式用https://openapi.alipay.com/gateway.do) - 对外只暴露
createPagePayRequest()和verifyNotify()两个方法,其他细节收口
常见坑:signType 必须设为 RSA2(支付宝已弃用 MD5 和 RSA),且私钥必须是 PKCS#1 格式(不是 PKCS#8),否则 verifyNotify() 永远返回 false。
微信支付:别用 EasyWeChat Factory::openPlatform,改用 wechatpay/php-sdk
EasyWeChat 的 Factory::openPlatform() 是为公众号/小程序开放平台设计的,而微信支付(尤其是 JSAPI/H5/APP)应优先使用官方维护的 wechatpay/php-sdk(Composer 安装:composer require wechatpay/php-sdk)。
原因很实际:
-
wechatpay/php-sdk内置自动证书加载、HTTP 签名、响应验签,verifyNotify()只需一行$body = $this->wechatPay->parseNotify($rawInput) - 它强制要求传入平台证书(
apiclient_cert.pem+apiclient_key.pem),避免因证书缺失导致异步通知解析失败却无报错 - 不依赖
curl_setopt手动设置 SSL 配置,规避 PHP cURL 版本兼容问题(比如某些 CentOS 7 默认 curl 不支持 TLS 1.2)
注意:notify_url 必须是公网可访问、带 HTTPS 的地址,且不能带 query 参数(微信会截断);回调入口必须是 POST,且响应体只能是纯字符串 success(不能带空格、换行、JSON 或 HTML)。
回调处理:所有 notify action 必须走统一验签 + 幂等控制
无论是 alipay/notify 还是 wxpay/notify,控制器里的 actionNotify() 如果没做两件事,就等于裸奔:
- 第一,必须调用 SDK 自带的验签方法(
$alipay->verifyNotify($post)或$wechatPay->parseNotify($rawInput)),不能自己拼字符串验签——支付宝字段顺序敏感,微信验签依赖证书序列号,手写极易出错 - 第二,必须查库判断该
out_trade_no是否已处理过。常见错误是:用户重复点击支付、支付宝重发通知、网络超时导致多次请求,结果订单被更新多次,金额扣 double
建议结构:
public function actionNotify()
{
$raw = file_get_contents('php://input');
$result = $this->wechatPay->parseNotify($raw); // 或 $this->alipay->verifyNotify($_POST)
if (!$result) {
\Yii::error('Wechat notify verify failed');
return 'failed'; // 微信要求非 success 即失败
}
$outTradeNo = $result['out_trade_no'];
if (Order::find()->where(['order_no' => $outTradeNo, 'status' => Order::STATUS_PAID])->exists()) {
return 'success';
}
// 更新订单...
}
别省略 \Yii::error 日志,生产环境靠它定位验签失败原因。
调试与上线前必须检查的三个硬性条件
很多项目本地能跑通,一上线就失败,往往卡在这三点:
-
return_url和notify_url必须是公网可访问的完整 URL(含协议、域名、路径),不能是localhost或127.0.0.1;微信还要求域名已在公众平台白名单中备案 - 服务器时间必须和 NTP 时间源同步(误差 > 15 分钟会导致微信签名失效,支付宝部分接口也校验时间戳);可用
ntpdate -q pool.ntp.org检查 - PHP OpenSSL 扩展必须启用,且版本 ≥ 1.0.2(旧版不支持 SHA256withRSA);微信支付的证书解密、支付宝的 RSA2 签名都依赖它
最易忽略的是:支付宝沙箱环境的 alipayPublicKey 和正式环境的不一样,微信的 serial_no 和证书也随环境切换——配置没分环境,上线后验签必然失败。











