700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Laravel 集成微信扫码支付

Laravel 集成微信扫码支付

时间:2022-07-24 05:28:56

相关推荐

Laravel 集成微信扫码支付

前期准备:

1.下载SDK,里面还有Demo,可以参照Demo里面的内容快速接入

微信扫码支付SDK与DEMO下载

2.把下载的zip文件解压,放到项目目录里,这里作者放在app文件夹里,方便查看

然后在根目录的composer.json文件的autoload数组中的classmap中加入该文件夹的路径,代码如下:

"autoload" : {"classmap" : ["database/seeds","database/factories","vendor/yansongda/pay/src","vendor/yansongda/supports/src","app/WeChatPay","app/AliPay"],"psr-4" : {"App\\" : "app/"}},

这里特别要注意,在引入命名空间后,要执行一下composer的自动加载类命令(应该是这个意思)

首先,进入项目的根目录,然后执行下面的命令

composer dump-autoload

这个命令很重要,不然上面加入的微信支付的类文件无法被识别

作者就在这里吃了大亏,说到底是对这个框架不熟悉

3.因为Laravel框架的原因,文件的入口在/public/index.php这个文件这里,所以所有需要require的文件的路径都要在相应的文件里修改一下,这里作者的路劲修改后举例为:

require_once '../app/AliPay/config.php';

为了方便使用,对部分类文件使用命名空间,这样使用起来目标明确,虽然会额外费点功夫,但作者觉得思路最重要。

因为是支付这块的内容,然后为了区别微信支付还有网银支付,所以命名空间定为:

namespace APP\Pay\WxPay;

4.为了方便日后管理,把一些相关的类文件集中起来放置在一个文件夹里,文件夹名为 qy ,意为为企业支付建立的这个文件夹

qy文件夹内有2个目录:

base: 存放一些基础的类文件,如配置等

notify : 存放相关的接口实现类

plugins: 存放一些需要的插件类,如二维码生成(phpqrcode.php)

Tool.php:工具类,存放如获取客户端IP等方法

这里对部分需要引入命名空间的文件列举一下(目前只做了支付,退款还没做,所以退款涉及的类文件不做举例)

//接口访问类/app/WeChatPay/lib/WxPay.Api.php//回调基础类/app/WeChatPay/lib/WxPay.Notify.php//配置类/app/WeChatPay/qy/base/WxPay.Config.php//刷卡支付实现类,封装了一些辅助方法/app/WeChatPay/qy/base/WxPay.NativePay.php//真正的微信支付回调类/app/WeChatPay/notify/WxPay.NotifyQY.php//工具类/app/WeChatPay/Tool.php

这里特别要注意,在引入命名空间后,要执行一下composer的自动加载类命令(应该是这个意思)

首先,进入项目的根目录,然后执行下面的命令

composer dump-autoload

这个命令很重要,不然上面引入命名空间的类文件无法被识别

作者就在这里吃了大亏,说到底是对这个框架不熟悉

这里只列举了部分需要引入命名空间的类文件,有些没列举到的,大家把微信支付功能跑起来后,再根据错误提示加上去就行了

还有,部分文件因为在第2步的composer.json里已经自动引入了,所以只需要在类名前加上 \ (反斜杠符号),即可使用

5.配置支付宝接口需要的基础信息,在/app/WeChatPay/qy/base/WxPay.Config.php这个文件里设置,这步按照里面的说明去修改就行了,没什么好说的

开始调用接口

6.前端 - 传递下单的金额,调用后端预下单接口(即第7步的接口),然后显示生成的支付二维码,轮询订单状态

Html部分

