微信小程序支付封装-复制即用

主要三个页面,一个微信小程序页面,一个请求接口文件,一个回调页面

过程:小程序请求后端接口文件,付款成功后触发回调页面

微信小程序页面

    zhifu() {
    
    
      this.pay();
    },
    pay(total_fee) {
    
    
      var total_fee = total_fee;
      wx.login({
    
    
        success: res => {
    
    
          //code 用于获取openID的条件之一
          var code = res.code;
          wx.request({
    
    
            url: 后台接口文件,
            method: "POST",
            data: {
    
    
              total_fee: total_fee,
              code: code,
            },
            header: {
    
    
              'content-type': 'application/x-www-form-urlencoded' // 默认值
            },
            success: function (res) {
    
     //后端返回的数据
              var data = res.data;
              console.log(data);
              console.log(data["timeStamp"]);
              wx.requestPayment({
    
    
                timeStamp: data['timeStamp'],
                nonceStr: data['nonceStr'],
                package: data['package'],
                signType: data['signType'],
                paySign: data['paySign'],
                success: function (res) {
    
    
                  wx.showModal({
    
    
                    title: '支付成功',
                    content: '',
                  })
                },
                fail: function (res) {
    
    
                  console.log(res);
                }
              })


            }
          });


        }
      })

    },

后端 接口文件

<?php

$aaa = new PayController;
$aaa->pay($_POST['code']);

class PayController
{
    
    
    public function __construct()
    {
    
    
        // 支付
        // $this->appid =  'w 8c3a'; //微信支付申请对应的公众号的APPID
        // $this->appKey = '5895b ef6e327489f'; //微信支付申请对应的公众号的APP Key,绑定公众号做的小程序,所以虽然商户号这些是属于公众号的,但是这里必须使用小程序加公众号的信息
         // 操作方法 添加特约商户号关联起来,在商户号后台关联小程序即可,调用时候使用小程序的appid,即 需要使用的 小程序appid+小程序AppSecret + 公众号mchid + 公众号apiKey
        $this->mchid = '148 022'; //https://pay.weixin.qq.com 产品中心-开发配置-商户号
        $this->apiKey = 'lnh rvjw';   //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥

        $this->xiaoAppid = "wxa4 e31";   /* 小程序appid */
        $this->xiaoAppSecret  = "d5 55c";/* 小程序AppSecret */

        // //回调的url【自己填写】
        $this->notify_url = '回调/notify.php';

    }
    //微信支付
    public function pay($code)
    {
    
    
        //获取openid
        if ($code) {
    
       //用code获取openid
            $code = $code;
            $WX_APPID =  $this->xiaoAppid; //appid
            $WX_SECRET =   $this->xiaoAppSecret; //AppSecret
            $url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $WX_APPID . "&secret=" . $WX_SECRET . "&js_code=" . $code . "&grant_type=authorization_code";
            $infos = json_decode(file_get_contents($url));
            $openid = $infos->openid;
        }


        $fee = 0.01; //举例支付0.01
        $appid =        $this->xiaoAppid; //这里填写公众号appiid的话会显示 appid和openid不匹配 ,解决方法 添加特约商户号关联起来,在商户号后台关联小程序即可,调用时候使用小程序的appid
        $body =         '标题';
        $mch_id =       $this->mchid;  //商户号
        $nonce_str =    $this->nonce_str(); //随机字符串
        $notify_url =    $this->notify_url;
        $openid =       $openid;
        $out_trade_no = $this->order_number($openid); //商户订单号
        $spbill_create_ip = '127.0.0.1'; //服务器的ip【自己填写】;
        $total_fee =    $fee * 100; // 微信支付单位是分,所以这里需要*100
        $trade_type = 'JSAPI'; //交易类型 默认


        //这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
        $post['appid'] = $appid;
        $post['body'] = $body;
        $post['mch_id'] = $mch_id;
        $post['nonce_str'] = $nonce_str; //随机字符串
        $post['notify_url'] = $notify_url;
        $post['openid'] = $openid;
        $post['out_trade_no'] = $out_trade_no;
        $post['spbill_create_ip'] = $spbill_create_ip; //终端的ip
        $post['total_fee'] = $total_fee; //总金额 
        $post['trade_type'] = $trade_type;
        // $sign1 = $this->sign($post); //签名
        $sign = self::getSign($post,  $this->apiKey);
        $post_xml = '<xml>
                    <appid>' . $appid . '</appid>
                    <body>' . $body . '</body>
                    <mch_id>' . $mch_id . '</mch_id>
                    <nonce_str>' . $nonce_str . '</nonce_str>
                    <notify_url>' . $notify_url . '</notify_url>
                    <openid>' . $openid . '</openid>
                    <out_trade_no>' . $out_trade_no . '</out_trade_no>
                    <spbill_create_ip>' . $spbill_create_ip . '</spbill_create_ip>
                    <total_fee>' . $total_fee . '</total_fee>
                    <trade_type>' . $trade_type . '</trade_type>
                    <sign>' . $sign . '</sign>
                    </xml> ';
        //统一接口prepay_id
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = $this->http_request($url, $post_xml);  //发送请求
        $array = $this->xml($xml); //全要大写
        // print_r($array); // print_r($xml); die();
        /*  */

        if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') {
    
    
            $time = time();
            $tmp = []; //临时数组用于签名
            $tmp['appId'] = $appid;
            $tmp['nonceStr'] = $nonce_str;
            $tmp['package'] = 'prepay_id=' . $array['PREPAY_ID'];
            $tmp['signType'] = 'MD5';
            $tmp['timeStamp'] = "$time";

            $data['state'] = 200;
            $data['timeStamp'] = "$time"; //时间戳
            $data['nonceStr'] = $nonce_str; //随机字符串
            $data['signType'] = 'MD5'; //签名算法,暂支持 MD5
            $data['package'] = 'prepay_id=' . $array['PREPAY_ID']; //统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
            $data['paySign'] =  self::getSign($tmp,  $this->apiKey); //签名,具体签名方案参见微信公众号支付帮助文档;
            $data['out_trade_no'] = $out_trade_no;
        } else {
    
    
            $data['state'] = 0;
            $data['text'] = "错误";
            $data['RETURN_CODE'] = $array['RETURN_CODE'];
            $data['RETURN_MSG'] = $array['RETURN_MSG'];
        }


