request->param('code','');//
$site_id = $this->request->param('site_id','');
$wx_config = Config::where('site_id',$site_id)->field('we_chat_pay_app_id,we_chat_pay_gzh_secret')->find();
$appid = $wx_config['we_chat_pay_app_id'];
$secret = $wx_config['we_chat_pay_gzh_secret'];
$tokeninfo = $this->http_curl("https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$secret}&code={$code}&grant_type=authorization_code");//获取access_token
$tokeninfo = json_decode($tokeninfo, true);
if (empty($tokeninfo['openid'])){
return fail('链接失效,请重新扫码');
}
$res = [
'openid'=>$tokeninfo['openid'],//微信openid
];
return success($res);
}
//获取微信小程序openid
public function getMiniOpenid(){
$code = $this->request->param('code','');//
$site_id = $this->request->param('site_id','');
$wx_config = Config::where('site_id',$site_id)->field('we_chat_pay_miniapp_id,we_chat_pay_miniapp_secret')->find();
$appid = $wx_config['we_chat_pay_miniapp_id'];
$secret = $wx_config['we_chat_pay_miniapp_secret'];
//获取微信小程序openid
// 调用微信接口获取 openid 和 session_key
$url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appid}&secret={$secret}&js_code={$code}&grant_type=authorization_code";
$tokeninfo = $this->http_curl($url); // 发送 HTTP 请求
$tokeninfo = json_decode($tokeninfo, true); // 解析返回的 JSON 数据
if (empty($tokeninfo['openid'])){
return fail('链接失效,请重新扫码');
}
$res = [
'openid'=>$tokeninfo['openid'],//微信openid
];
return success($res);
}
//curl请求
public function http_curl($url){
$curl = curl_init();
//设置抓取的url
curl_setopt($curl, CURLOPT_URL, $url);
//设置头文件的信息作为数据流输出
curl_setopt($curl, CURLOPT_HEADER, 0);
//设置获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//执行命令
$data = curl_exec($curl);
//关闭URL请求
curl_close($curl);
//显示获得的数据
return $data;
}
protected $config = [
'wechat' => [
'default' => [
// 必填-商户号
'mch_id' => '1647413230',
// 必填-v3商户秘钥
'mch_secret_key' => 'jTwAPZXpylR7TCoinWn2srOQUb6ioZlL',
// 必填-商户私钥 字符串或路径
'mch_secret_cert' => 'addon/hygl/wx_mch_cert/100000/apiclient_key.pem',
// 必填-商户公钥证书路径
'mch_public_cert_path' => 'addon/hygl/wx_mch_cert/100000/apiclient_cert.pem',
// 必填
'notify_url' => 'https://zhifuguanli.zeyan.wang/api/hygl/wechatPayNotify',
// 选填-公众号 的 app_id
'mp_app_id' => 'wxd2d733a7163bff05',
'mini_app_id' => 'wx42762c713f7bfa2e',//精准时光-微信小程序appid
// 选填-默认为正常模式。可选为: MODE_NORMAL, MODE_SERVICE
'mode' => Pay::MODE_NORMAL,
]
],
'logger' => [ // optional
'enable' => false,
'file' => './logs/wechat.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,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
];
public function wxMpPay_DEMO(){
$order = [
'out_trade_no' => time().'',
'description' => 'subject-测试',
'amount' => [
'total' => 1,
],
'payer' => [
'openid' => 'oYuE665Oexv3miom7BbuRQgevkHo',
],
];
$pay = Pay::wechat($this->config)->mp($order);
dd($pay);
}
//创建微信公众号支付(JSAPI)
public function wxMpPay(){
$order_id = $this->request->param('order_id','');
$user_id = $this->request->param('user_id','');
$site_id = $this->request->param('site_id','');
if (!$order_id || !$user_id || !$site_id) {
return fail('缺少参数');
}
$order = TransactionHistory::where('id',$order_id)
->where('user_id',$user_id)
->where('pay_status',0)
->find();
if (!$order){
return fail('订单不正确,请重新扫码');
}
$config = $this->initWxPayConfig($site_id);
if(!$config['code']){
return fail($config['msg']);
}
$openid = User::where('id',$user_id)->value('wx_openid');
if (!$openid){
return fail('请重新扫码');
}
$site_name = Site::where('site_id',$site_id)->value('site_name');
$order_pay = [
'out_trade_no' => $order['order_num'],//我方订单号
'description' => $site_name,
'amount' => [
'total' => $order['price'] * 100,//金额(分)
],
'payer' => [
'openid' => $openid,//支付用户的openid
],
];
//拉起微信公众号(JSAPI)支付
$pay = Pay::wechat($config['data'])->mp($order_pay);
return success($pay->toArray());
}
//创建微信小程序支付
public function wxMiniPay(){
$order_id = $this->request->param('order_id','');
$user_id = $this->request->param('user_id','');
$site_id = $this->request->param('site_id','');
if (!$order_id || !$user_id || !$site_id) {
return fail('缺少参数');
}
$order = TransactionHistory::where('id',$order_id)
->where('user_id',$user_id)
->where('pay_status',0)
->find();
if (!$order){
return fail('订单不正确,请重新扫码');
}
$config = $this->initWxPayConfig($site_id);
if(!$config['code']){
return fail($config['msg']);
}
$openid = User::where('id',$user_id)->value('wx_mini_openid');//小程序openid
if (!$openid){
return fail('请刷新页面后再试');
}
$site_name = Site::where('site_id',$site_id)->value('site_name');
$order_pay = [
'out_trade_no' => $order['order_num'],//我方订单号
'description' => $site_name,
'amount' => [
'total' => $order['price'] * 100,//金额(分)
'currency' => 'CNY',
],
'payer' => [
'openid' => $openid,//支付用户的openid
]
];
//拉起微信小程序支付
$pay = Pay::wechat($config['data'])->mini($order_pay);
return success($pay->toArray());
}
//微信公众号支付成功异步回调
public function wechatPayNotify($site_id)
{
$filePath = 'login/test.txt';
$filePath_0 = 'login/test0.txt';
$date = date('Y-m-d H:i:s') . '_$site_id=' .$site_id;
$data = "回调成功了-{$date}"; // 要写入的数据
$site_id = $this->request->param('site_id','');
$config = $this->initWxPayConfig($site_id);//初始化微信支付配置项
$pay = Pay::wechat($config['data']);
try {
// 是的,你没有看错,就是这么简单!返回值为微信回调的订单数据
$data = $pay->callback();
$a = "{$data->summary} - {$data['resource']['ciphertext']['trade_state_desc']}";
file_put_contents($filePath_0,json_encode($data, JSON_UNESCAPED_UNICODE));
Log::write($data->all(),'notice');//记录日志
//判断是否支付成功
if ($data['event_type'] == "TRANSACTION.SUCCESS" && $data['resource']['ciphertext']['trade_state'] == "SUCCESS") {
//支付成功
//防止支付回调成功后重复给用户打款
$order = TransactionHistory::where('order_num', $data['resource']['ciphertext']['out_trade_no'])
->find();//查询我方订单号是否打款
if ($order['pay_status'] == 1) {
//已经支付过了,通知微信停止异步回调
return '';//付款成功
}
//修改订单状态
$cash_fee = $data['resource']['ciphertext']['amount']['payer_total'] ?? 0;
if ($cash_fee > 0){
$cash_fee = bcdiv($cash_fee, 100, 2);
}
$update = TransactionHistory::where('id', $order['id'])
->where('pay_status', 0)
->update([
'pay_num' => $data['resource']['ciphertext']['transaction_id'],//支付平台订单号
'cash_fee' => $cash_fee,//用户实际支付金额(元) 分 / 100=元
'pay_status' => 1,//订单支付状态|默认0:未支付,1:已支付
'pay_time' => time(),//
'pay_data_json' => json_encode($data, JSON_UNESCAPED_UNICODE),//支付回调json字符串
]);
if ($order['user_coupons_id']){
//核销优惠券
UserCoupons::where('id',$order['user_coupons_id'])
->where('is_show',1)
->update([
'is_show'=>0,
]);
}
if (!$update){
Log::write("订单{$data['resource']['ciphertext']['out_trade_no']}支付回调失败", 'error');//记录日志
}
}
} catch (\Exception $exception) {
Log::write($exception->getMessage(), 'error');//记录日志
$data = "错误-{$exception->getMessage()},行={$exception->getFile()},{$exception->getLine()}";
file_put_contents($filePath, $data);
}
$str = '';
return $str;
}
/**
* 初始化微信支付配置项
* @param $site_id 站点id
* @return array[]
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function initWxPayConfig($site_id){
//微信支付配置项目
$wx_config = Config::where('site_id',$site_id)
->find();
if (!$wx_config){
$res = [
'code'=>false,//true=成功,false=失败
'msg'=>'支付配置项不正确',
'data'=>[],
];
}else{
$config = [
'wechat' => [
'default' => [
// 必填-商户号
'mch_id' => $wx_config['we_chat_pay_mch_id'],
// 必填-v3商户秘钥
'mch_secret_key' => $wx_config['we_chat_pay_key'],
// 必填-商户私钥 字符串或路径
'mch_secret_cert' => $wx_config['we_chat_pay_mch_secret_cert'],
// 必填-商户公钥证书路径
'mch_public_cert_path' => $wx_config['we_chat_pay_mch_public_cert_path'],
// 必填
'notify_url' => $wx_config['we_chat_pay_notify_url'],
// 选填-公众号 的 app_id
'mp_app_id' => $wx_config['we_chat_pay_app_id'],
// 「选填」小程序 的 app_id
'mini_app_id' => $wx_config['we_chat_pay_miniapp_id'],
// 选填-默认为正常模式。可选为: MODE_NORMAL, MODE_SERVICE
'mode' => Pay::MODE_NORMAL,
// 「选填」app 的 app_id
'app_id' => ''
]
],
'logger' => [ // optional
'enable' => false,
'file' => './logs/wechat.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,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
];
$res = [
'code'=>true,//true=成功,false=失败
'msg'=>'',
'data'=>$config,
];
}
return $res;
}
}