讀古今文學網 > 微信公眾平台開發:從零基礎到ThinkPHP5高性能框架實踐 > 17.2 公眾號支付 >

17.2 公眾號支付

公眾號支付即JS API支付,是用戶在微信中打開商戶的Web頁面,商戶在Web頁面通過調用微信支付提供的JS API接口調起微信支付模塊完成支付。其應用場景有:

·用戶在微信公眾號內進入商家公眾號,打開某個主頁面,完成支付。

·用戶的好友在朋友圈、聊天窗口等分享商家頁面鏈接,用戶點擊鏈接打開商家頁面,完成支付。

·將商戶頁面轉換成二維碼,用戶掃瞄二維碼後在微信瀏覽器中打開頁面,完成支付。

微信支付的接口類代碼如下。


  1 /**
  2 * JS API支付——H5網頁端調起支付接口
  3 */
  4 class JsApi_pub extends Common_util_pub
  5 {
  6     var $code;                // Code碼,用於獲取OpenID
  7     var $openid;        // 用戶的OpenID
  8     var $parameters;        // jsapi參數,格式為JSON
  9     var $prepay_id;        // 使用統一支付接口得到的預支付ID
 10     var $curl_timeout;// curl超時時間
 11 
 12     function __construct
 13     {
 14         // 設置curl超時時間
 15         $this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;
 16     }
 17 
 18     /**
 19      *     作用:生成可以獲得Code的URL
 20      */
 21     function createOauthUrlForCode($redirectUrl)
 22     {
 23         $urlObj["appid"] = WxPayConf_pub::APPID;
 24         $urlObj["redirect_uri"] = urlencode($redirectUrl);
 25         $urlObj["response_type"] = "code";
 26         $urlObj["scope"] = "snsapi_base";
 27         $urlObj["state"] = "STATE"."#wechat_redirect";
 28         $bizString = $this->formatBizQueryParaMap($urlObj, false);
 29         return "https:// open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
 30     }
 31 
 32     /**
 33      *     作用:生成可以獲得OpenID的URL
 34      */
 35     function createOauthUrlForOpenid
 36     {
 37         $urlObj["appid"] = WxPayConf_pub::APPID;
 38         $urlObj["secret"] = WxPayConf_pub::APPSECRET;
 39         $urlObj["code"] = $this->code;
 40         $urlObj["grant_type"] = "authorization_code";
 41         $bizString = $this->formatBizQueryParaMap($urlObj, false);
 42         return "https:// api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
 43     }
 44 
 45 
 46     /**
 47      *     作用:通過curl向微信提交Code,以獲取OpenID
 48      */
 49     function getOpenid
 50     {
 51         $url = $this->createOauthUrlForOpenid;
 52         // 初始化curl
 53         $ch = curl_init;
 54         // 設置超時
 55         curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
 56         curl_setopt($ch, CURLOPT_URL, $url);
 57         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
 58         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
 59         curl_setopt($ch, CURLOPT_HEADER, FALSE);
 60         curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
 61         // 運行curl,結果以JSON形式返回
 62         $res = curl_exec($ch);
 63         curl_close($ch);
 64         // 取出OpenID
 65         $data = json_decode($res,true);
 66         $this->openid = $data['openid'];
 67         return $this->openid;
 68     }
 69 
 70     /**
 71      *     作用:設置prepay_id
 72      */
 73     function setPrepayId($prepayId)
 74     {
 75         $this->prepay_id = $prepayId;
 76     }
 77 
 78     /**
 79      *     作用:設置Code
 80      */
 81     function setCode($code_)
 82     {
 83         $this->code = $code_;
 84     }
 85 
 86     /**
 87      *     作用:設置jsapi的參數
 88      */
 89     public function getParameters
 90     {
 91         $jsApiObj["appId"] = WxPayConf_pub::APPID;
 92         $timeStamp = time;
 93         $jsApiObj["timeStamp"] = "$timeStamp";
 94         $jsApiObj["nonceStr"] = $this->createNoncestr;
 95         $jsApiObj["package"] = "prepay_id=$this->prepay_id";
 96         $jsApiObj["signType"] = "MD5";
 97         $jsApiObj["paySign"] = $this->getSign($jsApiObj);
 98         $this->parameters = json_encode($jsApiObj);
 99         return $this->parameters;
100     }
101 }

  

公眾號支付的支付流程說明如下。

JS API支付前需要調用網頁授權接口獲取用戶的OpenID。其實現的代碼片段如下。


 1 // 使用JS API接口
 2 $jsApi = new JsApi_pub;
 3 
 4 // =========步驟1:網頁授權獲取用戶的OpenID============
 5 // 通過Code獲得OpenID
 6 if (!isset($_GET['code']))
 7 {
 8     // 觸發微信返回Code碼
 9     $url = $jsApi->createOauthUrlForCode(WxPayConf_pub::JS_API_CALL_URL);
10     Header("Location: $url"); 
11 }else
12 {
13     // 獲取Code碼,以獲取OpenID
14     $code = $_GET['code'];
15     $jsApi->setCode($code);
16     $openid = $jsApi->getOpenId;
17 }
  