<!-- 温馨提示窗口 Start --><div class="modal fade pay-warp" id="payWarpModel" role="dialog" tabindex="-1"><div class="modal-dialog modal-center"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span>×</span></button><h4 class="modal-title pay_status" style="padding-bottom:10px;margin-bottom:10px;border-bottom:1px solid #ccc;">正在支付...</h4><table><tr><td class="pay-title font-size-18">支付类型:</td><td class="pay-info font-size-14">微信支付</td></tr><tr><td class="pay-title font-size-18">支付金额:</td><td class="pay-info font-size-14"><span class="money">00.0</span>&nbsp;元</td></tr><tr><td class="pay-title font-size-18">支付订单号:</td><td class="pay-info font-size-14"><span class="order_no"></span></td></tr><tr><td class="" colspan=2><div class="nr"><img class="qrcode" src="" alt="Base64 encoded image" width="200" height="200"/></div></td></tr><tr><td class="pay-title font-size-18 padding-right-10">开始充值时间:</td><td class="pay-info font-size-14"><span class="code-time"></span></td></tr><tr><td class="pay-title font-size-18">付款成功:</td><td class="pay-info font-size-14"><a class="record hide" target="_blank" href="/user/idc/flow/index">查看充值记录</a><a class="pay-warp-close" href="javascript:$('#payWarpModel').modal('hide');">继续充值</a></td></tr><tr><td class="pay-title font-size-18">付款失败:</td><td class="pay-info font-size-14">联系我司客服(<a href="/about/contact" target="_blank">联系方式</a>)<!-- <p><a class="pay-warp-close" href="javascript:;">选择其他支付方式</a></p> --></td></tr></table><button type="button" class="btn btn-danger btn-cancel" data-dismiss="modal" aria-label="Close">取消</button></div></div></div></div><!-- 温馨提示窗口 End -->

JavaScript部分

//显示微信充值细节弹窗function showPayWarpModel(){$("#payWarpModel").modal('show');}//关闭微信充值细节弹窗function hidePayWarpModel(){$("#payWarpModel").modal('hide');}//轮询查询微信支付订单状态function queryWxPayOrder(trade_no){var func = setInterval(queryWxPay, 800);function queryWxPay(){$.post("/user/queryOrderWxPay",{_token:"{{csrf_token()}}", trade_no:trade_no},function(json){if(json.return_code=="SUCCESS" && json.result_code=="SUCCESS" && json.trade_state=="SUCCESS"){$('.pay_status').html("支付成功");setTimeout(function(){hidePayWarpModel();//订单支付成功,刷新页面window.location = "/user/...";}, 800);} else{$('.pay_status').html("支付正在校验,请不要关闭页面,稍后...");}},"json").error(function(xhr, errorText, errorType){...});}}//充值按钮绑定事件$("#btnRecharge").click(function(){$_money = $("input#money");var money = $_money.val();var min = "1";var msg = "";if(money==""){msg = "请填写充值金额";}if(parseFloat(money)<parseFloat(min)){msg = "充值金额不能小于充值最小金额,请重新填写";}if(msg!=""){$_money.val(money).focus();alert(msg);return false;}var send = {_token:$('meta[name="csrf-token"]').attr('content'),money:money};$("#payWarpModel .money").html(money);$.ajax({url : "/user/weChatPay",type : "POST",dataType : "json",data : send,success : function(json){if(json.code){showPayWarpModel();$("#payWarpModel .order_no").html(json.data.trade_no);$("#payWarpModel .code-time").html(json.data.time);$("#payWarpModel .qrcode").attr('src',json.data.imgData);//生成支付二维码后,开始查询订单状态queryWxPayOrder(json.data.trade_no);} else{alert("生成付款二维码失败,请重试!");}},error : function(xhr){...}});});

7.后端 - 生成支付订单,打印(返回)下单结果(不知道这样子描述是否有误。。)

