使用easywechat和THINKPHP6做小程序支付

时间:2024-02-20 12:34:44

在项目中用到小程序支付,费话不多说上代码

因为我这涉及么微信的很多开发功能  所以我把公共的方法放到的公共类中

WechatPublic
<?php
namespace app\zhonglian\controller\wechat;
use app\BaseController;
use think\facade\Config;
use EasyWeChat\Factory;
use app\zhonglian\controller\ZhonglianPublic;
class WechatPublic extends ZhonglianPublic{
    public $config;         //公众号配置文件
    public $app;            //公众号配置
    public $minConfig;      //小程序配置
    public $wechatPay;      //微信支付配置
    public function __construct(){
        $this->config = [
            /**
             * 账号基本信息,请从微信公众平台/开放平台获取
             */
            \'app_id\'  => Config::get(\'zhonglian.wechat.AppID\'),      // AppID
            \'secret\'  => Config::get(\'zhonglian.wechat.AppSecret\'),     // AppSecret
            \'token\'   => Config::get(\'zhonglian.wechat.token\'),      // Token
            \'aes_key\' => Config::get(\'zhonglian.wechat.aes_key\'),    // EncodingAESKey,安全模式与兼容模式下请一定要填写!!!
            \'response_type\' => \'array\',
        ];
        // 小程序
        $this->minConfig = [
            \'app_id\' => Config::get(\'zhonglian.minWechat.AppID\'),
            \'secret\' => Config::get(\'zhonglian.minWechat.AppSecret\'),
        
            // 下面为可选项
            // 指定 API 调用返回结果的类型:array(default)/collection/object/raw/自定义类名
            \'response_type\' => \'array\',
            \'log\' => [
                \'level\' => \'debug\',
                \'file\' => __DIR__.\'/wechat.log\',
            ],
        ];
        $this->webHost = \'https:://\'.$_SERVER[\'HTTP_HOST\'];   //站点域名
        //微信支付
        $this->wechatPay    =   [
            // 必要配置
            \'app_id\'             => Config::get(\'zhonglian.wechatPay.app_id\'),
            \'mch_id\'             => Config::get(\'zhonglian.wechatPay.mch_id\'),
            \'key\'                => Config::get(\'zhonglian.wechatPay.key\'),   // API 密钥

            // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
            \'cert_path\'          => \'V6/wechatpay/apiclient_cert.pem\', // XXX: 绝对路径!!!!
            \'key_path\'           => \'V6/wechatpay/apiclient_key.pem\',  // XXX: 绝对路径!!!!
            \'notify_url\'         => $this->webHost.\'/zhonglian/zl/pay_notify\',     // 你也可以在下单时单独设置来想覆盖它
        ];
        
        $this->app = Factory::officialAccount($this->config);
        $this->minApp = Factory::miniProgram($this->minConfig);
        $this->pay = Factory::payment($this->wechatPay);
    }
}

Pay

<?php
namespace app\zhonglian\controller\wechat;
use app\zhonglian\controller\wechat\WechatPublic;
use app\zhonglian\model\UserAccessToken;
use app\zhonglian\model\UserZhonglianOrder;
use think\Controller;
use EasyWeChat\Foundation\Application;
use think\exception\ValidateException;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Messages\Text;
use think\facade\Log;

