YIi2 對接 微信WechatPay(公衆號支付) 支付接口

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

介紹的是相當簡陋啊。。web

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

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

<?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';

 

支付中須要用到的幾個參數api

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

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

先看前臺微信

$("#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 獲取後臺數據yii2

//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/wechatpaycookie

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的獲取,app

/**
     * 判斷是否在微信客戶端打開連接
     * 若是是就跳轉到微信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 \yii\web\Cookie([ 'name' => 'wx_code', 'value' => $code, 'expire'=>time()+3600, ])); } $this->redirect(['/order/payment']); }

 

 

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

<?php


namespace frontend\components; 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中的 ..\lib\WxPay.Api.php
            $jsApiParameters = \WxPayApi::GetJsApiParameters($order);//這個函數在 微信sdk中的..\lib\WxPay.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>'; } }
相關文章
相關標籤/搜索