介绍
这篇文章主要为大家详细介绍微信支付如何接入开源管理后台webman-admin开发教程
必须申请开通微信支付
- 微信支付官方地址:https://pay.weixin.qq.com/index.php/core/home/login?return_url=/
- 申请指引:https://pay.weixin.qq.com/index.php/public/bare_applyment/login4bank
支付流程
接入流程
1. 登录商户
登录微信商户平台:https://pay.weixin.qq.com
2. 获取商户号
3. 添加支付授权域名目录
授权域名格式:
http://域名/
注意:域名最后的斜杠绝不能少
4. 若提示没有安装证书,请安装证书
按照提示语按照即可
5. 配置API安全
6. 申请API证书
注意:以前申请过的,并且可以找到的,直接跳过。找不到的,点击更换证书
7. 生成API证书
8. 下载至本地安装
9. 商户号和商户名称
对照检查商户号和商户名称是否为你当前配置帐号信息,确定无误后点击“下一步”
10. 复制证书内容
点击工具右侧「复制」
11. 打开商户平台(切换为浏览器)
12. 复制证书串
13. 切换至证书工具
14. 查看证书文件夹
15. 建议复制证书
建议复制证书,保存到的资料文件夹。证书为 _cert.zip 结尾压缩包。
16.解压证书压缩包
解压证书压缩包,得到文件(暂时不用管,后面会用到
17. 配置API秘钥(点击设置秘钥)
18.设置秘钥
设置秘钥,包含随机大小写字母、数字组合,32位。(记得保存)【不会的可以在 https://suijimimashengcheng.51240.com 里选择32位,随机生成,然后复制,在过来粘贴。】
支付相关配置完成,记得保存相关资料。
支付
安装依赖
代码语言:javascript复制composer require yansongda/pay ^3.0.0
配置文件
假设有以下配置文件 config/payment.php
<?php
/**
* @desc 支付配置文件
* @author Tinywan(ShaoBo Wan)
* @date 2023/4/5 13:51
*/
declare(strict_types=1);
return [
'wechat' => [
'default' => [
// 必填-商户号,服务商模式下为服务商商户号
// 可在 https://pay.weixin.qq.com/ 账户中心->商户信息 查看
'mch_id' => '12312312321',
// 必填-商户秘钥
// 即 API v3 密钥(32字节,形如md5值),可在 账户中心->API安全 中设置
'mch_secret_key' => '3324324reewrwerew',
// 必填-商户私钥 字符串或路径
// 即 API证书 PRIVATE KEY,可在 账户中心->API安全->申请API证书 里获得
// 文件名形如:apiclient_key.pem
'mch_secret_cert' => public_path().'/cert/wechat/apiclient_key.pem',
// 必填-商户公钥证书路径
// 即 API证书 CERTIFICATE,可在 账户中心->API安全->申请API证书 里获得
// 文件名形如:apiclient_cert.pem
'mch_public_cert_path' => public_path().'/cert/wechat/apiclient_cert.pem',
// 必填-微信回调url
// 不能有参数,如?号,空格等,否则会无法正确回调
'notify_url' => 'http://webman.tinywan.com/gateway/payment/wechat-notify',
'return_url' => 'http://webman.tinywan.com/index',
// 选填-公众号 的 app_id
// 可在 mp.weixin.qq.com 设置与开发->基本配置->开发者ID(AppID) 查看
'mp_app_id' => 'dsfdsfdsfdsdfdsafds',
// 选填-小程序 的 app_id
'mini_app_id' => '',
// 选填-app 的 app_id
'app_id' => '',
// 选填-合单 app_id
'combine_app_id' => '',
// 选填-合单商户号
'combine_mch_id' => '',
// 选填-服务商模式下,子公众号 的 app_id
'sub_mp_app_id' => '',
// 选填-服务商模式下,子 app 的 app_id
'sub_app_id' => '',
// 选填-服务商模式下,子小程序 的 app_id
'sub_mini_app_id' => '',
// 选填-服务商模式下,子商户id
'sub_mch_id' => '',
// 选填-微信平台公钥证书路径, optional,强烈建议 php-fpm 模式下配置此参数
'wechat_public_cert_path' => [
'45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__.'/Cert/wechatPublicKey.crt',
],
// 选填-默认为正常模式。可选为: MODE_NORMAL, MODE_SERVICE
'mode' => YansongdaPayPay::MODE_NORMAL,
]
],
'unipay' => [
'default' => [
// 必填-商户号
'mch_id' => '777290058167151',
// 必填-商户公私钥
'mch_cert_path' => __DIR__.'/Cert/unipayAppCert.pfx',
// 必填-商户公私钥密码
'mch_cert_password' => '000000',
// 必填-银联公钥证书路径
'unipay_public_cert_path' => __DIR__.'/Cert/unipayCertPublicKey.cer',
// 必填
'return_url' => 'https://yansongda.cn/unipay/return',
// 必填
'notify_url' => 'https://yansongda.cn/unipay/notify',
],
],
'logger' => [
'enable' => true,
'file' => runtime_path().'/logs/pay.log',
'level' => 'debug', // 建议生产环境等级调整为 info,开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
],
];
代码语言:javascript复制注意:证书目录放在的框架的
public
公共目录下
webman.tinywan.com/public$ tree -L 4
.
├── 404.html
├── cert
│ └── wechat
│ ├── apiclient_cert.p12
│ ├── apiclient_cert.pem
│ ├── apiclient_key.pem
│ └── 证书使用说明.txt
使用
初始化
直接调用 config
方法初始化
// 获取配置文件 config/payment.php
Pay::config(config('payment'));
注意:这里使用「微信公众号」进行支付
支付(微信公众号支付)
「服务端接口代码」
代码语言:javascript复制use supportRequest;
use WebmanConfig;
use YansongdaPayPay;
/**
* @desc: 公众号支付
* @param Request $request
* @return Response
* @author Tinywan(ShaoBo Wan)
*/
public function recharge(Request $request): Response
{
// 1. 订单预备订单
$user['username'] = 'Tinywan';
// 这个根据微信授权获取
$user['openid'] = 'fsdfsd342343241231fdsfsdafsd';
$order_sn = time();
$totalAmount = 0.01;
$discountAmount = 0;
$payAmount = $totalAmount - $discountAmount;
// 2. 支付开始预备订单
Pay::config(config('payment'));
$preOrder = [
'out_trade_no' => $order_sn,
'description' => $user['username'].',充值开源技术小栈',
'amount' => [
'total' => $payAmount * 100, // 分
],
'payer' => [
'openid' => $user['openid']
],
];
// 公众号支付
$wechatRes = Pay::wechat()->mp($preOrder);
}
路由地址为:
/test/recharge
「前端JS代码」
代码语言:javascript复制<!-- 引入 layui.css -->
<link rel="stylesheet" href="https://www.layuicdn.com/layui-v2.7.6/css/layui.css">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script src="https://www.layuicdn.com/layui-v2.7.6/layui.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>
let paySign;
let appId;
let timeStamp;
let nonceStr;
let packageStr;
let signType;
// 触发支付
layui.use(['form'], function () {
var form = layui.form, layer = layui.layer;
//监听提交
form.on('submit(submit)', function (data) {
$.ajax({
type: "post",
dataType: "json",
data: {
openId: "{$openid}",
score: 100,
money: 10
},
url: "/test/recharge",
async: false,
success: function (data) {
if (data.code === 0) {
appId = data.data.appId;
paySign = data.data.paySign;
timeStamp = data.data.timeStamp;
nonceStr = data.data.nonceStr;
packageStr = data.data.package;
signType = data.data.signType;
callpay();
} else {
layer.msg("下单失败请稍后再重试", {
time: 50000,
});
return false;
}
},
error: function () {
layer.alert('系统异常')
}
});
return false;
});
});
/**
* @desc 下单成功后调用 调用微信的支付界面
* @author Tinywan(ShaoBo Wan)
*/
function callpay() {
console.log('调用微信的支付界面')
if (typeof WeixinJSBridge == "undefined") {
console.log('undefinedundefinedundefined');
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
}
/**
* @desc 下面两个方法都是固定写法 调用微信自带的支付界面
* @author Tinywan(ShaoBo Wan)
*/
function onBridgeReady() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": appId, //公众号名称,由商户传入
"paySign": paySign, //微信签名
"timeStamp": timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": nonceStr, //随机串
"package": packageStr, //预支付交易会话标识
"signType": signType //微信签名方式
},
function (res) {
if (res.err_msg === "get_brand_wcpay_request:ok") {
window.location.href = 'http://webman.tinywan.com/user/home'
} else if (res.err_msg === "get_brand_wcpay_request:cancel") {
window.location.href = 'http://webman.tinywan.com/user/recharge?openid={$openid}';
} else if (res.err_msg === "get_brand_wcpay_request:fail") {
window.location.href = 'http://webman.tinywan.com/user/home?openid={$openid}';
}
}
);
}
</script>
异步回调
代码语言:javascript复制use supportRequest;
use WebmanConfig;
use YansongdaPayPay;
/**
* @desc:『微信』异步通知
* @param Request $request
* @return string
*/
public function wechatNotify(Request $request): string
{
Pay::config(Config::get('payment'));
$result = Pay::wechat()->callback($request->post());
// 接受回调信息
$openid = $result['resource']['ciphertext']['payer']['openid'];
$mchid = $result['resource']['ciphertext']['mchid'];
$thirdSn = $result['resource']['ciphertext']['transaction_id'];
$outTradeNo = $result['resource']['ciphertext']['out_trade_no'];
$tradeState= $result['resource']['ciphertext']['trade_state'];
$totalAmount = bcdiv((string) $result['resource']['ciphertext']['amount']['total'], '100', 2);
// 异步响应
$success = Pay::wechat()->success()->getBody()->getContents();
return $success;
}
注意:这里异步接受请求方式为 「
POST
」 请求方式。
「异步参数接受数据」
代码语言:javascript复制{
"id": "1f5c3fb7-4f13-5069-a3fc-5708e98a4c1d",
"create_time": "2023-11-05T19:30:16 08:00",
"resource_type": "encrypt-resource",
"event_type": "TRANSACTION.SUCCESS",
"summary": "支付成功",
"resource": {
"original_type": "transaction",
"algorithm": "AEAD_AES_256_GCM",
"ciphertext": {
"mchid": "1643333333427",
"appid": "wxd39133333333ae28e1",
"out_trade_no": "20231103333333331181193183",
"transaction_id": "42000033333333334559785",
"trade_type": "JSAPI",
"trade_state": "SUCCESS",
"trade_state_desc": "支付成功",
"bank_type": "OTHERS",
"attach": "",
"success_time": "2023-11-05T19:30:16 08:00",
"payer": {
"openid": "oyRe_1DFDSFSDFSDFSDFrY"
},
"amount": {
"total": 100,
"payer_total": 100,
"currency": "CNY",
"payer_currency": "CNY"
}
},
"associated_data": "transaction",
"nonce": "d8bcd7PDSFSDF2"
}
}
支付结果
日志
所有相关支付日志多存储在 项目目录/runtime/logs/pay.log
文件中