thinkphp3.2 小程序微信支付

直接上代码,只需要填写自己的参数就行

thinkphp 后台程序

<?php
/**
 * 小程序支付
 */

namespace Salesapi\Controller;

use Think\Controller;

class PayController extends Controller
{
    /*
     * 充值功能
     */
    public function recharge()
    {
        $uid = I("post.txt_uid", '');//用户id
        !$uid && $this->ajax_common_return(4, "用户id不能为空", array(), 1);
        $amount = I("post.txt_amount");
        !$amount && $this->ajax_common_return(4, "金额不能为空", array(), 1);
        $txt_mcoupon = I("post.txt_mcoupon");
        !$txt_mcoupon && $this->ajax_common_return(4, "金额不能为空", array(), 1);
        if (!is_numeric($amount)) {
            $this->ajax_common_return(4, "请输入正确的金额", array(), 1);
        }
        $data = M("system_set")->field("mcoupon_edinfo,recharge_status,recharge_radio")->find();
        if ($data['recharge_status'] == 0) {
            $this->ajax_common_return(4, "请先开启充值功能", array(), 1);
        }
        if (empty($data['recharge_radio']) || ($data['recharge_radio'] <= 0)) {
            $this->ajax_common_return(4, '请先设置比例', array(), 1);
        }
        $rechargeArr = M("system_set")->field("recharge_radio")->find();
        $saveData['ratio'] = $rechargeArr['recharge_radio'];
        $mcoupon = $txt_mcoupon;
        $ini['uid'] = $uid;
        $ini['status'] = 1;
        $result = M('order_recharge')->where($ini)->getField('recharge_id');
        if (empty($result)) {
            $saveData['uid'] = $uid;
            $saveData['amount'] = $amount;
            $saveData['mcoupon'] = $mcoupon;
            $saveData['status'] = 1;
            $saveData['out_trade_no'] = $this->createOrderNo();
            $saveData['add_time'] = time();
            M('order_recharge')->add($saveData);
        } else {
            $saveData['amount'] = $amount;
            $saveData['mcoupon'] = $mcoupon;
            $saveData['out_trade_no'] = $this->createOrderNo();
            $saveData['add_time'] = time();
            M('order_recharge')->where(array('recharge_id' => $result))->save($saveData);
        }
        $openid = M('users_sales')->where(array('sales_id' => $uid))->getField('openids');
        if (empty($openid)) {
            $this->ajax_common_return(4, "未获取到用户的openid", array(), 1);
        }
        $payData = $this->pay($amount, $openid, $saveData['out_trade_no']);
        $this->ajax_common_return(0, '请求成功', $payData);
    }

    /*
     *回调地址
     */
    public function notify()
    {
        //获取接口数据,如果$_REQUEST拿不到数据,则使用file_get_contents函数获取
        $post = $_REQUEST;
        if ($post == null) {
            $post = file_get_contents("php://input");
        }
        if ($post == null) {
            $post = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
        }
        if (empty($post) || $post == null || $post == '') {
            //阻止微信接口反复回调接口
            // 文档地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,
            //下面这句非常重要!!!
            $str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
            echo $str;
            exit('Notify 非法回调');
        }
        libxml_disable_entity_loader(true); //禁止引用外部xml实体
        $xml = simplexml_load_string($post, 'SimpleXMLElement', LIBXML_NOCDATA);//XML转数组
        $post_data = (array)$xml;
        //此时你就可以进行修改订单状态以及其他的操作了...
        $out_trade_no = $post_data['out_trade_no'];      //微信支付订单号
        $transaction_id = $post_data['transaction_id'];  //商户订单号
        $ini['out_trade_no'] = $out_trade_no;
        $res = M('order_recharge')->where($ini)->find();
        if ($res['status'] == 1) {
            //更新状态
            $saveData['status'] = 2;
            $saveData['transaction_id'] = $transaction_id;
            M('order_recharge')->where($ini)->save($saveData);
            $this->salesData($res['uid'],$res['mcoupon'],$res['amount']);
        }
        //阻止微信接口反复回调接口
        //文档地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,
        //下面这句非常重要!!!
        $str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        echo $str;
    }

