zoukankan      html  css  js  c++  java
  • YIi2 對接 微信WechatPay(公衆號支付) 支付接口

    微信支付的開發文檔 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

    介紹的是相當簡陋啊。。

    下載sdk和demo: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

    下載好後,放到 component文件夾(我用的是yii2),在sdk文件夾下添加一個   init.php

    <?php
    //init.php  主要是引用lib中的4個文件
    require_once  dirname(__FILE__).'/lib/WxPay.Api.php';
    require_once  dirname(__FILE__).'/lib/WxPay.Config.php';
    require_once  dirname(__FILE__).'/lib/WxPay.Data.php';
    require_once  dirname(__FILE__).'/lib/WxPay.Exception.php';
    require_once  dirname(__FILE__).'/lib/WxPay.Notify.php';

    支付中需要用到的幾個參數

    app_id,
    app_secret,
    MCHID,  //商戶號
    key

    這幾個參數在 「微信公衆平臺開發者設置 」 和 「商戶平臺設置 」 都能獲取到,具體百度。。

    先看前臺

    $("#pay").click(function(){
            var pay_way = $("input[type='radio']:checked").val();
            if(pay_way == 1){
                wap_pay(1) //支付寶
            }else if(pay_way == 2){
                wechatcallpay()  //微信支付
            }else if(pay_way == 3){
                paypal_pay()  //PayPal
            }
        });

    wechatcallpay(),我是通過 ajax 獲取後臺數據

    //wechat 支付
        function wechatcallpay()
        {
            $.ajax({
                type: 'POST',
                url: '/order/wechatpay',  //獲取後臺中的數據
                data:"_csrf="+_csrf+"&ssid="+ssid,
                dataType: 'json',
                success: function(data){
                    jsApiParamenters = data
                    if (typeof WeixinJSBridge == "undefined"){
                        if( document.addEventListener ){
                            document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
                        }else if (document.attachEvent){
                            document.attachEvent('WeixinJSBridgeReady', jsApiCall);
                            document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
                        }
                    }else{
                        jsApiCall();
                    }
                }
            });
        }
    
        function jsApiCall()
        {
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest',
                jsApiParamenters,
                function(res){
    //                WeixinJSBridge.log(res.err_msg);
    //                alert(res.err_code+res.err_desc+res.err_msg);
    
                    if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                        //跳轉到[成功界面]
                        window.location.href = "<?php echo Url::to('/order/success')?>";
                    } else if(res.err_msg == "get_brand_wcpay_request:cancel"){
                        //跳轉到[取消界面]
                        window.location.href = "<?php echo Url::to('/order/cancel')?>";
                    } else {
                        //跳轉到「失敗界面」
                        window.location.href = "<?php echo Url::to('/order/cancel')?>";
                    }
                }
            );
        }

    再看看 /order/wechatpay

    public function actionWechatpay()
        {
            if(Yii::$app->request->isPost) {
                $ssid = Yii::$app->request->post('ssid');
    
                $online_order = OnlineOrder::find()->where('order_code = :ssid',[':ssid'=>$ssid])->one();
                $data = OnlineOrder::findOrderDetail($online_order);
                $rate = Helper::rate(); //第三方 獲取匯率
                $money = ceil($data['total_money'] * $rate * 100); //取整,微信支付已分爲單位,而且不能有小數
                $order_number = $data['order_number'];
    
                $cookies = Yii::$app->request->cookies;
                $wx_code = $cookies->getValue('wx_code');  //通過cookies獲取wx_code,獲取方法下面有講
    
                $wx_app_id = Yii::$app->params['wechat']['wx_app_id'];   
                $wx_app_secret = Yii::$app->params['wechat']['wx_app_secret'];
                $open_id = WechatPay::getOpenid($wx_app_id, $wx_app_secret, $wx_code);  //獲取方法下面講
                $body = "商品簡述";
                $notify_url = Yii::$app->params['wechat']['notify_url'];  //回調uRL,支付成功後微信會調用這個接口
                $jsApiParams = Helper::getjsApiParams($open_id,$body,$ssid,$money,$order_number,$notify_url); //下面講
    
                echo $jsApiParams;
    
            } else {
                echo  0;
            }
        }

    首先是wx_code的獲取,

    /**
         * 判断是否在微信客户端打开链接
         * 如果是就跳转到微信code的重定向url地址
         * 如果不是就跳到支付宝支付界面
         */
    
        public function actionGetcode()
        {
            $isWechat = Helper::isWechatBrowser(); //下面有講到if($isWechat){
                $url = Helper::GetWxCodeUrl();  //下面講
                header("Location: $url");
                exit();
            } else {
                $this->redirect(['order/payment']);
            }
        }

    /** * 通过微信重定向url获取code, * 并且把code设置为cookie */ public function actionGetwxcode() { $code = Yii::$app->request->get('code'); //把wx_code作爲cookies保存if(!empty($code)){ $cookies = Yii::$app->response->cookies; $cookies->add(new yiiwebCookie([ 'name' => 'wx_code', 'value' => $code, 'expire'=>time()+3600, ])); } $this->redirect(['/order/payment']); }

    新建一個   WechatPay.php,主要是獲取 code 和openid

    <?php
    
    
    namespace frontendcomponents;
    
    class WechatPay
    {
       /**
        * 获取微信公众号授权用户唯一标识
        * @param $app_id 微信公众号应用唯一标识
        * @param $app_secret 微信公众号应用密钥(注意保密)
        * @param $code 授权code, 通过调用WxpubOAuth::createOauthUrlForCode来获取
        * @return openid 微信公众号授权用户唯一标识, 可用于微信网页内支付
        */
        public static function getOpenid($app_id, $app_secret, $code)
        {
            $url = self::_createOauthUrlForOpenid($app_id, $app_secret, $code);
            $res = self::_getRequest($url);
            $data = json_decode($res, true);
    
            return $data['openid'];
        }
    
        /**
         * 用于获取授权code的URL地址,此地址用于用户身份鉴权,获取用户身份信息,同时重定向到$redirect_url
         * @param $app_id 微信公众号应用唯一标识
         * @param $redirect_url 授权后重定向的回调链接地址,重定向后此地址将带有授权code参数,
         *                      该地址的域名需在微信公众号平台上进行设置,
         *                      步骤为:登陆微信公众号平台 => 开发者中心 => 网页授权获取用户基本信息 => 修改
         * @param bool $more_info FALSE 不弹出授权页面,直接跳转,这个只能拿到用户openid
         *                        TRUE 弹出授权页面,这个可以通过 openid 拿到昵称、性别、所在地,
         * @return string 用于获取授权code的URL地址
         */
        public static function createOauthUrlForCode($app_id, $redirect_url, $more_info = false)
        {
            $urlObj = array();
            $urlObj['appid'] = $app_id;
            $urlObj['redirect_uri'] = $redirect_url;
            $urlObj['response_type'] = 'code';
            $urlObj['scope'] = $more_info ? 'snsapi_userinfo' : 'snsapi_base';
            $urlObj['state'] = "#state";  //這個參數會原封不動地傳回來
            $queryStr = http_build_query($urlObj);
    
            return 'https://open.weixin.qq.com/connect/oauth2/authorize?' . $queryStr;
        }
    
        /**
         * 获取openid的URL地址
         * @param $app_id 微信公众号应用唯一标识
         * @param $app_secret 微信公众号应用密钥(注意保密)
         * @param $code 授权code, 通过调用WxpubOAuth::createOauthUrlForCode来获取
         * @return string 获取openid的URL地址
         */
        private static function _createOauthUrlForOpenid($app_id, $app_secret, $code)
        {
            $urlObj = array();
            $urlObj['appid'] = $app_id;
            $urlObj['secret'] = $app_secret;
            $urlObj['code'] = $code;
            $urlObj['grant_type'] = 'authorization_code';
            $queryStr = http_build_query($urlObj);
    
            return 'https://api.weixin.qq.com/sns/oauth2/access_token?' . $queryStr;
        }
    
        /**
         * GET 请求
         */
        private static function _getRequest($url) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
            curl_setopt($ch, CURLOPT_HEADER, FALSE);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
            $res = curl_exec($ch);
            curl_close($ch);
    
            return $res;
        }
    
    
        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;
        }
    
    }

    Helper.php

           //首先引入 init.php
           require_once dirname(dirname(__FILE__)).'/components/WxpayAPI/init.php';
    
    
            /**
             * 判断是否微信打开
             * @return boolean
             */
            public static function isWechatBrowser()
            {
                if (strpos($_SERVER['HTTP_USER_AGENT'],'MicroMessenger') !== false ) {
                    return true;
                }
                
                return false;
            }
    
    
           /**
             * 获取微信code的重定向前的url
             * @return string
             */
            public static function GetWxCodeUrl()
            {
                $wx_app_id = Yii::$app->params['wechat']['wx_app_id'];
                $redirect_url = Yii::$app->params['wechat']['redirect_url'];//這個就是前面 微信重定向獲取code的ur(/order/getwxcode )
                $code_url = WechatPay::createOauthUrlForCode($wx_app_id, $redirect_url);
                
                return $code_url;
            }
    
           /**
             * wechat支付 獲取jsapi參數
             */
            public static function getjsApiParams($openId,$body,$attach,$money,$order_number,$notify_url,$trade_type="JSAPI")
            {
                $input = new WxPayUnifiedOrder();
                $input->SetBody($body);
                $input->SetAttach($attach);
                $input->SetOut_trade_no($order_number);
                $input->SetTotal_fee($money);
                $input->SetTime_start(date("YmdHis"));
                $input->SetTime_expire(date("YmdHis", time() + 600));
                $input->SetGoods_tag("商品");
                $input->SetNotify_url($notify_url);
                $input->SetTrade_type($trade_type);
                $input->SetOpenid($openId);
                $input->setDetail("商品簡介");
                $order = WxPayApi::unifiedOrder($input);  //這個函數在 微信sdk中的 ..libWxPay.Api.php
                $jsApiParameters = WxPayApi::GetJsApiParameters($order);//這個函數在 微信sdk中的..libWxPay.Api.php
                return $jsApiParameters;
            }

    接通之後,還需要在 「微信公衆平臺」和 「商戶平臺」設置 授權url,不然是訪問不了微信的接口的,具體百度。。。

    「微信回調  Notify_url」

    可以完成支付了,還有就是  回調地址的處理,這個地址是在 上面 actionWechaypay() 中設置的,當支付成功後,微信就會調用

    class CallbackController extends BaseController
    {
        public $enableCsrfValidation = false;   //這個要關閉,不然接收不到數據
    
        public function actionWechat()
        {
            $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
    
            if ($postObj === false) {
                die('parse xml error');
            }
            if ($postObj->return_code != 'SUCCESS') {
                die("error_code: ".$postObj->err_code.",msg: ".$postObj->return_msg);
            }
            $key = Yii::$app->params['wechat']['wx_key'];
    
            //验证签名
            $wechat = new WechatPay();   //這個就是上面的WechatPay.php中的內容
            $arr = (array)$postObj;
            unset($arr['sign']);
            if($wechat::getSign($arr,$key) != $postObj->sign) {
                die("签名错误");
            }

    //之後的邏輯,就是 修改訂單狀態。。。
    return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; } }
  • 相关阅读:
    spring boot 集成activeMq
    spring boot配置跨域
    spring boot中使用mybatis逆向工程
    Cookie/Session/Token
    Spring Boot自定义Starter
    linux防火墙命令
    imx6ull+debian10 构建静态qt交叉编译环境
    Arm Qt编译Qt例程出错 GLES3/gl3.h: No such file or directory 解决方法
    QtCreator设置野火iMx6开发板提供的qt交叉编译套件
    联想ideapad-330C 在Ubuntu18.04 上安装Realtek 8821CE无线网卡驱动
  • 原文地址:https://www.cnblogs.com/weishuan/p/7464452.html
Copyright © 2011-2022 走看看