微信小程序+ThinkPHP3.2实现支付功能

ThinkPhP代码部分:

后端部分pay方法仅仅是发起微信统一下单,并没有实际发起支付,我们需要拿到统一下单微信返回的参数返还给小程序,小程序执行wx.requestPayment才是真正的发起支付。

//微信支付
    public function pay(){
        $fee = 1;//举例支付0.01,单位是分
        $appid = "你的小程序appid";//appid.如果是公众号 就是公众号的appid
        $body = "你的商品名称";
        $mch_id = '你的商户号';//商户号
        $nonce_str = $this->nonce_str();//随机字符串
        $notify_url = '你的支付成功回调url'; //回调的url【自己填写】,注:此处url必须是外网可访问地址才可以,如果是自己内网服务器不行。
        $openid = "支付用户的openid";  //支付用户的openid
        $out_trade_no = "此处是你生成的订单号";//商户订单号:需要保证随机生成不重复,建议生成20位
        $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;
        $sign = $this->sign($post);//签名
        $post_xml = '
           '.$appid.'
           '.$body.'
           '.$mch_id.'
           '.$nonce_str.'
           '.$notify_url.'
           '.$openid.'
           '.$out_trade_no.'
           '.$spbill_create_ip.'
           '.$total_fee.'
           '.$trade_type.'
           '.$sign.'
         ';
//        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;
            $data['orderNumber'] = $orderNumber;
            $data['sumPrice'] = $sumPrice;

        }else{
            $data['state'] = 0;
            $data['text'] = "错误";
            $data['returnArr'] = $array;
        }
        //将此处的$data返回给小程序即可,小程序端发起支付需要用到:timeStamp、nonceStr、package、signType、paySign等参数,我们此处并没有发起真正的支付,仅是向微信发起了统一下单拿到微信返回的相关参数返回给小程序,然后由小程序发起支付
        return $data;
    }
    //随机32位字符串
    private function nonce_str(){
        $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;
    }

notify小程序支付成功回调函数:

此处需要注意:只有当notify异步回调成功才算是支付成功,此时可以修改订单状态等操作。小程序wx.requestPayment中的success执行成功并不能进行修改订单状态等操作,但我们可以在success中进行跳转页面等操作。

//小程序支付成功回调函数
    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='';
            echo $str;
            exit('Notify 非法回调');
        }
        /*****************微信回调返回数据样例*******************
        $post = '
        
        
        
        
        
        
        
        
        
        
        
        
        1
        
        
        ';
         *************************微信回调返回*****************/
        libxml_disable_entity_loader(true); //禁止引用外部xml实体
        $xml = simplexml_load_string($post, 'SimpleXMLElement', LIBXML_NOCDATA);//XML转数组
        $post_data = (array)$xml;
        //将用户支付信息记录日志文件
        \Think\Log::record("用户openid:".$post_data['openid']);
        \Think\Log::record("appId:".$post_data['appid']);
        \Think\Log::record("订单编号:".$post_data['out_trade_no']);
        \Think\Log::record("支付金额:".$post_data['total_fee']/100);
        //此时你就可以进行修改订单状态以及其他的操作了...
        $out_trade_no=$post_data['out_trade_no'];  //订单编号
           
        //阻止微信接口反复回调接口  文档地址 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7,下面这句非常重要!!!
        $str='';
        echo $str;
    }

微信小程序代码部分:

此处发起支付所用到的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) {
		//此时用户取消支付
	}
})

 

你可能感兴趣的:(php,支付,微信小程序支付)