    /*
     * 业务员的操作
     */
    public function salesData($salesId,$mcoupon,$amount)
    {
        $ini['sales_id'] = $salesId;
        $res = M('users_sales')->where($ini)->getField('mcoupon_available');
        $saveData['mcoupon_available'] = $res + $mcoupon;
        $saveData['recharge_time'] = time();
        M('users_sales')->where($ini)->save($saveData);
        //记录
        mcoupon_store_record(1,12,'充值优惠券额度',$salesId,$mcoupon,$saveData['mcoupon_available'],$amount);
    }

    /*
     * 生成唯一的订单号
     * @return string
     */
    function createOrderNo()
    {
        $order_no = date('Ymd') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(1000, 9999));
        return $order_no;
    }

    /*
     * $openid 支付用户的openid
     * $out_trade_no 商户订单号
     * @return mixed
     */
    public function pay($fee, $openid, $out_trade_no)
    {
        $appid = "";//appid.如果是公众号 就是公众号的appid
        $body = "充值余额";
        $mch_id = '';//商户号
        $notify_url = '';
        //回调的url【自己填写】,注:此处url必须是外网可访问地址才可以,如果是自己内网服务器不行。
        $spbill_create_ip = '';//服务器的ip【自己填写】;
        $total_fee = $fee * 100;// 微信支付单位是分,所以这里需要*100
        $nonce_str = $this->nonceStr();//随机字符串
        $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;
        $sign = $this->sign($post);//签名
        $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> ';
//        print_r($post_xml);die;
        //统一接口prepay_id
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = $this->http_request($url, $post_xml);
        $array = $this->xmlToArray($xml);
//        print_r($xml);die;
        if ($array['return_code'] == 'SUCCESS' && $array['result_code'] == 'SUCCESS') {
            $time = time();
            $tempArr = array(
                'appId' => $appid,
                'nonceStr' => $nonce_str,
                'package' => 'prepay_id=' . $array['prepay_id'],
                'signType' => 'MD5',
                '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'] = $this->sign($tempArr);//签名,具体签名方案参见微信公众号支付帮助文档;
            $data['out_trade_no'] = $out_trade_no;
        } else {
            $data['state'] = 0;
            $data['text'] = "错误";
            $data['returnArr'] = $array;
        }
        //将此处的$data返回给小程序即可,小程序端发起支付需要用到:timeStamp、nonceStr、package、signType、paySign等参数,我们此处并没有发起真正的支付,仅是向微信发起了统一下单拿到微信返回的相关参数返回给小程序,然后由小程序发起支付
        return $data;
    }

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

    //签名 $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';//申请支付后有给予一个商户账号和密码,登陆后自己设置的key
        $stringSignTemp = $stringA . '&key=' . $wx_key;
        return strtoupper(md5($stringSignTemp));
    }

    //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 xmlToArray($xml)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring), true);
        return $val;
    }

    function ajax_common_return($code = "0", $other = "请求成功", $arr = array(), $save = "0")
    {
        if (empty($arr)) {
            $arr = array();
        }
        if ($save) {
            $returnarr = array("txt_code" => $code, "txt_other" => $other);
        } else {
            $returnarr = array("txt_code" => $code, "txt_other" => $other, "txt_mydata" => $arr);
        }
        return $this->ajaxReturn($returnarr);
    }
}

微信小程序代码部分:
此处发起支付所用到的timeStamp、nonceStr、package、signType、paySign等相关参数是由后端pay方法返回而来。

wx.requestPayment({
    timeStamp: results.data['timeStamp'],
    nonceStr: results.data['nonceStr'],
    package: results.data['package'],
    signType: results.data['signType'],
    paySign: results.data['paySign'],
    success: function(res) {
        //支付完成:此时可以执行跳转页面等操作
    },
    fail: function(res) {
        //此时用户取消支付
    }
})

猜你喜欢

转载自blog.csdn.net/weixin_38615720/article/details/99955560
今日推荐