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; } }