1. 程式人生 > >ThinkPHP整合微信支付之JSAPI模式

ThinkPHP整合微信支付之JSAPI模式

目前微信是很火的,微信支付目前很少在網上能看到一系列詳細的demo,因此,花一點時間來做一下關於微信支付系列教程,本次教程是JSAPI模式支付,其他的還會繼續寫下去
首先,下載微信支付的demo,我們根據微信上的demo來整合到TP中。

介紹下我們這裡需要用到的幾個檔案:

在demo資料夾中:
js_api_call.php:提供了微信jsapi的主要功能
log_.php:提供列印日誌功能
notify_url.php:非同步通知功能
notify_url.log:非同步通知日誌
qrcode.js:生成二維碼js外掛

接下來介紹下WxPayPubHelper資料夾下的檔案:

cacert 資料夾是存放微信證書的(PS:具體我還沒怎麼用證書,雖然下載下來了,證書請在微信商戶平臺上下載)
SDKRuntimeException.php:這個就是處理異常的、
WxPay.pub.config.php:這個是做一些配置的,稍後會詳細講解
WxPayPubHelper.php:這個其實就是微信支付的工具類,對於初學者只要知道怎麼用他裡面的方法就夠了

OK,瞭解了微信官方提供的檔案,我們就可以開始整合到TP中了,廢話不多說,這就開始!

step1:將demo中的WxPayPubHelper整個資料夾都複製到TP的Vendor目錄下,像我這樣:


step2:配置WxPay.pub.config.php檔案:
這裡的配置都有註釋,如果還有不懂或者配置出現問題可以留言提問
同時我把微信的這個配置放到了TP的config中,這一步大家可以隨意
  1. <?php
  2. return array(
  3. //'配置項'=>'配置值'
  4.     define('WEB_HOST','這是您的網站域名地址'),
  5. /*微信支付配置*/
  6. 'WxPayConf_pub'=>array(
  7. 'APPID'=>'您的APPID',
  8. 'MCHID'=>'您的商戶ID',
  9. 'KEY'=>'商戶祕鑰',
  10. 'APPSECRET'=>'您的APPSECRET',
  11. 'JS_API_CALL_URL'
    => WEB_HOST.'/index.php/Home/WxJsAPI/jsApiCall',
  12. 'SSLCERT_PATH'=> WEB_HOST.'/ThinkPHP/Library/Vendor/WxPayPubHelper/cacert/apiclient_cert.pem',
  13. 'SSLKEY_PATH'=> WEB_HOST.'/ThinkPHP/Library/Vendor/WxPayPubHelper/cacert/apiclient_key.pem',
  14. 'NOTIFY_URL'=>  WEB_HOST.'/index.php/Home/WxJsAPI/notify',
  15. 'CURL_TIMEOUT'=>
    30
  16. )
  17. );
複製程式碼 step3:將生成二維碼的js放在Public目錄下(這裡目前用不到,在用掃碼支付的情況才用到這個js),將日誌檔案放在Public目錄下:像我這樣:

step4:建立控制器:這裡建立了一個WxJsAPIController的控制器,這裡大家隨便起名字,只要這個跟你們在公眾平臺上的設定相對應就可以(公眾平臺設定稍後介紹)

下面是控制器的程式碼部分了,首先初始化控制器,將WxPayPubHelper匯入
  1. /**
  2.      * 初始化
  3.      */
  4. publicfunction _initialize()
  5. {
  6. //引入WxPayPubHelper
  7.         vendor('WxPayPubHelper.WxPayPubHelper');
  8. }