然後填充支付的參數,其中統一支付接口已經自動填充了以下參數的值。其代碼如下。


$this->parameters["appid"] = WxPayConf_pub::APPID;                    // 公眾賬號ID
$this->parameters["mch_id"] = WxPayConf_pub::MCHID;                   // 商戶號
$this->parameters["spbill_create_ip"] = $_SERVER['REMOTE_ADDR'];      // 終端IP
$this->parameters["nonce_str"] = $this->createNoncestr;          // 隨機字符串
$this->parameters["sign"] = $this->getSign($this->parameters);  // 簽名
 

JS API支付再另外填寫以下必要的參數,代碼如下。


 1 // 統一支付接口中,trade_type為JSAPI時,OpenID為必填參數!
 2 $unifiedOrder->setParameter("openid","$openid");        // 商品描述
 3 $unifiedOrder->setParameter("body","方倍工作室");        // 商品描述
 4 // 自定義訂單號,此處僅作舉例
 5 $timeStamp = time;
 6 $out_trade_no = WxPayConf_pub::APPID."$timeStamp";
 7 $unifiedOrder->setParameter("out_trade_no","$out_trade_no");         // 商戶訂單號 
 8 $unifiedOrder->setParameter("total_fee","1");             // 總金額
 9 $unifiedOrder->setParameter("notify_url",WxPayConf_pub::NOTIFY_URL);  // 通知地址
10 $unifiedOrder->setParameter("trade_type","JSAPI");        // 交易類型
  

這些參數將生成一個如下的XML示例數據。


<xml>
    <openid><![CDATA[ou9dHt0L8qFLI1foP-kj5x1mDWsM]]></openid>
    <body><![CDATA[方倍工作室]]></body>
    <out_trade_no><![CDATA[wx88888888888888881414411779]]></out_trade_no>
    <total_fee>1</total_fee>
    <notify_url><![CDATA[http:// www.fangbei.org/wxpay/notify_url.php]]></notify_url>
    <trade_type><![CDATA[JSAPI]]></trade_type>
    <appid><![CDATA[wx8888888888888888]]></appid>
    <mch_id>10012345</mch_id>
    <spbill_create_ip><![CDATA[61.50.221.43]]></spbill_create_ip>
    <nonce_str><![CDATA[60uf9sh6nmppr9azveb2bn7arhy79izk]]></nonce_str>
    <sign><![CDATA[2D8A96553672D56BB2908CE4B0A23D0F]]></sign>
</xml>
  

將這些數據提交給統一支付接口後,返回如下XML數據。


<xml>
    <return_code><![CDATA[SUCCESS]]></return_code>  
    <return_msg><![CDATA[OK]]></return_msg>  
    <appid><![CDATA[wx8888888888888888]]></appid>  
    <mch_id><![CDATA[10012345]]></mch_id>  
    <nonce_str><![CDATA[Be8YX7gjCdtCT7cr]]></nonce_str>  
    <sign><![CDATA[885B6D84635AE6C020EF753A00C8EEDB]]></sign>  
    <result_code><![CDATA[SUCCESS]]></result_code>  
    <prepay_id><![CDATA[wx201410272009395522657a690389285100]]></prepay_id>  
    <trade_type><![CDATA[JSAPI]]></trade_type> 
</xml>
  

其中包含了最重要的預支付ID參數prepay_id。

前面的準備工作做好以後,JS API根據prepay_id生成jsapi支付參數,代碼如下。


// =========步驟3:使用jsapi調起支付============
$jsApi->setPrepayId($prepay_id);
$jsApiParameters = $jsApi->getParameters;
  

上述代碼生成的JSON參數如下。


{
    "appId": "wx8888888888888888",
    "timeStamp": "1414411784",
    "nonceStr": "gbwr71b5no6q6ne18c8up1u7l7he2y75",
    "package": "prepay_id=wx201410272009395522657a690389285100",
    "signType": "MD5",
    "paySign": "9C6747193720F851EB876299D59F6C7D"
}
  

最後在微信瀏覽器中使用上述參數調起微信支付,其代碼如下。


<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
    <title>微信安全支付</title>
    <script type="text/javascript">
        // 調用微信JS API支付
        function jsApiCall
        {
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest',
                <?php echo $jsApiParameters; ?>,
                function(res){
                    WeixinJSBridge.log(res.err_msg);
                    // alert(res.err_code+res.err_desc+res.err_msg);
                }
            );
        }

        function callpay
        {
            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;
            }
        }
    </script>
</head>
<body>
    </br></br></br></br>
    <p >
        <button  type="button" 
        onclick="callpay" >貢獻一下</button>
    </p>
</body>
</html>
  

當用戶點擊「貢獻一下」按鈕時,將彈出微信支付插件,用戶就可以開始進行微信支付了。