tp5 -- 微信公衆號支付

近來期間比較忙, 忙完以後發現最近有挺多的東西沒有整理,因而乎。就將之前用到的一些小東西整理了一下。javascript

若是對您有幫助,則是我最大的幸運。php

本篇主要是說了一下整合TP5的微信公衆號支付。html

不過因爲最近TP6已經出了,小夥伴們要記得向最新的進發哦。前端

好了,廢話很少說了。開始。java

首先呢,須要引入咱們封裝好的類庫:數據庫

一樣在 extend/ 下json

由於會將支付類庫放在一塊兒,因而就在extend 文件夾下建立了一個pay文件夾用來存儲全部類文件。api

如下內容爲wxpay類的內容:數組

namespace pay;

class Wxpay
{
    private $config =[
        "appid"      => "********",    //   公衆號ID
        "mch_id"     => "********",    //   商戶號
        "notify_url" => "********",    //   回調地址
        "key"        => "********",    //   微信支付 商戶祕鑰KEY
    ];
    public function index($param,$openid)
    {
        $order=array(
            'body'          => $param['body'],// 商品描述
            'total_fee'     => intval($param['total']*100),// 訂單金額  以(分)爲單位
            // 'total_fee'     => 1, 
            'out_trade_no'  => $param['order_sn'],// 訂單號
            'trade_type'    => 'JSAPI',// JSAPI公衆號支付
            'openid'        => $openid// 獲取到的openid
        );
        $userip = $param['userip'];
        // 統一下單 獲取prepay_id
        $unified_order=$this->unifiedOrder($order,$userip);
        // 獲取當前時間戳
        $time=time();
        // 組合jssdk須要用到的數據
        $data=array(
            'appId'     =>$this->config['appid'], //appid
            'timeStamp' =>strval($time), //時間戳
            'nonceStr'  =>$unified_order['nonce_str'],// 隨機字符串
            'package'   =>'prepay_id='.$unified_order['prepay_id'],// 預支付交易會話標識
            'signType'  =>'MD5'      //加密方式
        );
        // 生成簽名
        $data['paySign']=$this->makeSign($data);
        return $data;
    }
    /**
     * 統一下單
     * @param  array $order 訂單 必須包含支付所須要的參數 body(產品描述)、total_fee(訂單金額)、out_trade_no(訂單號)、product_id(產品id)、trade_type(類型:JSAPI,NATIVE,APP)
     */
    public function unifiedOrder($order,$userip)
    {
        $config=array(
            'appid'             => $this->config['appid'], //appid
            'mch_id'            => $this->config['mch_id'], //商戶號ID
            'nonce_str'         => $this->getNonceStr(),
            'spbill_create_ip'  => $userip,  //你的IP
            'notify_url'        => $this->config['notify_url'],
            //'notify_url'        =>$url
            );
        // 合併配置數據和訂單數據
        $data=array_merge($order,$config);
        // 生成簽名
        $sign=$this->makeSign($data);
        $data['sign']=$sign;
        //轉換成xml
        $xml=$this->toXml($data);
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//接收xml數據的文件
        $header[] = "Content-type: text/xml";//定義content-type爲xml,注意是數組
        $ch = curl_init ($url);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 兼容本地沒有指定curl.cainfo路徑的錯誤
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $response = curl_exec($ch);
        if(curl_errno($ch)){
            // 顯示報錯信息;終止繼續執行
            die(curl_error($ch));
        }
        curl_close($ch);
        //轉換成數組
        $result=$this->toArray($response);
        //dump($result);
        // 顯示錯誤信息
        if ($result['return_code']=='FAIL') {
            die($result['return_msg']);
        }
        $result['sign']=$sign;
        $result['nonce_str']=$this->getNonceStr();
        return $result;
    }
    /**
     * 生成簽名
     * @return 簽名,本函數不覆蓋sign成員變量,如要設置簽名須要調用SetSign方法賦值
     */
    public function makeSign($data)
    {
        // 去空
        $data=array_filter($data);
        //簽名步驟一:按字典序排序參數
        ksort($data);
        //將數組轉成url形式
        $string_a=http_build_query($data);
        $string_a=urldecode($string_a);
        //簽名步驟二:在string後加入KEY
        $string_sign_temp=$string_a."&key=".$this->config['key'];
        //簽名步驟三:MD5加密
        $sign = md5($string_sign_temp);
        // 簽名步驟四:全部字符轉爲大寫
        $result=strtoupper($sign);
        return $result;
    }