複製程式碼 接下來是使用統一支付介面,獲取prepay_id的方法:
  1. publicfunction jsApiCall()
  2. {
  3. //使用jsapi介面
  4.         $jsApi =new \JsApi_pub();
  5. //=========步驟1:網頁授權獲取使用者openid============
  6. //通過code獲得openid
  7. if(!isset($_GET['code']))
  8. {
  9. //觸發微信返回code碼
  10.             $url = $jsApi->createOauthUrlForCode(C('WxPayConf_pub.JS_API_CALL_URL'));
  11. Header("Location: $url");
  12. }else
  13. {
  14. //獲取code碼,以獲取openid
  15.             $code = $_GET['code'];
  16.             $jsApi->setCode($code);
  17.             $openid = $jsApi->getOpenId();
  18. }
  19. //=========步驟2:使用統一支付介面,獲取prepay_id============
  20. //使用統一支付介面
  21.         $unifiedOrder =new \UnifiedOrder_pub();
  22. //設定統一支付介面引數
  23. //設定必填引數
  24. //appid已填,商戶無需重複填寫
  25. //mch_id已填,商戶無需重複填寫
  26. //noncestr已填,商戶無需重複填寫
  27. //spbill_create_ip已填,商戶無需重複填寫
  28. //sign已填,商戶無需重複填寫
  29.         $unifiedOrder->setParameter("openid",$openid);//商品描述
  30.         $unifiedOrder->setParameter("body","貢獻一分錢");//商品描述
  31. //自定義訂單號,此處僅作舉例
  32.         $timeStamp = time();
  33.         $out_trade_no = C('WxPayConf_pub.APPID').$timeStamp;
  34.         $unifiedOrder->setParameter("out_trade_no",$out_trade_no);//商戶訂單號
  35.         $unifiedOrder->setParameter("total_fee","1");//總金額
  36.         $unifiedOrder->setParameter("notify_url",C('WxPayConf_pub.NOTIFY_URL'));//通知地址
  37.         $unifiedOrder->setParameter("trade_type","JSAPI");//交易型別
  38. //非必填引數,商戶可根據實際情況選填
  39. //$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商戶號
  40. //$unifiedOrder->setParameter("device_info","XXXX");//裝置號
  41. //$unifiedOrder->setParameter("attach","XXXX");//附加資料
  42. //$unifiedOrder->setParameter("time_start","XXXX");//交易起始時間
  43. //$unifiedOrder->setParameter("time_expire","XXXX");//交易結束時間
  44. //$unifiedOrder->setParameter("goods_tag","XXXX");//商品標記
  45. //$unifiedOrder->setParameter("openid","XXXX");//使用者標識
  46. //$unifiedOrder->setParameter("product_id","XXXX");//商品ID
  47.         $prepay_id = $unifiedOrder->getPrepayId();
  48. //=========步驟3:使用jsapi調起支付============
  49.         $jsApi->setPrepayId($prepay_id);
  50.         $jsApiParameters = $jsApi->getParameters();
  51.         $this->assign('jsApiParameters',$jsApiParameters);
  52.         $this->display('pay');
  53. //echo $jsApiParameters;
  54. }
複製程式碼 這裡都是複製微信demo的,改改名字罷了,沒什麼其他的

接下來是非同步通知方法,也是複製的微信demo上的
  1. publicfunction notify()
  2. {
  3. //使用通用通知介面
  4.         $notify =new \Notify_pub();
  5. //儲存微信的回撥
  6.         $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
  7.         $notify->saveData($xml);
  8. //驗證簽名,並回應微信。
  9. //對後臺通知互動時,如果微信收到商戶的應答不是成功或超時,微信認為通知失敗,
  10. //微信會通過一定的策略(如30分鐘共8次)定期重新發起通知,
  11. //儘可能提高通知的成功率,但微信不保證通知最終能成功。
  12. if($notify->checkSign()== FALSE){
  13.             $notify->setReturnParameter("return_code","FAIL");//返回狀態碼
  14.             $notify->setReturnParameter("return_msg","簽名失敗");//返回資訊
  15. }else{
  16.             $notify->setReturnParameter("return_code","SUCCESS");//設定返回碼
  17. }
  18.         $returnXml = $notify->returnXml();
  19.         echo $returnXml;
  20. //==商戶根據實際情況設定相應的處理流程,此處僅作舉例=======
  21. //以log檔案形式記錄回撥資訊
  22. //         $log_ = new Log_();
  23.         $log_name= __ROOT__."/Public/notify_url.log";//log檔案路徑
  24.         log_result($log_name,"【接收到的notify通知】:\n".$xml."\n");
  25. if($notify->checkSign()== TRUE)
  26. {
  27. if($notify->data["return_code"]=="FAIL"){
  28. //此處應該更新一下訂單狀態,商戶自行增刪操作
  29.                 log_result($log_name,"【通訊出錯】:\n".$xml."\n");
  30. }
  31.             elseif($notify->data["result_code"]=="FAIL"){
  32. //此處應該更新一下訂單狀態,商戶自行增刪操作
  33.                 log_result($log_name,"【業務出錯】:\n".$xml."\n");
  34. }
  35. else{
  36. //此處應該更新一下訂單狀態,商戶自行增刪操作
  37.                 log_result($log_name,"【支付成功】:\n".$xml."\n");
  38. }
  39. //商戶自行增加處理流程,
  40. //例如:更新訂單狀態
  41. //例如:資料庫操作
  42. //例如:推送支付完成資訊
  43. }
  44. }
