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>'; } }
原文地址:https://www.cnblogs.com/weishuan/p/7464452.html