    /**
     * 將xml轉爲array
     * @param  string $xml xml字符串
     * @return array       轉換獲得的數組
     */
    public function toArray($xml){   
        //禁止引用外部xml實體
        libxml_disable_entity_loader(true);
        $result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);        
        return $result;
    }

    /**
     * 
     * 產生隨機字符串,不長於32位
     * @param int $length
     * @return 產生的隨機字符串
     */
    public function getNonceStr($length = 32) 
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";  
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {  
            $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);  
        } 
        return $str;
    }

    /**
     * 輸出xml字符
     * @throws WxPayException
     */
    public function toXml($data){
        if(!is_array($data) || count($data) <= 0){
            throw new WxPayException("數組數據異常!");
        }
        $xml = "<xml>";
        foreach ($data as $key=>$val){
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml; 
    }

    /**
     * 驗證
     * @return array 返回數組格式的notify數據
     */
    public function notify(){
        // 獲取xml
        $xml=file_get_contents('php://input', 'r'); 
        // 轉成php數組
        $data=$this->toArray($xml);
        // 保存原sign
        $data_sign=$data['sign'];
        // sign不參與簽名
        unset($data['sign']);
        $sign=$this->makeSign($data);
        // 判斷簽名是否正確  判斷支付狀態
        if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') {
            $result=$data;
        }else{
            $result=false;
        }
        // 返回狀態給微信服務器
        if ($result) {
            $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        }else{
            $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[簽名失敗]]></return_msg></xml>';
        }
        // file_put_contents("./Public/aaa.text",$result);
        // echo $str;
        return $result;
    }

    public function https_request($url, $data = null)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)){
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
         // var_dump($output);
        curl_close($curl);
        return $output;
    }

}

而後就是調用方法了:服務器

namespace app\index\controller;

use pay\Wxpay;

class Index extends Base
{
    /**
     *調用支付接口
     *
     */
    public function getorder()
    {

        $param = input('get.');
        $pays   = model('pay')->where('id',$id)->find();
        $wxpay = [
            'order_sn' => $pays['pay_sn'],   //支付訂單號
            'total'    => $pays['money'],    //支付總額
            'body'     => $pays['body'],     //支付說明
            'userip'   => $pays['userip'],   //用戶IP
        ];

        $openid = $this->_user['openid'];

        $pay = new Wxpay();
        $data = $pay->index($wxpay,$openid);

        $logUrl = "********"; //支付完成跳轉地址
 
        $this->assign([
                'data'=>json_encode($data),
                'logUrl'=>$logUrl,
            ]);
        return $this->fetch();
    }
    
    
    
}

其次是對應的調用空白頁面:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>訂單提交成功</title>

    <style>
        .info{
            text-align: center;
            margin-top: 40px;
        }
    </style>
</head>

<body>
<div class="info">支付進行中,請稍候...</div>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
        //調用微信JS api 支付
        function onBridgeReady(){
            var data = {$data};
                WeixinJSBridge.invoke(
                      'getBrandWCPayRequest', data, 
                    function(res){
                        if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                            // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回    ok,但並不保證它絕對可靠。
                            window.location.href="{$logUrl}"; 
                        }else{
                           alert('支付失敗');
                           // alert(res.err_code+res.err_desc+res.err_msg); // 顯示錯誤信息 
                        }
                    }
                );
            }
             
             if (typeof WeixinJSBridge == "undefined"){
                 if( document.addEventListener ){
                     document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
                 }else if (document.attachEvent){
                     document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
                     document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
                 }
             }else{
                  onBridgeReady();
             }
</script>


</body>
</html>

最後就是回調了(拿到回調在此控制器匯中進行數據庫操做):

namespace app\index\controller;

use Think\Controller;
/** * 支付回調 -- 接收並處理調整數據庫 */ class ClassName extends AnotherClass { private $config =[ "key" => "*******", //微信支付 商戶祕鑰KEY ]; /** * notify_url接收頁面 */ public function wxpaynotify() { $result=$this->notify(); if ($result) {//如下爲處理數據庫操做等 操做完成後輸出success echo "SUCCESS"; } } /** * 一下驗證類 活獲取 token 等可寫入至 common 公告類中 * 驗證 * @return array 返回數組格式的notify數據 */ public function notify(){ // 獲取xml $xml=file_get_contents('php://input', 'r'); // 轉成php數組 $data=$this->toArray($xml); // 保存原sign $data_sign=$data['sign']; // sign不參與簽名 unset($data['sign']); $sign=$this->makeSign($data); // 判斷簽名是否正確 判斷支付狀態 if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') { $result=$data; }else{ $result=false; } // 返回狀態給微信服務器 if ($result) { $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; }else{ $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[簽名失敗]]></return_msg></xml>'; } // file_put_contents("./Public/aaa.text",$result); // echo $str; return $result; } /** * 將xml轉爲array * @param string $xml xml字符串 * @return array 轉換獲得的數組 */ public function toArray($xml){ //禁止引用外部xml實體 libxml_disable_entity_loader(true); $result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $result; } /** * 生成簽名 * @return 簽名,本函數不覆蓋sign成員變量,如要設置簽名須要調用SetSign方法賦值 */ public function makeSign($data) { // 去空 $data=array_filter($data); //簽名步驟一:按字典序排序參數 ksort($data); //將數組轉成url形式 $string_a=http_build_query($data); $string_a=urldecode($string_a); //簽名步驟二:在string後加入KEY $string_sign_temp=$string_a."&key=".$this->config['key']; //簽名步驟三:MD5加密 $sign = md5($string_sign_temp); // 簽名步驟四:全部字符轉爲大寫 $result=strtoupper($sign); return $result; } }

以上就是微信公衆號支付的所有內容。

若有疑問,請評論或留言。

感謝您的查看。

2019年05月31日

相關文章
相關標籤/搜索