1. 程式人生 > >ThinkPHP5微信掃碼支付

ThinkPHP5微信掃碼支付

values ade oca location ood 二維碼 隱藏 目的 tint

1.把微信官網下載的demo放在根目錄/vendor/目錄下,這裏我的是/vendor/wxpay_pc目錄

2.把cert裏面的文件替換成自己項目的證書(登陸微信商戶平臺,賬戶中心,API安全下載)

3.把/wxpay_pc/lib目錄下的WxPay.Config.php文件裏的信息改成自己的信息,只需改以下四個就行:

技術分享圖片

3.把example/目錄下的notify.php改名為PayNotifyCallBack.php 不改也沒事,我是為了和該文件裏的類名保持一致

4.把裏面require_once包含的文件都寫成框架包含的形式,只要是用到的類裏面的包含都改成框架包含的形式,如:

技術分享圖片

改成:註意,“ . ”用“ # ”表示,至於為什麽,這裏不是重點,你可以看看底層代碼。

技術分享圖片

5.把native.php 裏面的模式二的php代碼拿出來,封裝起來放到控制器裏,把裏面的信息補充上去

WX_LOG(‘wxpay‘,‘60‘,‘二維碼加載完成‘); 這裏的WX_LOG()方法是我自己寫的打印日誌的函數,放在common.php文件下,怎麽寫的可以看上一篇ThinkPHP5自己寫日誌 ,使用日誌排錯還是在下面回調異步通知的方法裏還是很有用的,當初在這裏我踩了不少坑,畢竟是後臺異步,用日誌記錄比較直觀

