• 微信小程序调微信支付


    今天写小程序的支付接口,参照的当然是微信支付API了。(结尾附上第二步全部代码php版)

    另外,我也参照了简书上的这篇文章,浅显易懂:https://www.jianshu.com/p/72f5c1e3f8a5

    其实小程序中唤起微信支付不外乎以下几个步骤:

    1.获取openid

    小程序获取openid是分两个步骤的

    首先小程序前端通过wx.login获取code,然后用这个code通过后台接口内部访问微信官方API获取openidsession_key

    https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=CODE&grant_type=authorization_code

    红字为所需参数,appid和secret手动配置(开发者平台申请),code就是小程序前端获取的code了

    2.获取prepay_idpaySign

    拿着刚才的openid和订单号(自定义订单号)、订单金额(手动输入金额)以及其他平台参数拼接成一个xml文件作为请求体

    通过后台接口内部访问微信API接口:https://api.mch.weixin.qq.com/pay/unifiedorder

    如果参数无误,将如期返回prepay_idpaySign

    3.前端拉起支付

    拿到了所需参数,前端就可以发起:wx.requestPayment 来拉起支付了。

                wx.requestPayment({
                              'timeStamp':timeStamp,
                              'nonceStr': nonceStr,
                              'package': 'prepay_id='+res.data.prepay_id,
                              'signType': 'MD5',
                              'paySign': res.data._paySignjs,
                              'success':function(res){
                                  console.log(res);
                              },
                              'fail':function(res){
                                  console.log('fail:'+JSON.stringify(res));
                              }
                       })

    如此就完成了小程序的支付,下面就要说一下今天踩的坑了。

    1.appid问题

    前期前端用的appid是用的他个人的appid,要知道小程序用户授权小程序所生成的openid,是需要用appid来参与验签

    的,这直接导致,后期将appid更换为线上appid后,所有的测试用户openid(这个openid在用户授权之后直接存到数据

    库了,所以实际上我们省略了第一步,直接从数据库拿当前用户的数据库存储的openid)走如上第二步的时候,都会报

    openid和appid不匹配的错误,将前期用户数据删除,并更正appid以及其他参数,重新授权后的openid就不会产生不匹

    配的错误了。

    第二步获取prepay_idpaySign代码(php版本):

    <?php
    
    if (!defined('BASEPATH')) exit('No direct script access allowed');
    
    define(APPID, 'wx74bmn4nbf81f1593e');
    define(MCHID, '1510771171');
    define(KEY, 'WlUprCqVM53L4MnI6Dz2Nmz7f44');
    define(APPSECRET, '3b8e3202c39c67712879f6724fc8b42');
    define(NOTIFY_URL, SITE_URL.'web/dayrui/controllers/return_url.php');
    
    require_once FCPATH . 'branch/fqb/D_Wxapp.php';
    require 'WxPay.class.php';  
    
    
    class Wxapp extends D_Wxapp {
    ...
    
      //支付,红字参数依次是openid、订单号、订单说明、订单金额
        public function pay(){
            $pay = $this->req;
            $weixinpay = new WxPay(APPID, $pay['openid'], MCHID, KEY, $pay['out_trade_no'], $pay['body'], $pay['total_fee']);  
            exit_json(1, $weixinpay->pay());
        }
    
    
    
    }
    WxPay.class.php可以直接用,只是注意get_ip()函数是用来获取客户端ip的,这里稍加封装了一下,会在后面给出封装函数代码
    //WxPay.class.php
    
    <?php
    class WxPay {
        
        protected $appid;
        protected $mch_id;
        protected $key;
        protected $openid;
        protected $out_trade_no;
        protected $body;
        protected $total_fee;
        
        function  __construct ($appid, $openid, $mch_id, $key, $out_trade_no, $body,$total_fee){
            $this->appid = $appid;
            $this->openid = $openid;
            $this->mch_id = $mch_id;
            $this->key = $key;
            $this->out_trade_no = $out_trade_no;
            $this->body = $body;
            $this->total_fee = $total_fee;
        }
        
        public function  pay (){
            //统一下单接口  
            
            $return=$this->weixinapp ();
            return $return;
        }
        
        //微信小程序接口  
        private function  weixinapp (){
            //统一下单接口  
            $unifiedorder=$this->unifiedorder ();
            $parameters=array ('appId'=>$this->appid ,//小程序ID  
            'timeStamp'=>''.time().'',//时间戳  
            'nonceStr'=>$this->createNoncestr (),//随机串  
            'package'=>'prepay_id='.$unifiedorder['prepay_id'],//数据包  
            'signType'=>'MD5'//签名方式  
            );
            $parameters['paySign']=$this->getSign ($parameters);
            return $parameters;
        }
        
        //统一下单接口  
        private function  unifiedorder (){
            $url='https://api.mch.weixin.qq.com/pay/unifiedorder';
            $parameters=array (
                'appid'=>$this->appid ,
                'mch_id'=>$this->mch_id ,
                'nonce_str'=>$this->createNoncestr(),
                'body'=>$this->body,      
                'out_trade_no'=>$this->out_trade_no ,
                'total_fee'=>$this->total_fee,
                'spbill_create_ip'=>get_ip(),
                'notify_url'=> NOTIFY_URL,
                'openid'=>$this->openid,
                'trade_type'=>'JSAPI'
            );
            //统一下单签名  
            //pre($parameters);
            $parameters['sign']=$this->getSign ($parameters);
            $xmlData=$this->arrayToXml ($parameters);
            $return=$this->xmlToArray ($this->postXmlCurl ($xmlData,$url,60));
            return $return;
        }
        
        private static function  postXmlCurl ($xml,$url,$second=30){
            $ch=curl_init();
            //设置超时  
            curl_setopt($ch,CURLOPT_TIMEOUT ,$second);
            curl_setopt($ch,CURLOPT_URL ,$url);
            curl_setopt($ch,CURLOPT_SSL_VERIFYPEER ,FALSE);
            curl_setopt($ch,CURLOPT_SSL_VERIFYHOST ,FALSE);
            //严格校验  
            //设置header  
            curl_setopt($ch,CURLOPT_HEADER ,FALSE);
            //要求结果为字符串且输出到屏幕上  
            curl_setopt($ch,CURLOPT_RETURNTRANSFER ,TRUE);
            //post提交方式  
            curl_setopt($ch,CURLOPT_POST ,TRUE);
            curl_setopt($ch,CURLOPT_POSTFIELDS ,$xml);
            curl_setopt($ch,CURLOPT_CONNECTTIMEOUT ,20);
            curl_setopt($ch,CURLOPT_TIMEOUT ,40);
            set_time_limit(0);
            //运行curl  
            $data=curl_exec($ch);
            //返回结果  
            if ($data){
                curl_close($ch);
                return $data;
            }else {
                $error=curl_errno($ch);
                curl_close($ch);
                throw new WxPayException("curl出错,错误码:$error");
            }
        }
        //数组转换成xml  
        private function  arrayToXml ($arr){
            $xml="<root>";
            foreach ($arr as $key=>$val){
                if (is_array($val)){
                    $xml.="<".$key.">".arrayToXml ($val)."</".$key.">";
                }else {
                    $xml.="<".$key.">".$val."</".$key.">";
                }
            }
            $xml.="</root>";
            return $xml;
        }
        
        //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;
        }
        
        
        //作用:产生随机字符串,不长于32位  
        private function  createNoncestr ($length=32){
            $chars="abcdefghijklmnopqrstuvwxyz0123456789";
            $str="";
            for ($i=0;
            $i<$length;
            $i++){
                $str.=substr($chars,mt_rand(0,strlen($chars)-1),1);
            }
            return $str;
        }
        //作用:生成签名  
        private function  getSign ($Obj){
            foreach ($Obj as $k=>$v){
                $Parameters[$k]=$v;
            }
            //签名步骤一:按字典序排序参数  
            ksort($Parameters);
            $String=$this->formatBizQueryParaMap ($Parameters,false);
            //签名步骤二:在string后加入KEY  
            $String=$String."&key=".$this->key ;
            //签名步骤三:MD5加密  
            $String=md5($String);
            //签名步骤四:所有字符转为大写  
            $result_=strtoupper($String);
            return $result_;
        }
        ///作用:格式化参数,签名过程需要使用  
        private function  formatBizQueryParaMap ($paraMap,$urlencode){
            $buff="";
            ksort($paraMap);
            foreach ($paraMap as $k=>$v){
                if ($urlencode){
                    $v=urlencode($v);
                }
                $buff.=$k."=".$v."&";
            }
            $reqPar;
            if (strlen($buff)>0){
                $reqPar=substr($buff,0,strlen($buff)-1);
            }
            return $reqPar;
        }
    }

    get_ip():

    function get_ip(){
        //判断服务器是否允许$_SERVER
        if(isset($_SERVER)){    
            if(isset($_SERVER[HTTP_X_FORWARDED_FOR])){
                $realip = $_SERVER[HTTP_X_FORWARDED_FOR];
            }elseif(isset($_SERVER[HTTP_CLIENT_IP])) {
                $realip = $_SERVER[HTTP_CLIENT_IP];
            }else{
                $realip = $_SERVER[REMOTE_ADDR];
            }
        }else{
            //不允许就使用getenv获取  
            if(getenv("HTTP_X_FORWARDED_FOR")){
                  $realip = getenv( "HTTP_X_FORWARDED_FOR");
            }elseif(getenv("HTTP_CLIENT_IP")) {
                  $realip = getenv("HTTP_CLIENT_IP");
            }else{
                  $realip = getenv("REMOTE_ADDR");
            }
        }
        return $realip;
    }      
  • 相关阅读:
    2020年寒假假期总结0210
    2020年寒假假期总结0209
    2020年寒假假期总结0208
    2020年寒假假期总结0207
    2020年寒假假期总结0206
    yolo-v4:Optimal Speed and Accuracy of Object Detection解析
    Docker 练习
    tensorflow2.0 GPU版本镜像文件
    flink项目实战
    高等数理统计知识点
  • 原文地址:https://www.cnblogs.com/eco-just/p/9399151.html
Copyright © 2020-2023  润新知