zoukankan      html  css  js  c++  java
  • 微信支付之jsapi支付和h5支付

    支付类:

    <?php
    /**
     * Desc:微信支付jsapi和h5支付
     * Created by PhpStorm.
     * User: HOUDJ
     * Date: 2020/6/17
     * Time: 16:36
     */
    
    namespace appcommonussiness;
    
    
    class WechatPay
    {
        const UNURL = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        const SEORDERURL = 'https://api.mch.weixin.qq.com/pay/orderquery';
        //生成签名
        public function getSign($arr){
            //去除空值
            $arr = array_filter($arr);
            if(isset($arr['sign'])){
                unset($arr['sign']);
            }
            //按照键名字典排序
            ksort($arr);
            //生成url格式的字符串
            $str = $this->arrToUrl($arr) . '&key=' . config('app.wechat.api_key');
            return strtoupper(md5($str));
        }
    
        //获取带签名的数组
        public function setSign($arr){
            $arr['sign'] = $this->getSign($arr);;
            return $arr;
        }
    
        public function arrToUrl($arr){
            return urldecode(http_build_query($arr));
        }
    
        //验证签名
        public function chekSign($arr){
            $sign = $this->getSign($arr);
            if($sign == $arr['sign']){
                return true;
            }else{
                return false;
            }
        }
    
        /**
         * Notes:调用统一下单api
         * User: HOUDJ
         * Date: 2020/7/2
         */
        public function unifiedOrder($data,$type=false){
            /**
             * 1.构建原始数据
             * 2.加入签名
             * 3.将数据转换为XML
             * 4.发送XML格式的数据到接口地址
             */
            $params = [
                'appid'=> config('app.wechat.appid'),
                'mch_id'=> config('app.wechat.mch_id'),
                'nonce_str'=>md5(time()),
                'body'=>$data['body'],
                'attach'=>$data['attach'],
                'out_trade_no'=>$data['out_trade_no'],
                'total_fee'=> floatval($data['order_price']*100),
                'spbill_create_ip'=>$_SERVER['REMOTE_ADDR'],
                'notify_url'=> config('app.wechat.notify'),
                'trade_type'=>'JSAPI',
    
            ];
            if($type == 'h5'){
                $params['trade_type'] = 'MWEB';
            }else{
                $params['openid'] = $data['open_id'];
            }
            $params = $this->setSign($params);
            $xmldata = $this->ArrToXml($params);
            $resdata = $this->postXml(self::UNURL, $xmldata);
            $arr = $this->XmlToArr($resdata);
            return $arr;
        }
    
        /**
         * Notes:调用查询订单接口
         * User: HOUDJ
         * Date: 2020/7/2
         */
        public function queryOrder($trade_no){
            //构建数据
            $params = [
                'appid'=> config('app.wechat.appid'),
                'mch_id'=> config('app.wechat.mch_id'),
                'out_trade_no' => $trade_no,
                'nonce_str'=>md5(time()),
                'sign_type' => 'MD5'
            ];
    
            $params = $this->setSign($params);
            $xmldata = $this->ArrToXml($params);
            $resdata = $this->postXml(self::SEORDERURL, $xmldata);
            $arr = $this->XmlToArr($resdata);
            return $arr;
        }
    
        /**
         * Notes:获取prepayid
         * User: HOUDJ
         * Date: 2020/7/2
         */
        public function getPrepayId($oid){
            $arr = $this->unifiedOrder($oid);
            return $arr['prepay_id'];
        }
    
        /**
         * Notes:获取公众号支付所需要的json数据
         * User: HOUDJ
         * Date: 2020/7/2
         */
        public function getJsParams($prepay_id){
            $params = [
                'appId' => config('app.wechat.appid'),
                'timeStamp' =>time(),
                'nonceStr' => md5(time()),
                'package' =>'prepay_id=' . $prepay_id,
                'signType' =>'MD5',
                //       'paySign' => $this->getSign($params)
            ];
            $params['paySign'] = $this->getSign($params);
            return json_encode($params);
        }
    
        /**
         * Notes:数组转xml
         * User: HOUDJ
         * Date: 2020/7/2
         */
        public function ArrToXml($arr)
        {
            if(!is_array($arr) || count($arr) == 0) return '';
    
            $xml = "<xml>";
            foreach ($arr as $key=>$val)
            {
                if (is_numeric($val)){
                    $xml.="<".$key.">".$val."</".$key.">";
                }else{
                    $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
                }
            }
            $xml.="</xml>";
            return $xml;
        }
    
        /**
         * Notes:Xml转数组
         * User: HOUDJ
         * Date: 2020/7/2
         */
        public function XmlToArr($xml)
        {
            if($xml == '') return '';
            libxml_disable_entity_loader(true);
            $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            return $arr;
        }
    
        /**
         * Notes:发送
         * User: HOUDJ
         * Date: 2020/7/2
         */
        public function postXml($url,$postfields){
            $ch = curl_init();
            $params[CURLOPT_URL] = $url;    //请求url地址
            $params[CURLOPT_HEADER] = false; //是否返回响应头信息
            $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
            $params[CURLOPT_FOLLOWLOCATION] = true; //是否重定向
            $params[CURLOPT_POST] = true;
            $params[CURLOPT_POSTFIELDS] = $postfields;
            $params[CURLOPT_SSL_VERIFYPEER] = false;
            $params[CURLOPT_SSL_VERIFYHOST] = false;
            curl_setopt_array($ch, $params); //传入curl参数
            $content = curl_exec($ch); //执行
            curl_close($ch); //关闭连接
            return $content;
        }
    
        /**
         * Notes:获取post过来的数据
         * User: HOUDJ
         * Date: 2020/7/3
         */
        public function getPost(){
            $xml = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
            return $xml;
        }
    
    }

    支付:

    判断当前支付环境是h5还是为微信内支付,前台通过user_anv传递环境

        public function createOrder(){
            $project_id=$this->request->param('project_id',0,'intval');
            $integral=$this->request->param('integral',0,'intval');
            if(!$project_id){
                return returnMsg(config('status.error'),'','参数错误');
            }
            $orders=new OrdersModel();
            $info=$orders->createOrder($this->userId,$project_id,$integral);//生成订单
            if($info['code']){//订单生成成功 处理支付
                //如果当前是微信环境并且用户openid不为空 调取jsapi支付 否则h5支付
                $data['body']=$info['data']['body'];
                $data['out_trade_no']=$info['data']['order_sn'];
                $data['order_price']=$info['data']['pay_price'];
                $data['open_id']=$this->open_id;
                $data['attach']='课程购买';
                $pay=new WechatPay();
                if($this->user_env && $this->open_id){
                    $prepay_id = $pay->getPrepayId($data);
                    $code_str = $pay->getJsParams($prepay_id);
                    $info['data']['pay_type']='jsapi';
                    $info['data']['pay']=$code_str;
                }else{
                    $code_str = $pay->unifiedOrder($data,'h5');
                    $info['data']['pay_type']='h5';
                    $info['data']['pay']=$code_str['mweb_url'];
                }
                return returnMsg($info['code'],$info['data'],$info['msg']);
            }else{
                return returnMsg($info['code'],$info['data'],$info['msg']);
            }
        }

    jsapi支付返回

    {
        "code": 1,
        "data": {
            "stu_id": 15,
            "order_sn": "DD1593756697752151350",
            "order_price": "0.01",
            "pay_price": "0.01",
            "cost_integral": 0,
            "body": "学员注册",
            "pay_type": "jsapi",
            "pay": "{"appId":"wxbf20372629712be4","timeStamp":1593756697,"nonceStr":"23709aa6c748eab1f7abe3afbd1c6d7f","package":"prepay_id=wx0314113788641179329909651256281400","signType":"MD5","paySign":"D4E388855A2E8AFA6C8736C98F0B74DD"}"
        },
        "msg": "订单生成成功"
    }

    H5支付返回

    {
        "code": 1,
        "data": {
            "stu_id": 15,
            "order_sn": "DD1593756510004805466",
            "order_price": "0.01",
            "pay_price": "0.01",
            "cost_integral": 0,
            "body": "学员注册",
            "pay_type": "h5",
            "pay": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx0314083017318922e8e1ab591995287800&package=1813868424"
        },
        "msg": "订单生成成功"
    }

    支付回调:

    <?php
    /**
     * Created by PhpStorm.
     * User: HOUDJ
     * Date: 2020/7/2
     * Time: 16:16
     */
    
    namespace appindexcontroller;
    use appBaseController;
    use appcommonussinessWechatPay;
    use appindexmodelOrders;
    use appindexmodelPayLogs;
    use appindexmodelStudentStudyRules;
    use appindexmodelStudents;
    
    class Payment extends BaseController
    {
        /**
         * Notes:支付回调
         * User: HOUDJ
         * Date: 2020/7/3
         */
        public function notify(){
            $pay=new WechatPay();
            $xmlData = $pay->getPost();
            $arr = $pay->XmlToArr($xmlData);
            if($pay->chekSign($arr)){
                if($arr['return_code'] == 'SUCCESS' && $arr['result_code'] == 'SUCCESS') {
                    $this->pay_action($arr, $arr['out_trade_no']);
                }else{
                    logs(date('Y-m-d H:i:s').'业务结果错误:'.json_encode($arr),'pay_notify_fail');
                }
                //通知微信
                $returnParams = [
                    'return_code' => 'SUCCESS',
                    'return_msg'  => 'OK'
                ];
                echo $pay->ArrToXml($returnParams);
            }else{
                logs(date('Y-m-d H:i:s').'签名错误:'.json_encode($arr),'pay_notify_fail');
                //通知微信
                $returnParams = [
                    'return_code' => 'FAIL',
                    'return_msg'  => '签名错误'
                ];
                echo $pay->ArrToXml($returnParams);
            }
        }
    
        /**
         * Notes:h5查询是否支付成功
         * User: HOUDJ
         * Date: 2020/7/3
         */
        public function h5_notify(){
            $order_sn=$this->request->param('order_sn');
            $pay=new WechatPay();
            $arr=$pay->queryOrder($order_sn);
            if($arr['return_code'] == 'SUCCESS' && $arr['result_code'] == 'SUCCESS') {
                $this->pay_action($arr,$order_sn);
                return returnMsg(config('status.success'),'','支付成功');
            }else{
                logs(date('Y-m-d H:i:s').'业务结果错误:'.json_encode($arr),'pay_notify_fail');
                return returnMsg(config('status.error'),'','支付失败');
            }
        }
    
        /**
         * Notes:处理支付成功的逻辑
         * User: HOUDJ
         * Date: 2020/7/3
         */
        public function pay_action($arr,$order_sn=''){
            logs(date('Y-m-d H:i:s').json_encode($arr), 'pay_notify_success');
            //将金额分转化成交易金额
            $total_fee = number_format($arr['total_fee']/100,2,'.','');
            //改变订单状态
            $orderInfo= Orders::where('order_sn', '=', $order_sn)->find();
            $map[] = ['id', '=', $orderInfo['id']];
            Orders::updateOrderStatus($map, ['order_status' => 1, 'pay_time' => time(), 'pay_price' => $total_fee]);
            //如果是购买的课程 将课程的效期显示 如果购买的会员注册 则将会员状态改变
            if($arr['attach']=='课程购买') {
                StudentStudyRules::where('order_id', '=', $orderInfo['id'])->update(['status' => 1]);
            }else{
                Students::where('id','=',$orderInfo['stu_id'])->update(['status'=>2,'frozen'=>0]);
            }
            PayLogs::logs($orderInfo,$arr,$total_fee);
        }
    }
  • 相关阅读:
    python 打印对象的所有属性值
    selenium+python测试
    java连接3种数据库 JdbcLinkDB --201801
    又来折腾--正则表达式
    Excel 将A表的基础数据拼接到B表中来-三种方法: ctrl+回车, VLOOKUP()函数,宏
    Excel如何快速统计一列中相同数值出现的个数--数据透视表
    Jmeter、Postman 、 loadrunner SoapUI 接口测试工具
    delphi 获取时间戳 如何得到 和 js 中 new Date().getTime();的 相同?
    IIS部署项目
    C#使用log4net记录日志
  • 原文地址:https://www.cnblogs.com/houdj/p/13230771.html
Copyright © 2011-2022 走看看