複製程式碼 這裡我把記錄日誌的類寫到了function.php中:
  1. function  log_result($file,$word)
  2. {
  3.     $fp = fopen($file,"a");
  4.     flock($fp, LOCK_EX);
  5.     fwrite($fp,"執行日期:".strftime("%Y-%m-%d-%H:%M:%S",time())."\n".$word."\n\n");
  6.     flock($fp, LOCK_UN);
  7.     fclose($fp);
  8. }
複製程式碼 好了 其實控制器的方法就這麼多,沒什麼其他的了,下面看一下頁面,直接上程式碼吧:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <metahttp-equiv="content-type"content="text/html;charset=utf-8"/>
  5. <title>微信安全支付</title>
  6. <scripttype="text/javascript">
  7. //呼叫微信JS api 支付
  8. function jsApiCall()
  9. {
  10. WeixinJSBridge.invoke(
  11. 'getBrandWCPayRequest',
  12. <?php echo $jsApiParameters;?>,
  13. function(res){
  14. WeixinJSBridge.log(res.err_msg);
  15.                     alert(res.err_code+res.err_desc+res.err_msg);
  16. //alert("{$jsApiParameters}");
  17. }
  18. );
  19. }
  20. function callpay()
  21. {
  22. if(typeofWeixinJSBridge=="undefined"){
  23. if( document.addEventListener ){
  24.                     document.addEventListener('WeixinJSBridgeReady', jsApiCall,false);
  25. }elseif(document.attachEvent){
  26.                     document.attachEvent('WeixinJSBridgeReady', jsApiCall);
  27.                     document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
  28. }
  29. }else{
  30.                 jsApiCall();
  31. }
  32. }
  33. </script>
  34. </head>
  35. <body>
  36. </br></br></br></br>
  37. <divalign="center">
  38. <buttonstyle="width:210px; height:30px; background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer;  color:white;  font-size:16px;"type="button"onclick="callpay()">貢獻一下</button>
  39. </div>
  40. </body>
  41. </html>
複製程式碼 無須改動什麼,直接複製就好


接下來是微信公眾平臺上的配置了,這裡我遇到過問題,如果有在這裡遇到問題的同學請留言,比如出現了access_deined或者access_notallowed等問題,這都可能是因為這裡配置不對。
請看配置過程截圖:
點選修改進入配置:

好了,可以測試了:下面是我的測試截圖:
用微信掃描二維碼


微信上點選貢獻一下出現支付頁面:

到此為止,微信JSAPI支付功能就全部做好了

當然,如果你是第一次做,肯定會遇到各種問題,
如果你是新手,遇到的問題都不知道為什麼,
及時你做過了再做我相信還是可能由於細節上的疏忽會出現問題
不過不要煩躁,耐心的去發現問題
有問題請留言,下面還會介紹微信掃碼支付模式一,模式二的詳細教程

微信支付教程掃碼模式一:
http://www.thinkphp.cn/code/1322.html
微信支付教程掃碼模式二:
http://www.thinkphp.cn/code/1323.html
微信支付教程刷卡支付:
http://www.thinkphp.cn/code/1324.html
歡迎大家吐槽,轉載請說明出處,請支援原創,謝謝!