微信支付接入
- 微信支付-账户中心-API安全,设置APIV3密钥,密钥包括了32位的API V3秘钥(apiV3Key)
- 微信支付-账户中心-API安全,申请API证书(包括apiclient_cert.pem和apiclient_key.pem),申请完成后点击”管理证书“,获取证书序列号(mchSetialNo)
- 产品中心-我的产品,开通相关权限(Native支付)
- 下载微信支付平台证书
composer require wechatpay/wechatpay
php -f vendor\wechatpay\wechatpay\bin\CertificateDownloader.php -- -k ${apiV3Key} -m ${mchId} -f apiclient_key.pem -s ${mchSetialNo} -o .
注1: 如果出现错误: SSL certificate problem: unable to get local issuer certificate 修改CertificateDownloader.php,增加 'verify' => false
private function job(array $opts): void
{
...
$instance = Builder::factory([
'mchid' => $opts['mchid'],
'serial' => $opts['serialno'],
'privateKey' => \file_get_contents((string)$opts['privatekey']),
'certs' => &$certs,
'base_uri' => (string)($opts['baseuri'] ?? self::DEFAULT_BASE_URI),
'verify' => false
]);
...
参考文档 pay.weixin.qq.com/wiki/doc/ap…
PHP接口
<?php
namespace app\base;
use WeChatPay\Builder;
use WeChatPay\Crypto\AesGcm;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;
class WxPay
{
public static function getClient()
{
// 设置参数
$config = \Yii::$app->params['wxConfig'];
// 商户号
$merchantId = $config['merchant']['mchId'];
// 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
$merchantPrivateKeyFilePath = "file://" . $config['merchant']['mchKeyFile'];
$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
// 「商户API证书」的「证书序列号」
$merchantCertificateSerial = $config['merchant']['mchSetialNo'];
// 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
$platformCertificateFilePath = "file://" . $config['merchant']['wxKeyFile'];
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
// 从「微信支付平台证书」中获取「证书序列号」
$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
// 构造一个 APIv3 客户端实例
$instance = Builder::factory([
'mchid' => $merchantId,
'serial' => $merchantCertificateSerial,
'privateKey' => $merchantPrivateKeyInstance,
'certs' => [
$platformCertificateSerial => $platformPublicKeyInstance,
],
'verify' => false
]);
return $instance;
}
public static function getResponse()
{
$config = \Yii::$app->params['wxConfig'];
$headers = \Yii::$app->request->getHeaders();
$inWechatpaySignature = $headers['Wechatpay-Signature'];// 请根据实际情况获取
$inWechatpayTimestamp = $headers['Wechatpay-Timestamp'];// 请根据实际情况获取
$inWechatpaySerial = $headers['Wechatpay-Serial'];// 请根据实际情况获取
$inWechatpayNonce = $headers['Wechatpay-Nonce'];// 请根据实际情况获取
$inBody = \Yii::$app->request->getRawBody();// 请根据实际情况获取,例如: file_get_contents('php://input');
$apiv3Key = $config['merchant']['apiV3Key'];;// 在商户平台上设置的APIv3密钥
// 根据通知的平台证书序列号,查询本地平台证书文件,
$platformCertificateFilePath = 'file://'.$config['merchant']['wxKeyFile'];
$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
// 检查通知时间偏移量,允许5分钟之内的偏移
$timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
$verifiedStatus = Rsa::verify(
// 构造验签名串
Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
$inWechatpaySignature,
$platformPublicKeyInstance
);
if ($timeOffsetStatus && $verifiedStatus) {
// 转换通知的JSON文本消息为PHP Array数组
$inBodyArray = (array)json_decode($inBody, true);
// 使用PHP7的数据解构语法,从Array中解构并赋值变量
['resource' => [
'ciphertext' => $ciphertext,
'nonce' => $nonce,
'associated_data' => $aad
]] = $inBodyArray;
// 加密文本消息解密
$inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
// 把解密后的文本转换为PHP Array数组
$inBodyResourceArray = (array)json_decode($inBodyResource, true);
// print_r($inBodyResourceArray);// 打印解密后的结果
return $inBodyResourceArray;
}
return null;
}
}