laravel支付宝支付

541 阅读3分钟

这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

一、支付功能

1.1 支付宝支付安装配置

在这里插入图片描述 然后支付宝扫码登陆。因为个人号是没法去申请支付密钥,所以我们使用它的沙箱环境。 在这里插入图片描述 在这里插入图片描述 沙箱环境下我们这边都可以随便充值金额。


同样的在laravel中开发可以使用第三方包,来加快我们开发的进度,以及非常简便的使用。 在这里插入图片描述 运行命令composer require yansongda/laravel-pay在这里插入图片描述 运行命令php artisan vendor:publish --provider="Yansongda\LaravelPay\PayServiceProvider" --tag=laravel-pay配置文件: 在这里插入图片描述 接着按照文档。生成公钥证书, 下载安装文档指定生成即可。 将下载的证书放到code文件夹下: 在这里插入图片描述 我是将3个证书文件放到自己新建文件夹cert下。 接着修改配置:

'alipay' => [
        'default' => [
            // 支付宝分配的 app_id 沙箱测试就有
            'app_id' => '2021000118617661',
            // 应用私钥
            'app_secret_cert' => '', // 你申请的证书密钥
            // 应用公钥证书 路径
            'app_public_cert_path' => '/home/vagrant/code/cert/appCertPublicKey_2021000118617661.crt',
            // 支付宝公钥证书 路径
            'alipay_public_cert_path' => '/home/vagrant/code/cert/alipayCertPublicKey_RSA2.crt',
            // 支付宝根证书 路径  
            'alipay_root_cert_path' => '/home/vagrant/code/cert/alipayRootCert.crt',
            // 支付成功后同步通知地址
            'return_url' => '',
            // 异步通知地址
            'notify_url' => 'http://8bee-211-97-129-32.ngrok.io/api/pay/notify/aliyun', // 你的支付完成回调地址处理路由,这边采用了内网穿透的方式,在本章第4小节有说到配置
            'mode' => Pay::MODE_SANDBOX, // 沙箱环境,由于我们没有商户号,所以采用沙箱环境配置
            // 'mode' => Pay::MODE_NORMAL, // 正式环境
            
        ],
    ],

在这里插入图片描述

1.2 创建支付控制器

运行命令php artisan make:controller Web/PayController 在这里插入图片描述 写入支付时的方法,以及支付完成时的回调方法:

<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Yansongda\LaravelPay\Facades\Pay;

class PayController extends Controller
{
    // 支付
    public function pay(Request $request, Order $order)
    {
        $request->validate([
            'type' => 'required|in:aliyun,wechat',
        ], [
            'type.required' => '支付类型不能为空',
            'type.in' => '支付类型只能是支付宝或者微信支付'
        ]);

        // 如果订单状态不是1,直接返回
        if ($order->status != 1) {
            return $this->response->errorBadRequest('订单状态异常,请重新下单!');
        }


        if ($request->input('type') == 'aliyun') {


            $order = [
                'out_trade_no' => $order->order_no,
                'total_amount' => $order->amount/100,
                'subject' => $order->goods()->first()->title.' 等 '.$order->goods()->count() .'件商品',
            ];

            return Pay::alipay()->scan($order);
        }
        if ($request->input('type') == 'wechat') {
        }
    }

    /**
     * 支付宝支付成功之后的回调
     */
    public function notifyAliyun(Request $request) {
        $alipay = Pay::alipay();
    
        try{
            $data = $alipay->callback(); // 是的,验签就这么简单!

            // 请自行对 trade_status 进行判断及其它逻辑进行判断,在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
            // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号;
            // 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额);
            // 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email);
            // 4、验证app_id是否为该商户本身。
            // 5、其它业务逻辑情况
             
            // 判断支付状态 成功的状态
            if ($data->trade_status == 'TRADE_SUCCESS' || $data->trade_status == 'TRADE_FINISHED') {
                // 查询订单
                $order = Order::where('order_no', $data->out_trade_no)->first();

                // 更新订单数据 (简单的写,如果要完整的要按照以上5点去写)
                $order->update([
                    'status' => 2, // 支付完成
                    'pay_time' => $data->gmt_payment, // 支付的时间
                    'pay_type' => '支付宝', // 支付的类型
                    'trade_no' => $data->trade_no, // 支付宝的单号 在写的退款的时候会用到
                ]);
            }

            // Log::info($data); 打印log知道回调都给了什么字段 
            Log::debug('Alipay notify', $data->all()); // 打印log知道回调都给了什么字段 
        } catch (\Exception $e) {
            // $e->getMessage();
        }

        return $alipay->success();
    }
}

我们在支付回调时候插入的数据,所以Order.php需要增加可允许批量赋值的字段: 在这里插入图片描述

1.3 创建支付路由

        /**
         * 支付
         */
        $api->get('orders/{order}/pay', [PayController::class, 'pay']);

在这里插入图片描述


1.4 内网穿透

由于我们使用的是本地的域名,外网是访问不到,这个支付宝的回调函数它就请求不到,所以我们这边需要配置内网穿透: 运行命令share shopprojectapi.com
(shopprojectapi.com是你自己配置的域名) 会出现报错:-bash: /usr/local/bin/ngrok: cannot execute binary file: Exec format error 原因很简单,却弄了几个小时,是因为我的电脑是m1 arm64架构的,而homesteadngrok估计不是,所以我们去官网下载ngroklinux 在这里插入图片描述 下载完解压后将虚拟机上这个路径/usr/local/bin/ngrokngrok替换,可以使用工具FileZilla。 替换之后,接着运行命令share shopprojectapi.com ,可以看到: 在这里插入图片描述 接着访问它给我们的域名,可以看到外网已经可以访问到我们的内网项目了: 在这里插入图片描述 在这里插入图片描述


1.5 创建支付完成回调路由

需要注意的是这个回调路由是不需要登陆的,所以放在需要登陆中间件的外面。

    /**
     * 回调
     */ 
    // 支付宝支付成功之后的回调
    $api->any('pay/notify/aliyun', [PayController::class, 'notifyAliyun']);

在这里插入图片描述


1.6 测试效果

支付接口 在这里插入图片描述 生成链接,我们将链接通过该网址转为二维码,下载沙箱测试的支付宝版本 在这里插入图片描述 然后扫描生成的二维码,然后点击支付,支付成功后,我们查看订单是否有数据插入: 在这里插入图片描述 可以看到我们这条订单就是状态2了,并且也有支付宝的订单号。至此我们支付宝支付的功能已经相当完善了。 微信支付的话也是一样的申请商户号,配置方法逻辑和支付宝类似。

在学习的php的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。