use App\Pay\WxPay\NativePay;use APP\Pay\WxPay\Tool as WxTool;use App\Pay\WxPay\WxPayApi;use App\Pay\WxPay\WxPayConfig;//生成微信预支付订单public function weChatPay(Request $request){if(!$request->has('money') || floatval($request->money)<floatval(config('recharge.minRecharge'))){$this->jsonError('参数错误');return false;}//付款金额,必填$money = $request->money;$totalFee = floatval($money)*100;$totalFee = 1;$notify = new NativePay();//模式二/*** 流程:* 1、调用统一下单,取得code_url,生成二维码* 2、用户扫描二维码,进行支付* 3、支付完成之后,微信服务器会通知支付成功* 4、在支付成功通知中需要查单确认是否真正支付成功(见:notify.php)*/$body = $this->getBody();$outTradeNo = $this->getOutTradeNo(5);$input = new \WxPayUnifiedOrder();$input->SetBody($body);$input->SetAttach("{}");$input->SetOut_trade_no($outTradeNo);$input->SetTotal_fee($totalFee);$input->SetTime_start(date("YmdHis"));$input->SetTime_expire(date("YmdHis", time() + 600));$input->SetGoods_tag("test");$input->SetNotify_url('http://paysdk./notify.php');$input->SetTrade_type("NATIVE");$input->SetProduct_id("00001");$result = $notify->GetPayUrl($input);$url = $result["code_url"];if($result['return_code']=="SUCCESS" && $result['result_code']=="SUCCESS"){//预生成充值订单 - 微信扫码支付$remarks = $this->_toJsonString($result, ['appid','mch_id','trade_type','prepay_id','result_code','return_code']);$this->addChargeRecord($money, "weixin", $outTradeNo, 1, $remarks);require_once '../app/WeChatPay/qy/plugins/phpqrcode/phpqrcode.php';$url = urldecode($url);if(substr($url, 0, 6) == "weixin"){$imgData = $this->getWxPayQRcode($url);$this->ajaxData(Array("imgData" => $imgData,"trade_no" => $outTradeNo,"time" => date("Y-m-d H:i:s")));}else{header('HTTP/1.1 404 Not Found');}} else{//生成失败预充值订单if($res['return_code']=="SUCCESS"){//通信成功$remarks = $this->_toJsonString($res, ['appid','mch_id','trade_type','prepay_id','result_code','return_code']);$this->addFailedChargeRecord($money, "weixin", $outTradeNo, 1, $res['err_code_des'], $remarks);} else{//通信失败$remarks = $this->_toJsonString($res);$this->addFailedChargeRecord($money, "weixin", $outTradeNo, 1, $res['return_msg'], $remarks);}$this->ajaxError("生成微信充值订单失败");}}//按传入的url生成支付二维码,如果后端有上传logo,则加入function getWxPayQRcode($url){$config = new WxPayConfig();//获取微信支付二维码中央小LOGO$logo = $config->GetWxLogo();header("Content-Type: image/png");ob_start();\QRcode::png($url, false, "H", 3);$qr = ob_get_contents();ob_end_clean();//如果Logo存在if($logo && file_exists(storage_path('app/public')."/".$logo)){ob_start();$qr = imagecreatefromstring($qr);$logo = imagecreatefromstring(file_get_contents("http://".$_SERVER['HTTP_HOST']."/storage/".$logo));$qr_width = imagesx($qr);//二维码图片宽度$qr_height = imagesy($qr);//二维码图片高度$logo_width = imagesx($logo);//logo图片宽度$logo_height = imagesy($logo);//logo图片高度$logo_qr_width = $qr_width/4;//logo嵌入二维码图片后的新宽度,即二维码图片宽度的4分之一$scale = $logo_qr_width/$logo_width;//logo新宽度与logo原宽度的比例,即缩放比例$logo_qr_height = $logo_height*$scale;//logo嵌入二维码图片后的新高度,按缩放比例获取$from_width = ($qr_width - $logo_qr_width)/2;//新logo(缩放后)在二维码图片中的横坐标$from_height = ($qr_height - $logo_qr_height)/2;//新logo(缩放后)在二维码图片中的纵坐标$result = imagecopyresampled($qr, $logo, $from_width, $from_height, 0, 0, $logo_qr_width, $logo_qr_height, $logo_width, $logo_height);imagepng($qr, null);$data = ob_get_contents();ob_end_clean();$qr = "data:image/png;base64,".base64_encode($data);} else{$qr = "data:image/png;base64,".base64_encode($qr);}return $qr;}//按传入的键值获取数组对应的值,转为字符串function _toJsonString($data, $keys=null){$str = "";$type = gettype($data);switch($type){case "string":$str = "{\"data\":\"{$data}\"}";break;case "object":case "array":$str .= "{";$data = json_decode(json_encode($data), true);foreach($data as $k => $v){if($keys === null){$str .= "\"{$k}\":\"{$v}\", ";} else{if(in_array($k, $keys))$str .= "\"{$k}\":\"{$v}\", ";}}$str = substr($str, 0, -2)."}";break;}return $str;}

