分享

Laravel+easywechat 实现公众号微信支付 | Laravel China 社区

 中间件 2021-08-20

laravel 项目直接在终端跑以下命令:

composer require overtrue/wechat:~4.0

然后创建配置文件:

php artisan vendor:publish --provider="Overtrue\LaravelWeChat\ServiceProvider"

创建配置文件完成后会在你项目的 config 文件夹下生成一个 wechat.php 的文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
编辑 wechat.php,这截图的是默认屏蔽的,看你个人需要释放相关代码。并填上相关参数,app_id,mch_id 等等。可在.env 里面配置,如果觉得麻烦可直接写在 default 里面。至此所有准备工作完毕。

代码块

1,laravel 路由

Route::middleware('wechat.oauth', 'wechat')->group(function () {
    Route::get('/pay', 'CourseController@pay');//支付路由
});
 Route::post('/order/notify', 'OrderController@notify');//回调路由

注意
1.1,回调路由必须在 middleware 中间件路由外面,否则微信请求不到。
1.2,回调路由必须是 post 请求。
1.3,laravel 框架必须取消回调路由的 csrf 防护。在你项目的 app/Http/Middleware/VerifyCsrfToken.php 中加入如下代码:

protected $except = [
        'order/notify',//回调路由取消csrf防护
    ];

2,支付流程
2.1,点击支付按钮,ajax 提交相应参数到后台支付方法。
2.2,后台接收数据,往你的订单表里插入一条订单数据,状态为 0,也就是未支付状态。
2.3,带上这条订单的订单号,价格,请求微信换取 prepay_id。
2.4,请求微信成功会返回支付所需要的参数,appid,timestamp 等。返回前端 js 调起支付。
2.5,支付后微信会将支付结果通过回调返回,可根据返回信息更改订单状态,或者进行其他操作。

3,项目代码
3.1,前端 js 代码

var a;
$('.pay').click(function () {
    var course_id=$(this).val();//购买商品的id
    var price=$('.price').text();//购买商品的价格
    $.ajax({
        type:"GET",
        url:"/wechat/course/pay",
        data:{course_id:course_id,price:price},
        success:function (config) {
                a = config;//请求微信成功返回的支付参数
                callpay()
        }
    })
});
//调用微信JS api 支付
function jsApiCall() {
    WeixinJSBridge.invoke(
        'getBrandWCPayRequest', a,
        function (res) {
            WeixinJSBridge.log(res.err_msg);
            if (res.err_msg == 'get_brand_wcpay_request:ok') {
                window.location.reload();
            } else {
                // alert('取消支付');
            }
        }
    );
}

function callpay() {
    if (typeof WeixinJSBridge == "undefined") {
        if (document.addEventListener) {
            document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
        } else if (document.attachEvent) {
            document.attachEvent('WeixinJSBridgeReady', jsApiCall);
            document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
        }
    } else {
        jsApiCall();
    }
}

3.2,控制器代码:

 //微信支付
    public function pay(Request $request)
    {
        $customer = session('wechat.customer');
        $customer_id = $customer['id'];
        $price = $request->get('price');
        $order = PcOrder::create([
                'user_id' => $customer_id,
                'out_trade_no' => date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT) . rand(1000, 9999),
                'total_price' => $price,
                'status' => 0,//0未支付 1已支付
                'course_id' => $request->get('course_id'),
            ]);
            $original = session('wechat.oauth_user.default.original');
            $openid = $original['openid'];
            $payment = \EasyWeChat::payment(); // 微信支付实例

            $total_fee = $price * 100;//微信支付以分为单位 
            //统一下单
            $result = $payment->order->unify([
                'body' => '微信支付',
                'out_trade_no' => $order['out_trade_no'],
                'total_fee' => $total_fee,
                'notify_url' => 'https://www.********.com/order/notify', //回调地址,用于接收微信支付结果
                'trade_type' => 'JSAPI',
                'openid' => $openid,
            ]);

            if ($result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS') {
                $prepayId = $result['prepay_id'];
                $jssdk = $payment->jssdk;
                $config = $jssdk->sdkConfig($prepayId);
                return $config;
            } else {
                return $result;
            }
    }

注意
1,如果支付时出现报错,timestame 参数问题。这是 easywechat 底层文件出错了。
解决办法:在你项目的 vendor/overtrue/wechat/src/Payment/Jssdk/Client.php 中把第 70 行和第 71 行代码屏蔽了就行。

3.3,回调代码:

 /**
     * 微信测评支付回调方法,修改订单状态
     * @return mixed
     */
    public function notify()
    {
        $payment = \EasyWeChat::payment();
        $response = $payment->handlePaidNotify(function ($message, $fail) {
            if ($message['return_code'] === 'SUCCESS' && $message['result_code'] === 'SUCCESS') {
                \Log::debug($message);
                 PcOrder::where('out_trade_no', $message['out_trade_no'])->update(['status' => 1, 'pay_time' => time()]);//更改订单状态
                //支付后,微信会在此处返回支付状态,就是$message,回调里面打印不出来,可通过写入日志里面查看,支付成功后更改订单状态。当然你也可以进行其他操作。
                return true;
            } else {
                \Log::debug('我不买了');
                return $fail('失败');
            }
        });
        return $response;
    }

3.4,回调日志:

[2019-11-27 19:00:03] local.DEBUG: array (
  'appid' => '**************',
  'bank_type' => 'CFT',
  'cash_fee' => '1',
  'fee_type' => 'CNY',
  'is_subscribe' => 'Y',
  'mch_id' => '*************',
  'nonce_str' => '*******',
  'openid' => '*****************',
  'out_trade_no' => '20191127733582017',
  'result_code' => 'SUCCESS',
  'return_code' => 'SUCCESS',
  'sign' => '************',
  'time_end' => '20191127190001',
  'total_fee' => '1',
  'trade_type' => 'JSAPI',
  'transaction_id' => '**************',
)

结束

1,本人是一个萌新 php,很多都不懂,这是我上班时碰到的问题,所以记录下来,希望对和我一样的新手有所帮助,如有疑问评论即可。
2,大佬们看到此文章如有错误之处请多多指教,万分感谢。

本作品采用《CC 协议》,转载必须注明作者和本文链接                         

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多