public function pay_pc()
    {

        error_reporting(E_ERROR);

        ini_set(‘date.timezone‘,‘Asia/Shanghai‘);
        vendor(
‘wxpay_pc.lib.WxPay#Api‘); vendor(‘wxpay_pc.example.WxPay#NativePay‘); $notify = new \NativePay(); $input = new \WxPayUnifiedOrder(); // 必填項 $out_trade_no = date(‘Ymd‘) . str_pad(mt_rand(1, 99999), 6, ‘0‘, STR_PAD_LEFT);; //訂單號 $input->SetBody("蜜蜂雲"); //
商品名稱 $input->SetOut_trade_no($out_trade_no); //訂單號 $input->SetTotal_fee("1"); //價格0.01 以分為單位1分 $input->SetNotify_url(‘https://www.hulianweidu.com/index/wxpay/notify.html‘); //異步回調通知地址 $input->SetTrade_type("NATIVE"); //NATIVE 掃碼支付 $input->SetProduct_id("123456789"); //商品ID // 可填項 $input->SetAttach("互聯維度"); //附加數據 $input->SetTime_start(date("YmdHis")); //訂單生成時間 $input->SetTime_expire(date("YmdHis", time() + 600)); //訂單失效時間 $input->SetGoods_tag("PC網頁支付"); //訂單優惠標記 $result = $notify->GetPayUrl($input); WX_LOG(‘wxpay‘,‘60‘,‘二維碼加載完成‘); $url2 = urlencode($result["code_url"]); //對url中文字字符編碼 $this->assign(‘url2‘,$url2); $this->assign(‘out_trade_no‘,$out_trade_no); return $this->fetch() }

需要註意的是$input->SetTotal_fee("1"); //價格0.01 以分為單位1分,我這裏是為了方便測試,上線的時候別忘了乘以100,變成以元為單位

6.前端二維碼:二維碼$url2別忘了對中文字符編碼,因為我在對應的方法裏已經編碼過了,所以在前端就沒有再次編碼操作。

<img alt="微信掃碼支付" id="img" src="http://www.wxpay.com/example/qrcode.php?data={$url2}" style="width:150px;height:150px;"/>

7.現在二維碼生成了,現在不出意外應該能支付成功了,一種方法是可以在商戶平臺查看交易信息,一種是自己寫個方法,查看交易結果,因為這個方法下面會用到,還是推薦用這種。因為當用戶進入二維碼頁面之後,我們需要用戶支付成功之後給出相應的提示,並跳轉下一頁面,所以我們需要ajax輪詢請求剛剛說的這個方法,3秒查詢一次,去判斷用戶有沒有支付,如果支付則進入下一步操作,如果沒有支付則繼續輪詢,直到支付結果改變。

首先是前端代碼:

<body>
    <input type="hidden" id="out_trade_no" value="{$out_trade_no}" > 
    <img alt="微信掃碼支付" id="img" src="http://www.wxpay.com/example/qrcode.php?data={$url2}" style="width:150px;height:150px;"/>
    
</body>
<script src="/public/index/index/vendor/bootstrap/jquery-3.2.1.min.js"></script>
<script type="text/javascript">

    var time = setInterval("check()",3000);    //3秒查詢一次是否支付成功

    function check() {
        var url = "{:url(‘/index/Wxpay/orderstate‘)}";
        var out_trade_no = $("#out_trade_no").val();
        var param = {out_trade_no:out_trade_no};
        $.post(url,param,function(data){
            data = JSON.parse(data);
            if (data[trade_state] == SUCCESS) {
                
                time = window.clearInterval(time);
                // 支付成功把二維碼替換成支付成功圖標
                $("#img").attr(src,/public/index/pay/images/success.png);
                console.log(data);
                // window.location.href="{:url(‘/index/wxpay/notify‘)}";
            }else{
                console.log(data);
            }
        });
    }
</script>

註意:別忘了在傳二維碼$url2的時候順便把訂單號也傳過來,可以看上面的代碼,並把訂單號放在隱藏域,使用該訂單號去查詢該訂單的支付結果

後端代碼:

//訂單查詢結果
    public function orderstate()
    {
        error_reporting(E_ERROR);
        ini_set(‘date.timezone‘,‘Asia/Shanghai‘);
        vendor(‘wxpay_pc.lib.WxPay#Api‘);

        if(isset($_REQUEST["transaction_id"]) && $_REQUEST["transaction_id"] != ""){
            $transaction_id = $_REQUEST["transaction_id"];
            $input = new \WxPayOrderQuery();
            $input->SetTransaction_id($transaction_id);
            echo json_encode(\WxPayApi::orderQuery($input));
            exit();
        }

        if(isset($_REQUEST["out_trade_no"]) && $_REQUEST["out_trade_no"] != ""){
            $out_trade_no = $_REQUEST["out_trade_no"];
            $input = new \WxPayOrderQuery();
            $input->SetOut_trade_no($out_trade_no);
            echo json_encode(\WxPayApi::orderQuery($input));
            exit();
        }
    }

為掃碼支付的時候顯示

技術分享圖片

掃碼支付成功後,trade_state會改為SECCESS,成功的時候就可以進行後面的操作了(更改通知信息,跳轉頁面)

8.支付成功後,微信服務器會異步返回你信息(xml格式數據),判斷是否正確(包括簽名),就是在最上面那段代碼要填的異步通知地址,這個地址必須保證外網能訪問,就是必須放在線上。關於異步回調當初可是坑了我不少啊!

關於異步通知的代碼,其他不用改,就是把/example/PayNotifyCallBack.php(官網裏notify.php)裏的代碼最後幾行註釋掉了,其他的沒改:

<?php
ini_set(‘date.timezone‘,‘Asia/Shanghai‘);
error_reporting(E_ERROR);

vendor(‘wxpay_pc.lib.WxPay#Api‘);
vendor(‘wxpay_pc.lib.WxPay#Notify‘);
vendor(‘wxpay_pc.example.log‘);
        
//初始化日誌
// $logHandler= new CLogFileHandler("../logs/".date(‘Y-m-d‘).‘.log‘);
// $log = Log::Init($logHandler, 15);

class PayNotifyCallBack extends WxPayNotify
{
    //查詢訂單
    public function Queryorder($transaction_id)
    {
        $input = new \WxPayOrderQuery();
        $input->SetTransaction_id($transaction_id);
        $result = \WxPayApi::orderQuery($input);
        // Log::DEBUG("query:" . json_encode($result));
        if(array_key_exists("return_code", $result)
            && array_key_exists("result_code", $result)
            && $result["return_code"] == "SUCCESS"
            && $result["result_code"] == "SUCCESS")
        {
            
            return true;
        }
        return false;
    }
    
    //重寫回調處理函數  通知地址
    public function NotifyProcess($data, &$msg)
    {
        // Log::DEBUG("call back:" . json_encode($data));
        $notfiyOutput = array();
        
        if(!array_key_exists("transaction_id", $data)){
            $msg = "輸入參數不正確";
            return false;
        }
        //查詢訂單,判斷訂單真實性
        if(!$this->Queryorder($data["transaction_id"])){
            $msg = "訂單查詢失敗";
            return false;
        }
        
        return true;
    }
}

// Log::DEBUG("begin notify");
// $notify = new PayNotifyCallBack();
// $notify->Handle(false);

這是異步返回的數據:

技術分享圖片

只需判斷 return_code 是否等於SUCCESS

然後就是異步回調通知這個方法了:

    // 回調頁面
    public function notify() {

      // 是否接收到了返回的xml數據
      // $data = file_get_contents(‘php://input‘);
      // WX_LOG(‘wxpay‘,‘95‘,$data);

     error_reporting(E_ERROR);
        ini_set(‘date.timezone‘, ‘Asia/Shanghai‘);
        vendor(‘wxpay_pc.example.PayNotifyCallBack‘);
               
        $notify = new \PayNotifyCallBack();
        $notify->Handle(false);    

        $result = $notify->GetValues();    //數組
// ///////////////////更新支付狀態//////////////
        if ($result[‘return_code‘] == ‘SUCCESS‘) {
            //訂單支付完成,修改訂單狀態,發貨。
            $res = Db::table(‘test‘)->insert([‘state‘=>1]);
            if ($res) {
                WX_LOG(‘wxpay‘,‘114‘,‘支付成功‘);
            }else{
                WX_LOG(‘wxpay‘,‘116‘,‘支付失敗‘);
            }
        }
    }

操作數據庫等邏輯,只需要在這個方法寫就行了!

對於這個方法,因為是後臺異步操作的,前端看不到,所以建議打印日誌,看看微信服務器有沒有給這個方法傳數據,方便排錯!

支付頁面pay_pc,查詢訂單結果orderstate,異步回調notify,我都寫在wxpay這個控制器裏面了。

9.到現在整個微信掃碼支付整個流程就完成了!

ThinkPHP5微信掃碼支付