1、接入前准备 根据微信支付官方文档指引
https://pay.weixin.qq.com/doc/v3/merchant/4012064918
下载微信支付证书脚本
composer exec CertificateDownloader.php -- -k ${9*****} -m ${******} -f ${********} -s ${**********} -o ${D:\wx\crm\app\\wechat}
-
-k 9∗∗∗∗∗:这是一个选项参数,−�表示后面的值是指定的密钥。9∗∗∗∗∗:这是一个选项参数,−k表示后面的值是指定的密钥。{9*****}是一个占位符,实际是一个具体的密钥值。
-
-m ∗∗∗∗∗∗:这是另一个选项参数,−�表示后面的值是指定的模式。∗∗∗∗∗∗:这是另一个选项参数,−m表示后面的值是指定的模式。{******}是一个占位符,实际是一个具体的模式值。
-
-f ∗∗∗∗∗∗∗∗:这是一个选项参数,−�表示后面的值是指定的文件名。∗∗∗∗∗∗∗∗:这是一个选项参数,−f表示后面的值是指定的文件名。{********}是一个占位符,实际是一个具体的文件名。
-
-s ∗∗∗∗∗∗∗∗∗∗:这是一个选项参数,−�表示后面的值是指定的文件路径。∗∗∗∗∗∗∗∗∗∗:这是一个选项参数,−s表示后面的值是指定的文件路径。{**********}是一个占位符,实际上是一个具体的文件路径。
-
-o ParseError: KaTeX parse error: Undefined control sequence: \wx at position 4: {D:\̲w̲x̲\crm\app\\wecha…{D:\wx\crm\app\wechat}是一个占位符,实际是你自己要下载的地址
2、根据自己的开发语言下载对应的sdk包 (下面以php为示例,所有语言都类似)
composer require wechatpay/wechatpay
3、配置微信支付相关参数
1:初始化
private $merchantId; //商户号
private $merchantPrivateKeyFilePath;
private $merchantPrivateKeyInstance;
private $merchantCertificateSerial;//证书序列号
private $platformCertificateFilePath;
private $platformPublicKeyInstance;
private $platformCertificateSerial;
private $instance;
private $appId;
private $apiKey;
public function __construct()
{
//初始化配置
try {
$this->merchantId = env('WECHAT_MERID');
$this->merchantCertificateSerial = env('WECHAT_MER_CERTIFICATE_SERIAL');
$this->appId = env('SHOP_WECHAT_PAYMENT_APPID');
$this->apiKey = env('WECHAT_APIKEY');
// 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
$this->merchantPrivateKeyFilePath = 'file://' . dirname(dirname(__FILE__)) . ' 自己私钥文件地址';
$this->merchantPrivateKeyInstance = Rsa::from($this->merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
// 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
$this->platformCertificateFilePath = 'file://' . dirname(dirname(__FILE__)) . 自己微信支付平台证书;
$this->platformPublicKeyInstance = Rsa::from($this->platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
// 从「微信支付平台证书」中获取「证书序列号」
$this->platformCertificateSerial = PemUtil::parseCertificateSerialNo($this->platformCertificateFilePath);
// 构造一个 APIv3 客户端实例
$this->instance = Builder::factory([
'mchid' => $this->merchantId,
'serial' => $this->merchantCertificateSerial,
'privateKey' => $this->merchantPrivateKeyInstance,
'certs' => [
$this->platformCertificateSerial => $this->platformPublicKeyInstance,
],
]);
} catch (\Exception $e) {
throw new ApiException('此功能暂未开放,请稍后再试');
}
}
2:发起微信支付
public function jsPay($outTradeNo,$goodsName,$totalFee,$openId,$orderType,$doneOrderType = 1){
//自己回调时需要的参数会原样带回(非必填)
$attach = json_encode([]);
try {
$body = [
'json' => [
'mchid' => $this->merchantId,
'out_trade_no' => "自己系统单号",
'appid' => $this->appId,
'description' => "订单描述",
'notify_url' => "回调地址",
'amount' => [
'total' => 支付金额, (以分为单位)
'currency' => 'CNY'(人民币)
],
'time_expire' => "",过期时间(具体时间格式看微信官方文档)
'payer' => [
'openid' => $openId,(支付人的openid)
],
'attach' => $attach,
]
];
$resp = $this->instance
->chain('v3/pay/transactions/jsapi')
->post($body);
$status = $resp->getStatusCode();
if ($status != 200){
throw new ApiException($resp->getBody());
}
$body = json_decode($resp->getBody(),true);
$data = $this->configForPayment($body['prepay_id']);(前端需要唤起微信支付组件的加密格式)
return $data;
} catch (\Exception $e) {
// 进行错误处理
throw new ApiException('支付异常,请稍后重试');
}
}
3:支付回调
public function notify($info)
{
Common::log('info','orderCallback',$info);
$inWechatpaySignature = $info['wechatpay-signature'][0];
$inWechatpayTimestamp = $info['wechatpay-timestamp'][0];
$inWechatpaySerial = $info['wechatpay-serial'][0];
$inWechatpayNonce = $info['wechatpay-nonce'][0];
if ( !$inWechatpaySignature or !$inWechatpayTimestamp or !$inWechatpaySerial or !$inWechatpayNonce ) {
header("Location:/404.html");
exit;
}
$inBody = file_get_contents("php://input");// 请根据实际情况获取,例如: file_get_contents('php://input');
Common::log('info','refundsNotify inBody',json_decode($inBody,true));
// 检查通知时间偏移量,允许5分钟之内的偏移
$verifiedStatus = Rsa::verify(
// 构造验签名串
Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
$inWechatpaySignature,
$this->platformPublicKeyInstance
);
if ($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, $this->apiKey, $nonce, $aad);
// 把解密后的文本转换为PHP Array数组
$inBodyResourceArray = (array) json_decode($inBodyResource, true);
$result = $inBodyResourceArray;
Common::log('info','refundsNotify result',$result);
if ( $result['trade_state'] == 'SUCCESS' ) {
DB::beginTransaction();//开启事务
try {
//写自己业务的回调逻辑
DB::commit();
}catch (\Exception $exception){
DB::rollBack();
throw new ApiException($exception->getMessage());
}
return 'success';
}
}
}
public function configForPayment($prepayId)
{
$params = [
'appId' => $this->appId,
'timeStamp' => (string) Formatter::timestamp(),
'nonceStr' => Formatter::nonce(),
'package' => 'prepay_id=' . $prepayId,
];
$params += [
'paySign' => Rsa::sign(
Formatter::joinedByLineFeed(...array_values($params)),
$this->merchantPrivateKeyInstance
),
'signType' => 'RSA'
];
return $params;
}