官方文档有些地方没说明白的坑,记录下踩过的坑!
1、准备文件
-
测试框架
Laravel8
-
新创建的商户号以下代码可能无参考价值(2025-01-14更新)
-
官方环境要求
PHP 5.5+ / PHP 7.0+
guzzlehttp/guzzle 6.0+ -
微信支付证书,微信支付商户平台下载
2、下载官方提供SDK-wechatpay-guzzle-middleware
composer require wechatpay/wechatpay-guzzle-middleware
3、代码示例
use GuzzleHttp;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
public function wechatPay()
{
// 商户相关配置
$merchantId = ''; // 商户ID
$merchantSerialNumber = ''; // 商户API证书序列号
$merchantPrivateKey = PemUtil::loadPrivateKey('apiclient_key.pem'); // 商户私钥的绝对路径
// 微信支付平台配置【注意:这个参数需要另外生成】
$wechatPayCertificate = PemUtil::loadCertificate('cert.pem'); // 微信支付平台证书的绝对路径
// 构造一个WechatPayMiddleware
$wechatPayMiddleware = WechatPayMiddleware::builder()
->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
->withWechatPay([ $wechatPayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array
->build();
// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
$stack = GuzzleHttp\HandlerStack::create();
$stack->push($wechatPayMiddleware, 'wechatpay');
// 创建Guzzle HTTP Client时,将HandlerStack传入
$client = new GuzzleHttp\Client(['handler' => $stack]);
// 接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
try {
// 以下内容根据自身需求填写,我做的是小程序支付统一下单API
$resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi',
[
'json' => [ // JSON请求体-具体参数说明请阅读相关官方文档
'appid' => '', // 小程序APPID
'mchid' => $merchantId, // 商户号
'description' => '', // 商品描述
'out_trade_no' => '', // 商户订单号
'time_expire' => '', // 交易结束时间 DATE_RFC3339格式
'notify_url' => '', // 通知地址
'amount' => [
'total' => '', // 金额
'currency' => 'CNY' // 货币类型
],
'payer' => [
'openid' => '' // 用户标识
]
],
'headers' => [ // 请求头
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => request()->userAgent()
]
]);
echo $resp->getStatusCode().' '.$resp->getReasonPhrase()."\n";
echo $resp->getBody()."\n";
} catch (RequestException $e) {
// 进行错误处理
echo $e->getMessage()."\n";
if ($e->hasResponse()) {
echo $e->getResponse()->getStatusCode().' '.$e->getResponse()->getReasonPhrase()."\n";
echo $e->getResponse()->getBody();
}
return;
}
}
注意:cert.pem证书(平台证书)的生成
这个证书不是apiclient_cert.pem证书,官方文档没有详细说明,容易导致踩坑!
这个证书需要手动生成,生成工具就是这个SDK里的这个文件,需要运行命令生成
提示证书不存在看文末
生成命令
php vendor/wechatpay/wechatpay-guzzle-middleware/tool/CertificateDownloader.php -f apiclient_key.pem证书的绝对路径 -k apiv3密匙 -m 填商户号 -o 生成的路径 -s 商户API证书序列号
生成证书需要5个必要参数
1 -f 商户的私钥文件,填写绝对路径
2 -k ApiV3的密钥
3 -m 商户号
4 -o 下载成功后保存证书的路径
5 -s 商户证书的序列号
报错处理
1、cURL error 60: SSL certificate problem: unable to get local issuer certificate…
- 下载cacert.pem放在php目录下的
\extras\ssl
内 - 修改php.ini(记得把参数前面的 ; 去掉),并重启服务。示例:
curl.cainfo=‘D:\phpEnv\php\php-7.4\extras\ssl\cacert.pem’
openssl.cafile=‘D:\phpEnv\php\php-7.4\extras\ssl\cacert.pem’
获取平台证书接口报「系统繁忙」/「文件不存在」,原因分析及解决方法看这里
提示这个就是需要切换公钥模式使用了,也可以看文档指引也可以参考以下内容
问题说明
微信支付对于新申请商户号以及平台证书过期商户已不再签发平台证书,需要更换使用微信支付平台公钥进行敏感信息加密、通知回调签名验证,因此此类商户号调用获取平台证书接口时会出现报错“证书不存在”或者“系统繁忙”的情况。
解决方案
目前会存在两种情况,一种是新申请商户号商户后台没有“平台证书”管理入口,另一种为存量商户存在有在有效期的平台证书和平台证书过期没有签发,第一种可以直接在商户后台->账户中心->API安全->启用“微信支付公钥”,下面教程主要以存量商户切换公钥进行说明(懒得申请新商户号了,拿个白名单商户来写的)。
1.1获取商户对应的平台公钥
商户后台->账户中心->API安全->申请“微信支付公钥“,在点击申请的时候会提示你查看指引,要点查看才可以进行公钥申请!!!
下载公钥
点击“下载公钥”后会自动下载文件名为’pub_key.pem’的公钥并在后台生成“PUB_KEY_ID”开头的公钥ID(丢了也没事,后台可以重复下载,公钥ID不变)
代码参考
// 从本地文件中加载「微信支付平台证书」或者「微信支付平台公钥」,用来验证微信支付应答的签名,这里直接使用前面从后台获取的微信支付平台公钥;
$platformCertificateOrPublicKeyFilePath = 'file:///path/to/wechatpay/certificate_or_publickey.pem';
$platformPublicKeyInstance = Rsa::from($platformCertificateOrPublicKeyFilePath, Rsa::KEY_TYPE_PUBLIC);
// 「微信支付平台证书」的「证书序列号」或者是「微信支付平台公钥ID」
// 「平台证书序列号」及/或「平台公钥ID」可以从 商户平台 -> 账户中心 -> API安全 直接查询到,这里直接写前面从后台获取的微信支付平台公钥ID,注意要带上'PUB_KEY_ID_'
$platformCertificateSerialOrPublicKeyId = 'PUB_KEY_ID_0114232134912410000000000000';
感谢Memory大神,详细内容链接:
https://developers.weixin.qq.com/community/develop/article/doc/000ca894a20c983cad52242286b813