        echo json_encode($data);
    }




    //随机32位字符串
    private function nonce_str()
    {
    
    
        $result = '';
        $str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
        for ($i = 0; $i < 32; $i++) {
    
    
            $result .= $str[rand(0, 48)];
        }
        return $result;
    }



    //生成订单号
    private function order_number($openid)
    {
    
    
        //date('Ymd',time()).time().rand(10,99);//18位
        return md5($openid . time() . rand(10, 99)); //32位
    }



    //签名 $data要先排好顺序
    private function sign($data)
    {
    
    
        $stringA = '';
        foreach ($data as $key => $value) {
    
    
            if (!$value) continue;
            if ($stringA) $stringA .= '&' . $key . "=" . $value;
            else $stringA = $key . "=" . $value;
        }
        $wx_key = ''; //申请支付后有给予一个商户账号和密码,登陆后自己设置的key
        $stringSignTemp = $stringA . '&key=' . $wx_key;
        return strtoupper(md5($stringSignTemp));
    }
    // 获取签名
    public static function getSign($params, $key)
    {
    
    
        ksort($params, SORT_STRING);
        $unSignParaString = self::formatQueryParaMap($params, false);
        $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
        return $signStr;
    }
    protected static function formatQueryParaMap($paraMap, $urlEncode = false)
    {
    
    
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
    
    
            if (null != $v && "null" != $v) {
    
    
                if ($urlEncode) {
    
    
                    $v = urlencode($v);
                }
                $buff .= $k . "=" . $v . "&";
            }
        }
        $reqPar = '';
        if (strlen($buff) > 0) {
    
    
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }
    //curl请求
    public function http_request($url, $data = null, $headers = array())
    {
    
    
        $curl = curl_init();
        if (count($headers) >= 1) {
    
    
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($curl, CURLOPT_URL, $url);


        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);


        if (!empty($data)) {
    
    
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }


    //获取xml
    private function xml($xml)
    {
    
    
        $p = xml_parser_create();
        xml_parse_into_struct($p, $xml, $vals, $index);
        xml_parser_free($p);
        $data = [];
        foreach ($index as $key => $value) {
    
    
            if ($key == 'xml' || $key == 'XML') continue;
            $tag = $vals[$value[0]]['tag'];
            $value = $vals[$value[0]]['value'];
            $data[$tag] = $value;
        }
        return $data;
    }
}

后台回调页面,在付款成功后就会触发这个页面,我在里面写了一个函数,付款成功后就会把付款信息生成日志文件

<?php
 
$info = file_get_contents("php://input");
// $order = xmlToArray($info);
// $trade['order'] = $order['out_trade_no'];   /* 微信分配的小程序ID,即订单号 */
// $trade["total_fee"] = $order["total_fee"];    /* 金额 */
// $trade["sign"] = $order["sign"];    /* 签名 */
// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8


// // 3,针对信息做处理,
// // 3.1根据返回的信息在生成签名防止数据泄漏导致出现“假通知”,造成资金损失。
// $newSign = verifySign($order);
// // // 3.2根据订单id去数据库或者换成查找订单消息
// $data = $pdo->query("SELECT payAmount,status from a_buy WHERE outTradeNo='{$trade['order']}'")->fetch(PDO::FETCH_ASSOC); //需要注意单位为分

// if (($data['payAmount'] * 100) == $trade['total_fee'] && $newSign == $trade["sign"]) {
    
    
//     if ($data['status'] == '待付款') {
    
    
//         // 更改订单状态
//         $pdo->exec("UPDATE a_buy set status='待发货'  WHERE outTradeNo='{$trade['order']}'");
        var_dump($info);
        logInfo($info); //写入日志
//     }
//     return
//         '<xml>
//             <return_code><![CDATA[SUCCESS]]></return_code>
//             <return_msg><![CDATA[OK]]></return_msg>
//         </xml>';
//     var_dump($data);
// } else {
    
    
//     // 失败的请求
// }



// 将xml装换为数组
function xmlToArray($data)
{
    
    
    return  (array)simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
}
// 将付款成功后的数据写入log 日志文件
function logInfo($info, $fileName = 'pay')
{
    
    
    $debugInfo = debug_backtrace();
    $message = date("Y-m-d H-i-s") . PHP_EOL . $info . PHP_EOL;;
    $message .= '[' . $debugInfo[0]['file'] . ']' . 'line' . $debugInfo[0]["line"] . PHP_EOL;
    file_put_contents($fileName . '-' . date("Y-m-d") . '.log', $message, FILE_APPEND);
}
// 判断返回的签名和根据数据生成的数据判断是否相同,防止数据泄漏导致出现“假通知”,造成资金损失。
function verifySign($params, $apikey = "c17FZND q71Tt9")
{
    
    
    ksort($params);
    $string = "";
    foreach ($params as $k => $v) {
    
    

        if ($k != "sign" && $v != "" && !is_array($v)) {
    
    
            $string .= $k . "=" . $v . "&";
        }
    }
    $string = $string . "key=" . $apikey;
    $string = md5($string);
    $result = strtoupper($string);
    return $result;
}


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44797182/article/details/112856545
今日推荐