use app\zhonglian\validate\Pay as PayV;
class Pay extends WechatPublic{
    public function pay(){
        if(request()->isPost()){
            $data = input(\'post.\');
            try {
                validate(PayV::class)
                    ->scene(\'pay\')
                    ->check($data);
            } catch (ValidateException $e) {
                // 验证失败 输出错误信息
                return json([\'code\'=>10001,\'msg\'=>$e->getError()]);
            }
            $data[\'orderId\'] = date(\'YmdHis\', time()).rand(10000,99999);
            $data[\'userId\'] = UserAccessToken::where(\'accessToken\',$data[\'access_token\'])->value(\'userId\');
            //存入数据至本地表
            $res = UserZhonglianOrder::addData($data);
            $result = $this->pay->order->unify([
                \'body\'          => $data[\'body\'],
                \'out_trade_no\'  => $date[\'orderId\'],
                \'total_fee\'     => floatval($data[\'total_fee\'] * 100),
                \'spbill_create_ip\' => \'\', // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
                \'notify_url\'    => $this->webHost.\'/zhonglian/zl/pay_notify\', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
                \'trade_type\'    => \'JSAPI\', // 请对应换成你的支付方式对应的值类型
                \'openid\'        => $data[\'openid\'],
            ]);
            /*$result返回数据如下
            $result = [
                "return_code" => "SUCCESS",         
                "return_msg" => "OK",
                "appid" => "****************",
                "mch_id" => ""****************",",
                "nonce_str" => "oYRmqEGsfV95H221",
                "sign" => "37DC4CB564102893FC8C09C488D2FA00",
                "result_code" => "SUCCESS",
                "prepay_id" => "wx0411540670981758f0ccc5845afd110000",
                "trade_type" => "JSAPI"
            ];
            */
            if($result[\'return_code\'] != \'SUCCESS\' || $result[\'result_code\'] != \'SUCCESS\'){
                return json([\'code\'=>1,\'msg\'=>\'获取支付订单失败\']);
            }else{
                if ($res) {
                    $jssdk = $this->pay->jssdk;
                    $config = $jssdk->bridgeConfig($result[\'prepay_id\'], false);
                    return json([\'code\'=>0,\'data\'=>$config]);
                } else {
                    return json([\'code\'=>1,\'msg\'=>\'创建订单失败!\']);
                }    
            }
            /*$config返回如下
            [
                \'appId\' => \'wx9ae6b16168110e36\',
                \'timeStamp\' => \'1604475465\',
                \'nonceStr\' => \'5fa25a49a887b\',
                \'package\' => \'prepay_id=wx0411540670981758f0ccc5845afd110000\',
                \'signType\' => \'MD5\',
                \'paySign\' => \'A332227D36EC94B3610A86C8049F069C\',
              ]
            */
        }  
    }
    //支付回调
    public function pay_notify(){
        $response = $this->pay->handlePaidNotify(function($message, $fail){
            $order = Db::name(\'order\')->where([\'order\'=> $message[\'out_trade_no\']])->find();
            if (!$order || $order[\'status\']==2) { // 如果订单不存在 或者 订单已经支付过了
                return true;
            }

            if ($message[\'return_code\'] === \'SUCCESS\') { // return_code 表示通信状态,不代表支付状态
                // 用户是否支付成功
                if ($message[\'result_code\'] === \'SUCCESS\') {
                 //成功处理操作 略
          //$message[\'out_trade_no\']  商户订单号
// 用户支付失败
                } elseif ($message[\'result_code\'] === \'FAIL\') {
                    return true;
                }
            } else {
                return false;
            }
        });
        return $response;
    }

    public function get_openid()
    {
        $code = $this->request->param(\'code\');
        $res = $this->app->auth->session($code);
        return json($res);
    }
}

小程序

getUserInfo: function (e){
    var that = this;
    if (e.detail.userInfo) {
      wx.login({
        success: res_user => {
          http.Get("/zhonglian/zl/get_openid", {code:res_user.code}, function (res) {
            console.log(res.data)
            wx.setStorageSync(\'openid\', res.data.openid);
            wx.setStorageSync(\'nickname\', e.detail.userInfo.nickName);
            wx.setStorageSync(\'image\',  e.detail.userInfo.avatarUrl);
            wx.setStorageSync(\'sex\',   e.detail.userInfo.gender);
            that.setData({login:false})
          });
        }
      })  
    } else {
      console.log(\'用户拒绝了授权\')
      wx.showToast({
        title: "为了您更好的体验,请同意授权登陆",
        icon: \'none\',
        duration: 2000
      });
    }
  },
pay:function (){
    var that = this
    var formData = {
      access_token: \'***********\',
      total_fee: 0.01,
      openid: wx.getStorageSync(\'openid\'),
      body: \'支付产品\',
    }
    http.Post("/zhonglian/zl/pay", formData, function (res) { 
        console.log(res.data);  
        console.log(\'调起支付\');  
        wx.requestPayment({  
          \'timeStamp\': res.data.timeStamp,  
          \'nonceStr\': res.data.nonceStr,  
          \'package\': res.data.package,  
          \'signType\':\'MD5\',  
          \'paySign\': res.data.paySign,  
          \'success\':function(resa){              
            console.log(\'支付成功\')
          },  
          \'fail\':function(err){ 
            console.log(\'支付失败\');  
          } 
        });  
     
    });
  },