整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          一文快速實現微信公眾號支付功能(詳細版,建議收藏備用)

          階架構精品專題

          • Mysql優化專題(★★★★)
          • 網絡協議專題(★★★★)
          • 其余18大專題,請在主頁菜單欄查看
          • 后臺回復【加群】,獲取BAT真實面經




          微信支付類型

          微信支付實際上有很多種不同的類型,具體要使用哪一種就需要根據不同的應用場景來選擇,官方給出的參考例子:

          刷卡支付:用戶打開微信錢包的刷卡的界面,商戶掃碼后提交完成支付。

          公眾號支付:用戶在微信內進入商家H5頁面,頁面內調用JSSDK完成支付

          掃碼支付:用戶打開"微信掃一掃“,掃描商戶的二維碼后完成支付

          APP支付:商戶APP中集成微信SDK,用戶點擊后跳轉到微信內完成支付

          H5支付:用戶在微信以外的手機瀏覽器請求微信支付的場景喚起微信支付

          小程序支付:用戶在微信小程序中使用微信支付的場景

          本篇文章實現的是公眾號支付,會使用到網頁授權及微信JS-SDK相關知識,但不再詳細介紹

          建議大家先閱讀以下文章了解相關內容:

          網頁授權:https://www.jianshu.com/p/94b0e53cccc3

          微信JS-SDK:https://www.jianshu.com/p/b3c4450f845e

          實現效果如下動圖:


          公眾號支付相關配置

          本篇文章中實現的是公眾號支付,實現條件如下:

          1.需要一個已經進行微信認證的公眾號


          2.該公眾號需要開通微信支付功能


          3.到微信商戶平臺https://pay.weixin.qq.com 注冊一個商戶賬號,并關聯你的公眾號,如果需要實現小程序支付的,需要關聯小程序。


          4.擁有一個正式的應用服務器,并且注冊域名

          微信支付涉及的私密數據比較多,不允許使用natapp,花生殼之類的內網穿透工具實現,需要有正式的服務器環境,并且要注冊域名,不能使用IP。

          比如:http://www.baidu.com

          5.相關配置

          5.1 配置支付授權目錄,登錄商戶平臺——>產品中心——>開發配置

          圖中配置的例子,代表在項目根路徑下,以及web目錄下的頁面都有支付權限,如果不在該路徑的頁面,則無法調用支付功能。

          若頁面地址為:http://mywexx.xxxx.com/web/pay.html

          則需要配置為:http://mywexx.xxxx.com/web/


          5.2 設置API密鑰,登錄商戶平臺——>賬戶中心——>API安全——>API密鑰

          該密鑰在后面的代碼中計算支付簽名的時候需要使用到。


          5.3 配置JS接口安全域名與網頁授權域名,登錄公眾平臺——>公眾號設置——>功能設置

          配置網頁授權域名:主要用于獲取用戶的openId,需要識別這是哪個人。

          若對openID不了解的同學可先參考微信公眾號開發文檔:https://mp.weixin.qq.com/wiki

          配置JS接口安全域名:要讓我們的頁面中彈出輸入密碼的窗口,需要使用微信提供的JS-SDK工具,如果不配置JS接口安全域名,你的頁面無法使用JS-SDK。


          公眾號支付實現流程

          大致流程參考官方提供的時序圖:


          流程有很多,不一一演示,我們選取核心部分來實現。

          1.提供商城主頁,用戶進入后通過網頁授權獲取openid


          如果對網頁授權不熟悉的同學先參考這篇文章:

          https://www.jianshu.com/p/94b0e53cccc3

          訪問主頁的地址:http://www.wolfcode.cn/index.do

          當用戶第一次打開主頁,默認沒有code參數,此時會先重定向到獲取授權的地址

          (如果只需要獲取openid,可以使用scope為snsapi_base靜默授權的方式)

          經過授權地址再重定向到我們的index.do時,會帶上code參數,此時即可通過接口獲取用戶的openid

          @Controllerpublic class IndexController { @RequestMapping("index") public void index(String code, Model model, HttpServletResponse response,HttpServletRequest request) { //如果有code就可以去獲取用戶的openid
           if(code!=null) { //通過code來換取access_token
           JSONObject json = WeChatUtil.getWebAccessToken(code); //獲取用戶openid
           String openid = json.getString("openid"); //設置到會話中
           request.getSession().setAttribute("openid",openid); //重定向到主頁
           response.sendRedirect("/index.html");
           }else{ //重定向到授權頁面
           response.sendRedirect(WeChatUtil.WEB_REDIRECT_URL.replace("APPID",WeChatUtil.APPID)
           .replace("REDIRECT_URI", RequestUtil.getUrl(request)));
           }
           }
          }
          注意: 1. WeChatUtil.getWebAccessToken 方法在網頁授權的文章中有介紹。 
          2. WEB_REDIRECT_URL 是網頁授權的地址常量:
          public static final String WEB_REDIRECT_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?" +
           "appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base#wechat_redirect";
          

          2.點擊商品后跳轉到商品詳細頁面

          具體頁面根據自己的項目添加,主要是頁面需要提供一個可以馬上下訂單的按鈕即可。(這里不演示加入購物車功能)


          點擊立即購買按鈕跳轉到后臺下單地址,并帶上當前商品的id。

          <script>
           $(function () { //立即購買按鈕
           $("#orderBtn").click(function(){ //獲取商品id
           var id = $("#productId").val(); //提交到下單
           window.location.href = "/order.do?productId="+id;
           })
           })</script>
          

          3.接收商品參數并調用微信支付統一下單接口

          正常的業務流程是在該方法中,獲取商品id,再通過id去查詢數據庫該商品的相關屬性,比如名稱,價格等等,然后再創建業務訂單,再去調用微信支付的統一下單接口(讓微信生成預支付單,后續才可以進行支付)。

          但此處重點在支付流程,商品的屬性值和訂單相關值,暫且先使用假數據。

          接口以及參數可參考微信官方提供的統一下單文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

          根據文檔介紹,我們調用統一下單接口時需要帶上相關必填的參數如下:


          1.PNG

          把必填的參數封裝成對應的實體類:



          調用接口成功后返回的結果也封裝成實體類:



          該結果中最重要的是prepay_id參數,在頁面中彈出支付窗口時需要用到。


          注意:下單的業務邏輯,正常是需要抽取到業務層的,但是此處為了方便閱讀代碼,直接寫到了控制器上。

          @Controllerpublic class OrderController { @RequestMapping("order") public String save(Long productId,Model model,HttpServletRequest request) throws Exception { //根據商品id查詢商品詳細信息(假數據)
           //productService.getProductById(productId)
           double price = 0.01;//(0.01元)
           String productName = "SweetCity"; //生成訂單編號
           int number = (int)((Math.random()*9)*1000);//隨機數
           DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//時間
           String orderNumber = dateFormat.format(new Date()) + number; //獲取openId
           String openId = (String) request.getSession().getAttribute("openid"); //準備調用接口需要的參數
           WxOrderEntity order = new WxOrderEntity(); //公眾號appid
           order.setAppid(WeChatUtil.APPID); //商戶號
           order.setMch_id(WeChatUtil.MCH_ID); //商品描述
           order.setBody(productName); //設備號,公眾號支付直接填WEB
           order.setDevice_info("WEB"); //交易類型
           order.setTrade_type("JSAPI"); //商戶訂單號
           order.setOut_trade_no(orderNumber); //支付金額(單位:分)
           order.setTotal_fee((int)(price*100)); //用戶ip地址
           order.setSpbill_create_ip(RequestUtil.getIPAddress(request)); //用戶openid
           order.setOpenid(openId); //接收支付結果的地址
           order.setNotify_url("http://www.wolfcode.com/receive.do"); //32位隨機數(UUID去掉-就是32位的)
           String uuid = UUID.randomUUID().toString().replace("-", "");
           order.setNonce_str(uuid); //生成簽名
           String sign = WeChatUtil.getPaySign(order);
           order.setSign(sign); //調用微信支付統一下單接口,讓微信也生成一個預支付訂單
           String xmlResult = HttpUtil.post(GET_PAY_URL,XMLUtil.toXmlString(order)); //把返回的xml字符串轉成對象
           WxOrderResultEntity entity = XMLUtil.toObject(xmlResult,WxOrderResultEntity.class); //如果微信預支付單成功創建,就跳轉到支付訂單頁進行支付
           if(entity.getReturn_code().equals("SUCCESS")&&entity.getResult_code().equals("SUCCESS")){ //jssdk權限驗證參數
           TreeMap<Object, Object> map = new TreeMap<>();
           map.put("appId",WeChatUtil.APPID); long timestamp = new Date().getTime();
           map.put("timestamp",timestamp);//全小寫
           map.put("nonceStr",uuid);
           map.put("signature",WeChatUtil.getSignature(timestamp,uuid,RequestUtil.getUrl(request)));
           model.addAttribute("configMap",map); //微信支付權限驗證參數
           String prepayId = entity.getPrepay_id();
           TreeMap<Object, Object> payMap = new TreeMap<>();
           payMap.put("appId",WeChatUtil.APPID);
           payMap.put("timeStamp",timestamp);//駝峰
           payMap.put("nonceStr",uuid);
           payMap.put("package","prepay_id="+prepayId);
           payMap.put("signType","MD5");
           payMap.put("paySign",WeChatUtil.getPaySign(payMap));
           payMap.put("packageStr","prepay_id="+prepayId);
           model.addAttribute("payMap",payMap);
           } //跳轉到查看訂單頁面
           return "order";
           }
          }
          

          下面是jssdk中config權限使用到的的簽名,以及微信支付使用的簽名的算法代碼。

          官方文檔參考:

          config簽名:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

          pay簽名:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3

          /**
           * 計算jssdk-config的簽名
           * @param timestamp
           * @param noncestr
           * @param url
           * @return
           */
           public static String getSignature(Long timestamp,String noncestr,String url ){ //對所有待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)
           Map<String,Object> map = new TreeMap<>();
           map.put("jsapi_ticket",getTicket());
           map.put("timestamp",timestamp);
           map.put("noncestr",noncestr);
           map.put("url",url); //使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1
           StringBuilder sb = new StringBuilder();
           Set<String> set = map.keySet(); for (String key : set) {
           sb.append(key+"="+map.get(key)).append("&");
           } //去掉最后一個&符號
           String temp = sb.substring(0,sb.length()-1); //使用sha1加密
           return SecurityUtil.SHA1(temp);
           } /**
           * 計算微信支付的簽名
           * @param obj
           * @return
           * @throws IllegalAccessException
           */
           public static String getPaySign(Object obj) throws IllegalAccessException, IOException {
           StringBuilder sb = new StringBuilder(); //把對象轉為TreeMap集合(按照key的ASCII 碼從小到大排序)
           TreeMap<String, Object> map; if(!(obj instanceof Map)) {
           map = ObjectUtils.objectToMap(obj);
           }else{
           map = (TreeMap)obj;
           }
           Set<Map.Entry<String, Object>> entrySet = map.entrySet(); //遍歷鍵值對
           for (Map.Entry<String, Object> entry : entrySet) { //如果值為空,不參與簽名
           if(entry.getValue()!=null) { //格式key1=value1&key2=value2…
           sb.append(entry.getKey() + "=" + entry.getValue() + "&");
           }
           } //最后拼接商戶的API密鑰
           String stringSignTemp = sb.toString()+"key="+WeChatUtil.KEY; //進行md5加密并轉為大寫
           return SecurityUtil.MD5(stringSignTemp).toUpperCase();
           }
          

          4.提供訂單展示頁面


          若對微信JS-SDK不了解的同學可先參考該文章:

          https://www.jianshu.com/p/b3c4450f845e

          在頁面中調用微信JS-SDK,通過config接口注入權限驗證配置,并且添加支付功能。

          <!--jquery-->
           <script src="/js/jquery.min.js" type="text/javascript" charset="utf-8"></script>
           <!--微信的JSSDK-->
           <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
           <script>
           $(function() {
           <!--通過config接口注入權限驗證配置-->
           wx.config({ debug: true, // 開啟調試模式
           appId: '${configMap.appId}', // 公眾號的唯一標識
           timestamp: '${configMap.timestamp}', // 生成簽名的時間戳
           nonceStr: '${configMap.nonceStr}', // 生成簽名的隨機串
           signature: '${configMap.signature}',// 簽名
           jsApiList: ['chooseWXPay'] // 填入需要使用的JS接口列表,這里是先聲明我們要用到支付的JS接口
           }); <!-- config驗證成功后會調用ready中的代碼 -->
           wx.ready(function(){
           //點擊馬上付款按鈕
           $("#payBtn").click(function(){
           //彈出支付窗口
           wx.chooseWXPay({
           timestamp: '${payMap.timeStamp}', // 支付簽名時間戳,
           nonceStr: '${payMap.nonceStr}', // 支付簽名隨機串,不長于 32 位
           package: '${payMap.packageStr}', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=xxxx)
           signType: '${payMap.signType}', // 簽名方式,默認為'SHA1',使用新版支付需傳入'MD5'
           paySign: '${payMap.paySign}', // 支付簽名
           success: function (res) {
           // 支付成功后的回調函數
           alert("支付成功!");
           }
           });
           })
           });
           }); </script>
          

          點擊馬上付款后可彈出支付窗口:


          支付完成:


          5.支付結果的處理

          當用戶支付后,微信會把支付結果發送到我們前面指定的notify_url地址,我們可以根據支付結果的參數來做相關的業務邏輯,但這里暫不實現,具體支付通知結果的參數可參考官方文章:

          https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8

          作者:陳惠

          鏈接:https://www.jianshu.com/p/9c322b1a5274

          tml頁面選擇微信支付后,超鏈接請求后臺wxPayment()方法,例如鏈接請求:

          location.href="../wxPayment?userName="+userName+"&phone="+phone+"&orderAmount="+orderAmount;

          后臺接收并處理如下:

          第一步:public void wxPayment() {

          HttpServletRequest request = getRequest();

          HttpServletResponse response = getResponse();

          String userName = getPara("userName");

          String phone = getPara("phone");

          String orderAmount = getPara("orderAmount");

          try {

          response.setContentType("text/html");

          response.setCharacterEncoding("UTF-8");

          request.setCharacterEncoding("UTF-8");

          String redirect_uri=URLEncoder.encode(/*你的網頁授權域名*/, "UTF-8");

          String url =

          "https://open.weixin.qq.com/connect/oauth2/authorize?" +

          "appid=" + /*你的APPID*/ +

          "&redirect_uri=" + redirect_uri +

          "?userName=" + URLEncoder.encode(userName) +

          "%26phone=" + phone +

          "%26orderAmount=" + orderAmount +

          "&response_type=code" +

          "&scope=snsapi_base" +

          "&state=STATE" +

          "#wechat_redirect";

          response.sendRedirect(url.toString());

          } catch (Exception e) {

          log.error("微信支付出現異常", e);

          }

          此處需要注意:

          1. 網頁授權域名必須在微信公眾平臺設置過,代碼中必須加上你要跳轉且獲取參數的方法名,例如:網頁授權域名/wxPay
          2. 第一個參數必須是?掛載,后面的參數必須用%26進行轉義,否則微信識別不了
          3. 針對有漢字的參數,必須進行編碼URLEncoder.encode(參數),否則微信識別不了

          第二步:網頁授權域名后面的方法,請求回調跳轉的接口

          public void wxPay() {

          HttpServletRequest request = getRequest();

          HttpServletResponse response = getResponse();

          try {

          response.setContentType("text/html");

          request.setCharacterEncoding("UTF-8");

          response.setCharacterEncoding("UTF-8");

          String code = request.getParameter("code");

          String userName = request.getParameter("userName");

          String phone = request.getParameter("phone");

          String orderAmount = request.getParameter("orderAmount");

          } catch (Exception e) {

          log.error("微信支付出現異常", e);

          }

          }

          這樣一來,除了code,就可以獲取到其他的訂單參數啦,接下來就根據code獲取openId進行下單處理吧!我們下次分享

          可能喜歡的文章

          1-1:Nginx+PHP+FastCGI加速模式

          1-2:Nginx服務優化(隱藏版本號、修改用戶和組、設置鏈接超時)

          1-3:Nginx服務優化(日志切割與設置鏈接超時)

          2-1:Nginx均衡TCP協議服務器案例

          2-2:Nginx反向代理和靜態資源服務配置

          本文實例講述了PHP與微信支付,在公眾號支付的功能,接入Api是很簡單的,初學者總是會想得很麻煩,其實你按照api文檔給你的思路那樣做就好了,下面給大家講解一下,供大家參考,具體如下:


          編寫代碼之前會有一系列的支付的配置,這一塊可以參考微信文檔

          https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

          效果圖如下







          需要注意的事項:

          1.該文件需放到支付授權目錄下,可以在微信支付商戶平臺->產品中心->開發配置中設置。

          2.如提示簽名錯誤可以通過微信支付簽名驗證工具進行驗證:微信公眾平臺支付接口調試工具

          代碼如下:

          配置文件與支付

          <?php
          header('Content-type:text/html; Charset=utf-8');
          $mchid = 'xxxxx'; //微信支付商戶號 PartnerID 通過微信支付商戶資料審核后郵件發送
          $appid = 'xxxxx'; //微信支付申請對應的公眾號的APPID
          $appKey = 'xxxxx'; //微信支付申請對應的公眾號的APP Key
          $apiKey = 'xxxxx'; //https://pay.weixin.qq.com 帳戶設置-安全設置-API安全-API密鑰-設置API密鑰
          //①、獲取用戶openid
          $wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey);
          $openId = $wxPay->GetOpenid(); //獲取openid
          if(!$openId) exit('獲取openid失敗');
          //②、統一下單
          $outTradeNo = uniqid(); //你自己的商品訂單號
          $payAmount = 0.01; //付款金額,單位:元
          $orderName = '支付測試'; //訂單標題
          $notifyUrl = 'https://www.xxx.com/wx/'; //付款成功后的回調地址(不要有問號)
          $payTime = time(); //付款時間
          $jsApiParameters = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$orderName,$notifyUrl,$payTime);
          $jsApiParameters = json_encode($jsApiParameters);
          ?>
          


          模板文件

          <html>
           <head>
           <meta charset="utf-8" />
           <meta name="viewport" content="width=device-width, initial-scale=1"/>
           <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/>
           <font color="#9ACD32"><b>該筆訂單支付金額為<span style="color:#f00;font-size:50px"><?php echo $payAmount?>元</span>錢</b></font><br/><br/>
           <div align="center">
           <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type="button" onclick="callpay()" >立即支付</button>
           </div>
           </body>
           </html>
          


          JSAPI文件

          <?php
          class WxpayService
          {
           protected $mchid;
           protected $appid;
           protected $appKey;
           protected $apiKey;
           public $data = null;
           public function __construct($mchid, $appid, $appKey,$key)
           {
           $this->mchid = $mchid; //https://pay.weixin.qq.com 產品中心-開發配置-商戶號
           $this->appid = $appid; //微信支付申請對應的公眾號的APPID
           $this->appKey = $appKey; //微信支付申請對應的公眾號的APP Key
           $this->apiKey = $key; //https://pay.weixin.qq.com 帳戶設置-安全設置-API安全-API密鑰-設置API密鑰
           }
           /**
           * 通過跳轉獲取用戶的openid,跳轉流程如下:
           * 1、設置自己需要調回的url及其其他參數,跳轉到微信服務器https://open.weixin.qq.com/connect/oauth2/authorize
           * 2、微信服務處理完成之后會跳轉回用戶redirect_uri地址,此時會帶上一些參數,如:code
           * @return 用戶的openid
           */
           public function GetOpenid()
           {
           //通過code獲得openid
           if (!isset($_GET['code'])){
           //觸發微信返回code碼
           $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
           $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
           $url = $this->__CreateOauthUrlForCode($baseUrl);
           Header("Location: $url");
           exit();
           } else {
           //獲取code碼,以獲取openid
           $code = $_GET['code'];
           $openid = $this->getOpenidFromMp($code);
           return $openid;
           }
           }
           /**
           * 通過code從工作平臺獲取openid機器access_token
           * @param string $code 微信跳轉回來帶上的code
           * @return openid
           */
           public function GetOpenidFromMp($code)
           {
           $url = $this->__CreateOauthUrlForOpenid($code);
           $res = self::curlGet($url);
           //取出openid
           $data = json_decode($res,true);
           $this->data = $data;
           $openid = $data['openid'];
           return $openid;
           }
           /**
           * 構造獲取open和access_toke的url地址
           * @param string $code,微信跳轉帶回的code
           * @return 請求的url
           */
           private function __CreateOauthUrlForOpenid($code)
           {
           $urlObj["appid"] = $this->appid;
           $urlObj["secret"] = $this->appKey;
           $urlObj["code"] = $code;
           $urlObj["grant_type"] = "authorization_code";
           $bizString = $this->ToUrlParams($urlObj);
           return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
           }
           /**
           * 構造獲取code的url連接
           * @param string $redirectUrl 微信服務器回跳的url,需要url編碼
           * @return 返回構造好的url
           */
           private function __CreateOauthUrlForCode($redirectUrl)
           {
           $urlObj["appid"] = $this->appid;
           $urlObj["redirect_uri"] = "$redirectUrl";
           $urlObj["response_type"] = "code";
           $urlObj["scope"] = "snsapi_base";
           $urlObj["state"] = "STATE"."#wechat_redirect";
           $bizString = $this->ToUrlParams($urlObj);
           return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
           }
           /**
           * 拼接簽名字符串
           * @param array $urlObj
           * @return 返回已經拼接好的字符串
           */
           private function ToUrlParams($urlObj)
           {
           $buff = "";
           foreach ($urlObj as $k => $v)
           {
           if($k != "sign") $buff .= $k . "=" . $v . "&";
           }
           $buff = trim($buff, "&");
           return $buff;
           }
           /**
           * 統一下單
           * @param string $openid 調用【網頁授權獲取用戶信息】接口獲取到用戶在該公眾號下的Openid
           * @param float $totalFee 收款總費用 單位元
           * @param string $outTradeNo 唯一的訂單號
           * @param string $orderName 訂單名稱
           * @param string $notifyUrl 支付結果通知url 不要有問號
           * @param string $timestamp 支付時間
           * @return string
           */
           public function createJsBizPackage($openid, $totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp)
           {
           $config = array(
           'mch_id' => $this->mchid,
           'appid' => $this->appid,
           'key' => $this->apiKey,
           );
           $orderName = iconv('GBK','UTF-8',$orderName);
           $unified = array(
           'appid' => $config['appid'],
           'attach' => 'pay', //商家數據包,原樣返回,如果填寫中文,請注意轉換為utf-8
           'body' => $orderName,
           'mch_id' => $config['mch_id'],
           'nonce_str' => self::createNonceStr(),
           'notify_url' => $notifyUrl,
           'openid' => $openid, //rade_type=JSAPI,此參數必傳
           'out_trade_no' => $outTradeNo,
           'spbill_create_ip' => '127.0.0.1',
           'total_fee' => intval($totalFee * 100), //單位 轉為分
           'trade_type' => 'JSAPI',
           );
           $unified['sign'] = self::getSign($unified, $config['key']);
           $responseXml = self::curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', self::arrayToXml($unified));
           $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
           if ($unifiedOrder === false) {
           die('parse xml error');
           }
           if ($unifiedOrder->return_code != 'SUCCESS') {
           die($unifiedOrder->return_msg);
           }
           if ($unifiedOrder->result_code != 'SUCCESS') {
           die($unifiedOrder->err_code);
           }
           $arr = array(
           "appId" => $config['appid'],
           "timeStamp" => "$timestamp", //這里是字符串的時間戳,不是int,所以需加引號
           "nonceStr" => self::createNonceStr(),
           "package" => "prepay_id=" . $unifiedOrder->prepay_id,
           "signType" => 'MD5',
           );
           $arr['paySign'] = self::getSign($arr, $config['key']);
           return $arr;
           }
           public static function curlGet($url = '', $options = array())
           {
           $ch = curl_init($url);
           curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
           curl_setopt($ch, CURLOPT_TIMEOUT, 30);
           if (!empty($options)) {
           curl_setopt_array($ch, $options);
           }
           //https請求 不驗證證書和host
           curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
           curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
           $data = curl_exec($ch);
           curl_close($ch);
           return $data;
           }
           public static function curlPost($url = '', $postData = '', $options = array())
           {
           if (is_array($postData)) {
           $postData = http_build_query($postData);
           }
           $ch = curl_init();
           curl_setopt($ch, CURLOPT_URL, $url);
           curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
           curl_setopt($ch, CURLOPT_POST, 1);
           curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
           curl_setopt($ch, CURLOPT_TIMEOUT, 30); //設置cURL允許執行的最長秒數
           if (!empty($options)) {
           curl_setopt_array($ch, $options);
           }
           //https請求 不驗證證書和host
           curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
           curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
           $data = curl_exec($ch);
           curl_close($ch);
           return $data;
           }
           public static function createNonceStr($length = 16)
           {
           $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
           $str = '';
           for ($i = 0; $i < $length; $i++) {
           $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
           }
           return $str;
           }
           public static function arrayToXml($arr)
           {
           $xml = "<xml>";
           foreach ($arr as $key => $val) {
           if (is_numeric($val)) {
           $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
           } else
           $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
           }
           $xml .= "</xml>";
           file_put_contents('1.txt',$xml);
           return $xml;
           }
           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;
           }
          }
          ?>
          


          以上是文章全部內容,有學習與經驗交流的可關注小編。有技術問題可以一起探討與交流,如果你是PHP的,小編也可以拉你進微信技術群,交流與學習!


          上一篇:Javascript之選項卡
          下一篇:html詳解之input
          主站蜘蛛池模板: 99在线精品一区二区三区| 亚洲日韩国产一区二区三区| 国产福利电影一区二区三区久久久久成人精品综合 | 2021国产精品一区二区在线| 精品人妻中文av一区二区三区| 精品少妇ay一区二区三区| 国产一区中文字幕在线观看 | 中文无码精品一区二区三区| 亚洲日本一区二区| 亚洲性色精品一区二区在线| 国产成人精品一区二三区在线观看| 国产suv精品一区二区33| 福利一区二区三区视频在线观看| 色偷偷av一区二区三区| 成人一区二区免费视频| 久久精品无码一区二区三区免费 | 国模精品视频一区二区三区| 国产午夜精品一区二区| 国产精品一区二区无线| 日韩免费视频一区| 九九无码人妻一区二区三区| 人妻天天爽夜夜爽一区二区| 夜夜添无码试看一区二区三区| 国产一区二区三区视频在线观看 | 国产丝袜无码一区二区三区视频| 国产精品美女一区二区三区 | 精品少妇一区二区三区在线| 免费一区二区视频| AV无码精品一区二区三区宅噜噜| 午夜视频久久久久一区 | 91久久精品国产免费一区 | 日韩在线不卡免费视频一区| 亚洲一区二区三区夜色| 亚欧在线精品免费观看一区 | 精品视频一区二区三区在线观看 | 岛国无码av不卡一区二区| 欧洲精品无码一区二区三区在线播放| 国产一区二区三区在线影院| 中文字幕在线一区二区在线| 无码喷水一区二区浪潮AV| 色噜噜AV亚洲色一区二区|