8.后端 - 支付结果异步通知接口 ,这里只能在异步通知接口里调用第9步我们自己写的微信回调处理类

use App\Pay\WxPay\WxPayConfig;use App\Pay\WxPay\WxPayNotifyQY;public function WxPayNativeCallBack(Request $request){$config = new WxPayConfig();$notify = new WxPayNotifyQY();$notify->Handle($config, false);}

9.真正的回调处理类,这里需要我们处理的只有NotifyProcess 这个函数

<?phpnamespace App\Pay\WxPay;use App\Http\Controllers\PayController as UserPayController;use App\Pay\WxPay\WxPayApi;use App\Pay\WxPay\WxPayConfig;use App\Pay\WxPay\WxPayNotify;use Illuminate\Support\Facades\Log;class WxPayNotifyQY extends WxPayNotify{//查询订单public function Queryorder($transaction_id){$input = new \WxPayOrderQuery();$input->SetTransaction_id($transaction_id);$config = new WxPayConfig();$result = WxPayApi::orderQuery($config, $input);Log::DEBUG("query:" . json_encode($result));if(array_key_exists("return_code", $result)&& array_key_exists("result_code", $result)&& $result["return_code"] == "SUCCESS"&& $result["result_code"] == "SUCCESS"){return true;}return false;}/**** 回包前的回调方法* 业务可以继承该方法,打印日志方便定位* @param string $xmlData 返回的xml参数***/public function LogAfterProcess($xmlData){Log::DEBUG("call back, return xml:" . $xmlData);return;}//重写回调处理函数/*** @param WxPayNotifyResults $data 回调解释出的参数* @param WxPayConfigInterface $config* @param string $msg 如果回调处理失败,可以将错误信息输出到该方法* @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调*/public function NotifyProcess($objData, $config, &$msg){$data = $objData->GetValues();//TODO 1、进行参数校验if(!array_key_exists("return_code", $data) ||(array_key_exists("return_code", $data) && $data['return_code'] != "SUCCESS")) {//TODO失败,不是支付成功的通知//如果有需要可以做失败时候的一些清理处理,并且做一些监控$msg = "异常异常";Log::error("微信支付回调 WxPayNotify NotifyProcess 进行参数校验 ".$msg);return false;}if(!array_key_exists("transaction_id", $data)){$msg = "输入参数不正确";Log::error("微信支付回调 WxPayNotify NotifyProcess 进行参数校验 ".$msg);return false;}//TODO 2、进行签名验证try {$checkResult = $objData->CheckSign($config);if($checkResult == false){//签名错误Log::error("微信支付回调 WxPayNotify NotifyProcess 签名错误... ");return false;}} catch(Exception $e) {Log::ERROR("微信支付回调 WxPayNotify NotifyProcess 签名失败... ".json_encode($e));}//TODO 3、处理业务逻辑$notfiyOutput = array();//查询订单,判断订单真实性if(!$this->Queryorder($data["transaction_id"])){$msg = "订单查询失败";Log::error("微信支付回调 WxPayNotify NotifyProcess 3、处理业务逻辑 ".$msg );return false;}$PayController = new UserPayController();$PayController->UserCharge($data['total_fee']*100, "weixin", $data['out_trade_no'], $data['openid'], 1, $data['mch_id'], $data['appid']);return true;}}

10.支付接口、查询接口对应的回调处理

/*** [会员充值回调处理]* @param int $money [订单金额]* @param int $payType [订单类型 weixin|alipay]* @param int $outTradeNo [商户订单号]* @param int $payAccount [支付账号]* @param int $status [支付状态]* @param int $appID [商务ID]* @param int $smId [收款支付宝账号对应的支付宝唯一用户号/微信支付分配的商户号]*/function UserCharge($money, $payType, $outTradeNo, $payAccount, $status, $smId, $appID=null){//支付类型 判断设置 日志类型$payLogType = "";if($payType=="alipay") $payLogType='Alipay';else if($payType=="weixin") $payLogType='WechatPay';//防止异步支付通知接口与查询接口同时调用回调处理,使用事务,通知在事务内使用lockForUpdate阻止同时读取修改用户的信息DB::beginTransaction();$Function= new Function();//按照商务订单号获取预充值订单$record = $Function->getUserChargeRecordByOutTradeNo($outTradeNo);$record = json_decode(json_encode($record),true);$remarks = json_decode($record['remarks'],true);if($record['status']!="0"){//已经处理过充值回调,直接返回true//防止多次处理return true;}/* -------------------- 检验 开始 -------------------- */$msg = "";$checkResult=1;//检验1:out_trade_no 商务订单号if($outTradeNo != $record['trade_no']){$msg = "商务订单号参数错误";$checkResult = 0;}//检验2:total_amount/total_fee 实际金额if($checkResult==1 && floatval($money) != floatval($record['money'])){$msg = "订单金额参数错误";$checkResult = 0;}//检验3:app_id/appid 商务号ID//支付宝查询订单时未返回这个参数,跳过这个检查if($checkResult==1 && $appID != null){if($payType == "alipay" && $appID != $remarks['app_id']){$msg = "支付宝分配给开发者的应用ID参数错误";$checkResult = 0;} else if($payType == "weixin" && $appID != $remarks['appid']){$msg = "微信支付分配的公众账号ID参数错误";$checkResult = 0;}}//检验4:seller_id/mch_idif($checkResult==1 && $payType == "alipay" && $smId != $remarks['seller_id']){$msg = "收款支付宝账号参数错误";$checkResult = 0;} else if($checkResult==1 && $payType == "weixin" && $smId != $remarks['mch_id']){$msg = "商户号参数错误";$checkResult = 0;}if($checkResult == 0){Log::error("用户充值失败,out_trade_no为{$outTradeNo},原因为{$msg}");$this->writePayLog("用户充值失败,out_trade_no为{$outTradeNo},原因为{$msg}", $payLogType);//更新用户预充值记录信息$res = ...;if(!$res){DB::rollback();Log::error("用户充值失败,更新充值表失,out_trade_no为{$outTradeNo},原因为{$msg}");$this->writePayLog("用户充值失败,更新充值表失败,out_trade_no为{$outTradeNo},原因为{$msg}", $payLogType);} else{DB::commit();Log::info("用户充值失败,更新充值表成功,out_trade_no为{$outTradeNo},原因为{$msg}");$this->writePayLog("用户充值失败,更新充值表成功,out_trade_no为{$outTradeNo},原因为{$msg}", $payLogType);}return Array('result'=>0,'msg'=>$msg);}/* -------------------- 检验 结束 -------------------- *///检验通过,开始处理业务流程//更新充值表...//更新用户余额...DB::commit();}

11.实现查询接口。

在第6步的JavaScript部分的调用后端预下单接口时,会回传商务订单号(out_trade_no)。

然后调用JavaScript部分的queryWxPayOrder方法,调用后端的查询订单接口。

接口代码如下:

//查询微信支付订单function queryOrderWxPay(Request $request){if(!$request->has('trade_no') || empty($request->trade_no)){$this->ajaxError("参数错误");return false;}$tradeNo = $request->trade_no;$input = new \WxPayOrderQuery();$input->SetOut_trade_no($tradeNo);$config = new WxPayConfig();$response = WxPayApi::orderQuery($config, $input);if(array_key_exists("return_code", $response) && array_key_exists("result_code", $response) && $response['return_code'] == "SUCCESS" &&$response['result_code'] == "SUCCESS" &&$response['trade_state'] == "SUCCESS"){DB::beginTransaction();$outTradeNo = $response['out_trade_no'];$UserFunction = new UserFunction();$record = $UserFunction->getUserChargeRecordByOutTradeNo($outTradeNo);$record = json_decode(json_encode($record), true);if($record['status']==0){//未处理过充值回调,防止多次处理Log::info(" 充值后轮询更新用户信息 ");$this->UserCharge(floatval($response['total_fee'])*100,'weixin',$outTradeNo,$response['openid'],1,$response['mch_id'],$response['appid']);}DB::commit();}return json_encode(Array("return_code" => $response['return_code'],"result_code" => $response['result_code'],"trade_state" => $response['trade_state'],),true);}

后续有时间再做完善这篇文章

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。