如何應(yīng)對微信支付這一步一個(gè)坑的APP支付
引言
秋高氣爽,天氣轉(zhuǎn)涼,正是學(xué)習(xí)工作做的好時(shí)候。(~ ̄▽ ̄)~~(~ ̄▽ ̄)~
我是個(gè)phper最近在寫微信支付(APP支付),微信給的官方文檔并不是很詳細(xì)也沒有dome之類的代碼啥的(對于新手來說比較麻煩),本人是新手以前也沒寫過支付,踩了好多坑,所以想寫篇文章給沒寫過支付的新手幾個(gè)建議。
準(zhǔn)備工作
這首先呢你得注冊個(gè)開放平臺以及商戶平臺的賬號吧,注冊完成后呢你會收到一封微信里郵件里面有你的商戶號等信息,注冊這倆賬號完你會擁有商戶號,appid,appkey等需要的東西。
開發(fā)流程
準(zhǔn)備完成后我們來看一下支付的大體流程
商戶APP應(yīng)用與微信支付主要的交互說明:
- 用戶在商戶APP應(yīng)用(移動端)中選擇商品提交訂單,支付方式選擇微信支付。
- 商戶APP應(yīng)用(后臺)收到用戶支付訂單,調(diào)用微信支付中的統(tǒng)一下單接口。
- 商戶APP應(yīng)用(后臺)統(tǒng)一下單接口調(diào)用成功后,返回的數(shù)據(jù)中有我們需要的prepay_id,按照簽名規(guī)范重新生成一個(gè)簽名,然后把這個(gè)重新生成的簽名及app需要的數(shù)據(jù)返回給商戶APP應(yīng)用(移動端)。
- 商戶APP應(yīng)用(移動端)收到商戶APP應(yīng)用(后臺)的數(shù)據(jù)調(diào)起微信支付,用戶進(jìn)行支付
- 商戶APP應(yīng)用(后臺)的回調(diào)接口會收到微信發(fā)來的支付結(jié)果通知
- 商戶APP應(yīng)用(后臺)查詢支付結(jié)果通知
附:1,4是移動端所要做的事情,2,3,5是我們PHP服務(wù)端后臺要做的6也是,但我沒做,這個(gè)根據(jù)情況而定如果需要的話就做。
開始干活
步驟1.由移動端完成
步驟2. 調(diào)用同一下單接口:
先要做的是流程中的第二步,調(diào)用同一下單接口。官方文檔里說了請求的地址與參數(shù),其中有一些是必填參數(shù),有
- appid
應(yīng)用ID 固定值,你申請賬號時(shí)就給你了 - mch_id
商戶號 固定值,你申請賬號時(shí)就給你了 - nonce_str
隨機(jī)字符串 這個(gè)是自己寫的要求不能長于32位,參見官方給的[標(biāo)準(zhǔn)][8] - sign
簽名 我們把這個(gè)簽名叫做第一次簽名,注意這個(gè)是個(gè)坑,得自己寫了,官方只給了如何寫的[標(biāo)準(zhǔn)][9]沒有代碼,這個(gè)就比較蛋疼了。好多人掉進(jìn)這個(gè)坑里,寫的簽名函數(shù)不對,老是出錯。但不用擔(dān)心我在文章的最后會貼出代碼里面有簽名函數(shù)直接調(diào)用就可以了。(注意看我寫的函數(shù)使用規(guī)則) - body
商品描述 固定值 商品描述交易字段格式根據(jù)不同的應(yīng)用場景按照以下格式:APP——需傳入應(yīng)用市場上的APP名字-實(shí)際商品名稱,天天愛消除-游戲充值。 - out_trade_no
商戶訂單號 我們自己定義的訂單號,32個(gè)字符內(nèi)、可包含字母。 - total_fee
總金額 這個(gè)就是你要支付的錢數(shù)了,由前端返回。注意一下這里的貨幣單位是分! - spbill_create_ip
終端IP 這個(gè)用戶的IP地址,寫個(gè)取IP地址的函數(shù)一調(diào)用就行 - notify_url
通知地址 這又是一個(gè)坑,好多人不理解是干嘛的,這是接收微信支付異步通知回調(diào)地址用的,通知url必須為直接可訪問的url,不能攜帶參數(shù)! 也可以這樣理解,這個(gè)是給微信支付的接口,微信來調(diào)用的接口,微信調(diào)這接口干嘛用呢?就是告訴你用戶付款成功啦或者用戶付款失敗了,然后你就可以在這個(gè)接口里通過微信給你返回的信息來做邏輯處理了。 - trade_type
固定值 寫 “APP” 因?yàn)樵蹖懙氖茿PP支付嘛,所以就填A(yù)PP。
好了就是這些必選參數(shù)了,剩下就可以自己選擇是否要用的參數(shù)了根據(jù)自己情況而定。
參數(shù)選完了就要發(fā)送參數(shù)了唄,如何發(fā)呢?
我們來調(diào)用wechatAppPay類中的unifiedOrder()函數(shù)。
啊哈啥!!!!!!??????
(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?(⊙o⊙)?
wechatAppPay類???unifiedOrder()函數(shù)???
對就這這倆東西,不要驚訝,不要著急看最后有代碼,有這個(gè)類,有代碼的O(∩_∩)O哈哈~,
你只需在你的項(xiàng)目中加載這個(gè)類就可以調(diào)用這個(gè)方法了!不要崇拜我( ╯▽╰)(因?yàn)檫@個(gè)類不是我寫的我也忘了從哪找的了,我從百度搜的然后整理的做了些改動╮(╯▽╰)╭ -_-|||-_-|||-_-!好吧好吧好吧沒做改動,只是加了點(diǎn)注釋而已,感謝寫這個(gè)類的大神謝謝O(∩_∩)O謝謝O(∩_∩)O謝謝)
好了抽完瘋了,開是干正事!
我們先來new下wechatAppPay類
- $wxappid = 'wx0000000000000';//應(yīng)用ID 字符串
- $mch_id = '1000000000';//商戶號 字符串
- $notify_url = 'http://www.xxx.com/xxxx.php/xxxx/xxxx';//接收微信支付異步通知回調(diào)地址 字符串
- $wxkey = '00000000000000000000000';//這個(gè)是在商戶中心設(shè)置的那個(gè)值用來生成簽名時(shí)保證安全的 字符串
- $this->wechatAppPay = new wechatAppPay($wxappid, $mch_id, $notify_url, $wxkey);
調(diào)用wechatAppPay類中的unifiedOrder()函數(shù)。unifiedOrder()需要的參數(shù)是個(gè)數(shù)組我們定義為$params
- $params = array();
- $params['body'] = 'APP-在線支付'; //必填項(xiàng) 商品描述
- $params['out_trade_no'] = time()."$member"; //必填項(xiàng) 自定義的訂單號
- $params['total_fee'] = ($money*100); //必填項(xiàng) 訂單金額 單位為分所以要*100
- $params['trade_type'] = 'APP'; //必填項(xiàng) 交易類型固定寫 APP
- $params['根據(jù)自己情況定的值'] = "根據(jù)自己情況定的值" //非必填項(xiàng) 根據(jù)自己情況定的值 這個(gè)可有好多個(gè)可以參看開發(fā)文檔中的參數(shù)
- $result = $this->wechatAppPay->unifiedOrder( $params );
注:如果你加了$params['根據(jù)自己情況定的值'] wechatAppPay類里要做相應(yīng)的改動,文章的最后有代碼,你一看代碼就明白了
現(xiàn)在$result就是我們調(diào)用統(tǒng)一下單接口返回的數(shù)據(jù)了,這個(gè)$resutl通過unifiedOrder()函數(shù)的處理已經(jīng)把xml格式變成數(shù)組了。$result 里有return_code,return_msg,appid,mch_id,nonce_str,sign,result_code,prepay_id,trade_type。這里面就用一個(gè)prepay_id(預(yù)支付交易會話ID),其他都不重要了
步驟2完畢
步驟3. 把數(shù)據(jù)返回給商戶APP應(yīng)用(移動端)調(diào)起支付接口
現(xiàn)在我們要把調(diào)用統(tǒng)一下單接口返回的數(shù)據(jù)$resutl里的幾個(gè)值返回給移動端那幾個(gè)值呢?這幾個(gè):
- appid
應(yīng)用ID 這個(gè)是固定的 可以自己寫也可以從$resutl里拿 可以讓移動端寫死 就不用每次返回了 - partnerid
商戶號 這個(gè)也是固定的 可以自己寫也可以從$resutl里拿 可以讓移動端寫死 就不用每次返回了 - prepayid
預(yù)支付交易會話ID 這個(gè)很重要必須返回給移動端 是必須從$resutl里拿的 - package
擴(kuò)展字段 可以自己寫也可以從$resutl里拿 暫填寫固定值"Sign=WXPay" 可以讓移動端寫死 就不用每次返回了 - noncestr
隨機(jī)字符串 這個(gè)可以自己寫也可以從$resutl里拿 - timestamp
時(shí)間戳 自己生成 標(biāo)準(zhǔn)北京時(shí)間,時(shí)區(qū)為東八區(qū)注意:部分系統(tǒng)取到的值為毫秒級,需要轉(zhuǎn)換成秒(10位數(shù)字),這里有個(gè)坑,ISO端接收的時(shí)候好像得強(qiáng)行轉(zhuǎn)化一下,因?yàn)榉祷氐氖亲址皇菙?shù)字,還有什么幾位的數(shù)字之類的,我也不太懂,反正就是寫的時(shí)候提醒下iOS工程師就行。安卓不清楚。 - sign
簽名 又來一個(gè)坑,我們把這個(gè)簽名叫做二次簽名,但是這個(gè)簽名不是從$resutl里拿的,而是自己寫的,如何寫呢,又有坑!因?yàn)閰⑴c簽名的參數(shù)值是那幾個(gè)不清楚,參數(shù)名寫不對!不怕我有代碼!貼給你看!需要參與簽名的值有六個(gè)!
現(xiàn)在就可以把重新生成的sign($sign_two)以及其他參數(shù)返回給移動端了,一共返回七個(gè)值,有三個(gè)之可以讓前端寫死(appid,partnerid,package),其余四個(gè)必須由服務(wù)器返回給移動端。
- $sign_array = array();
- $sign_array['appid'] = $wx_result['appid']; //注意 $sign_array['appid'] 里的參數(shù)名必須是appid
- $sign_array['partnerid'] = $wx_result['mch_id']; //注意 $sign_array['partnerid'] 里的參數(shù)名必須是partnerid
- $sign_array['prepayid'] = $wx_result['prepay_id'];//注意 $sign_array['prepayid'] 里的參數(shù)名必須是prepayid
- $sign_array['package'] = 'Sign=WXPay'; //注意 $sign_array['package'] 里的參數(shù)名必須是package
- $sign_array['noncestr'] = $wx_result['nonce_str'];//注意 $sign_array['noncestr'] 里的參數(shù)名必須是noncestr
- $sign_array['timestamp'] = time(); //注意 $sign_array['timestamp'] 里的參數(shù)名必須是timestamp
- $sign_two = $this->wechatAppPay->MakeSign($sign_array);//調(diào)用wechatAppPay類里的MakeSign()函數(shù)生成sign
步驟3完畢
步驟4.由移動端完成
步驟5. 回調(diào)接口 支付結(jié)果通用通知
還記得步驟2中我們設(shè)置的$notify_url嗎,對現(xiàn)在就要對這個(gè)微信返回到這個(gè)接口的數(shù)據(jù)進(jìn)行一系列的邏輯處理了官方是這樣寫的:
支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,商戶需要接收處理,并返回應(yīng)答。
對后臺通知交互時(shí),如果微信收到商戶的應(yīng)答不是成功或超時(shí),微信認(rèn)為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒)
注意:同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。
推薦的做法是,當(dāng)收到通知進(jìn)行處理時(shí),首先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),判斷該通知是否已經(jīng)處理過,如果沒有處理過再進(jìn)行處理,如果處理過直接返回結(jié)果成功。在對業(yè)務(wù)數(shù)據(jù)進(jìn)行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進(jìn)行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。
特別提醒:商戶系統(tǒng)對于支付結(jié)果通知的內(nèi)容一定要做簽名驗(yàn)證,防止數(shù)據(jù)泄漏導(dǎo)致出現(xiàn)“假通知”,造成資金損失。
首先來接收數(shù)據(jù)
- $data = $this->wechatAppPay->getNotifyData();//獲取數(shù)據(jù) 用wechatAppPay類里的getNotifyData()方法,這里數(shù)據(jù)也被getNotifyData()由xml轉(zhuǎn)化成了數(shù)組。
然后官方說要采用數(shù)據(jù)鎖進(jìn)行并發(fā)控制,這個(gè)我不懂所以沒寫(如果你懂你會的話請給我留言私信告訴我,在這謝謝了),對數(shù)據(jù)進(jìn)行狀態(tài)檢查這個(gè)寫了,如何寫的呢?很簡單微信返回的值有好多其中就可以判斷result_code(業(yè)務(wù)結(jié)果)和return_code(返回狀態(tài)碼)是否為SUCCESS就可以了代碼就不寫了。
然后驗(yàn)簽,這個(gè)很重要因?yàn)檫@是保證數(shù)據(jù)沒有被第三方人為篡改的標(biāo)準(zhǔn)!
如何驗(yàn)簽?zāi)?
把返回的數(shù)據(jù)$data里除去sign剩下的值都參與重新簽名我們把這次簽名叫做驗(yàn)簽簽名,驗(yàn)簽簽名生成后再與$data里的sign對比,如果相同驗(yàn)簽通過,否則不通過。這次簽名的參數(shù)名與二次簽名時(shí)的參數(shù)名不同,$data數(shù)組里叫什么參數(shù)名就驗(yàn)簽時(shí)叫什么參數(shù)名。聽亂了吧?(~ ̄▽ ̄)~(~ ̄▽ ̄)~沒關(guān)系請看代碼
- //假如$data里有如下參數(shù)
- $w_sign = array(); //參加驗(yàn)簽簽名的參數(shù)數(shù)組
- $w_sign['appid'] = $data['appid'];
- $w_sign['bank_type'] = $data['bank_type'];
- $w_sign['cash_fee'] = $data['cash_fee'];
- $w_sign['fee_type'] = $data['fee_type'];
- $w_sign['is_subscribe'] = $data['is_subscribe'];
- $w_sign['mch_id'] = $data['mch_id'];
- $w_sign['nonce_str'] = $data['nonce_str'];
- $w_sign['openid'] = $data['openid'];
- $w_sign['out_trade_no'] = $data['out_trade_no'];
- $w_sign['result_code'] = $data['result_code'];
- $w_sign['return_code'] = $data['return_code'];
- $w_sign['time_end'] = $data['time_end'];
- $w_sign['total_fee'] = $data['total_fee'];
- $w_sign['trade_type'] = $data['trade_type'];
- $w_sign['transaction_id'] = $data['transaction_id'];
- $verify_sign = $this->wechatAppPay->MakeSign($w_sign);//生成驗(yàn)簽簽名
好了現(xiàn)在假設(shè)你的驗(yàn)簽已經(jīng)通過了接下里就是你自己的邏輯處理了
///////////////////////////////////////////////////////
商戶APP應(yīng)用(后臺)處理邏輯代碼
//////////////////////////////////////////////////////
自己的邏輯處理已經(jīng)處理完之后,還得告訴微信一下,別再一直發(fā)結(jié)果通用通知啦,我已經(jīng)收到通知并處理完啦!
- $this->wechatAppPay->replyNotify();//商戶處理后同步返回給微信參數(shù)
步驟5結(jié)束步驟6根據(jù)自己情況而定
結(jié)束語
至此微信支付處理完成~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦
寫的有不對的方還請大家多多指導(dǎo)指教!!!給我留言!!b( ̄▽ ̄)db( ̄▽ ̄)db( ̄▽ ̄)d
還有感謝在我寫微信支付地時(shí)候 那些被我問煩了的大神們! !謝謝啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦~(≧▽≦)/~啦啦啦O(∩_∩)O哈哈~O(∩_∩)O哈哈~O(∩_∩)O哈哈~<( ̄︶ ̄)><( ̄︶ ̄)><( ̄︶ ̄)>
代碼
wechatAppPay類
- class wechatAppPay
- {
- //接口API URL前綴
- const API_URL_PREFIX = 'https://api.mch.weixin.qq.com';
- //下單地址URL
- const UNIFIEDORDER_URL = "/pay/unifiedorder";
- //查詢訂單URL
- const ORDERQUERY_URL = "/pay/orderquery";
- //關(guān)閉訂單URL
- const CLOSEORDER_URL = "/pay/closeorder";
- //公眾賬號ID
- private $wxappid;
- //商戶號
- private $mch_id;
- //隨機(jī)字符串
- private $nonce_str;
- //簽名
- private $sign;
- //商品描述
- private $body;
- //商戶訂單號
- private $out_trade_no;
- //支付總金額
- private $total_fee;
- //終端IP
- private $spbill_create_ip;
- //支付結(jié)果回調(diào)通知地址
- private $notify_url;
- //交易類型
- private $trade_type;
- //支付密鑰
- private $key;
- //證書路徑
- private $SSLCERT_PATH;
- private $SSLKEY_PATH;
- //所有參數(shù)
- private $params = array();
- public function __construct($wxappid, $mch_id, $notify_url, $key)
- {
- $this->appid = $wxappid;
- $this->mch_id = $mch_id;
- $this->notify_url = $notify_url;
- $this->key = $key;
- }
- /**
- * 下單方法
- * @param $params 下單參數(shù)
- */
- public function unifiedOrder( $params ){
- $this->body = $params['body'];
- $this->out_trade_no = $params['out_trade_no'];
- $this->total_fee = $params['total_fee'];
- $this->trade_type = $params['trade_type'];
- $this->nonce_str = $this->genRandomString();
- $this->spbill_create_ip = $_SERVER['REMOTE_ADDR'];
- $this->params['appid'] = $this->appid;
- $this->params['mch_id'] = $this->mch_id;
- $this->params['nonce_str'] = $this->nonce_str;
- $this->params['body'] = $this->body;
- $this->params['out_trade_no'] = $this->out_trade_no;
- $this->params['total_fee'] = $this->total_fee;
- $this->params['spbill_create_ip'] = $this->spbill_create_ip;
- $this->params['notify_url'] = $this->notify_url;
- $this->params['trade_type'] = $this->trade_type;
- //獲取簽名數(shù)據(jù)
- $this->sign = $this->MakeSign( $this->params );
- $this->params['sign'] = $this->sign;
- $xml = $this->data_to_xml($this->params);
- $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::UNIFIEDORDER_URL);
- if( !$response ){
- return false;
- }
- $result = $this->xml_to_data( $response );
- if( !empty($result['result_code']) && !empty($result['err_code']) ){
- $result['err_msg'] = $this->error_code( $result['err_code'] );
- }
- return $result;
- }
- /**
- * 查詢訂單信息
- * @param $out_trade_no 訂單號
- * @return array
- */
- public function orderQuery( $out_trade_no ){
- $this->params['appid'] = $this->appid;
- $this->params['mch_id'] = $this->mch_id;
- $this->params['nonce_str'] = $this->genRandomString();
- $this->params['out_trade_no'] = $out_trade_no;
- //獲取簽名數(shù)據(jù)
- $this->sign = $this->MakeSign( $this->params );
- $this->params['sign'] = $this->sign;
- $xml = $this->data_to_xml($this->params);
- $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::ORDERQUERY_URL);
- if( !$response ){
- return false;
- }
- $result = $this->xml_to_data( $response );
- if( !empty($result['result_code']) && !empty($result['err_code']) ){
- $result['err_msg'] = $this->error_code( $result['err_code'] );
- }
- return $result;
- }
- /**
- * 關(guān)閉訂單
- * @param $out_trade_no 訂單號
- * @return array
- */
- public function closeOrder( $out_trade_no ){
- $this->params['appid'] = $this->appid;
- $this->params['mch_id'] = $this->mch_id;
- $this->params['nonce_str'] = $this->genRandomString();
- $this->params['out_trade_no'] = $out_trade_no;
- //獲取簽名數(shù)據(jù)
- $this->sign = $this->MakeSign( $this->params );
- $this->params['sign'] = $this->sign;
- $xml = $this->data_to_xml($this->params);
- $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::CLOSEORDER_URL);
- if( !$response ){
- return false;
- }
- $result = $this->xml_to_data( $response );
- return $result;
- }
- /**
- *
- * 獲取支付結(jié)果通知數(shù)據(jù)
- * return array
- */
- public function getNotifyData(){
- //獲取通知的數(shù)據(jù)
- $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
- $data = array();
- if( empty($xml) ){
- return false;
- }
- $data = $this->xml_to_data( $xml );
- if( !empty($data['return_code']) ){
- if( $data['return_code'] == 'FAIL' ){
- return false;
- }
- }
- return $data;
- }
- /**
- * 接收通知成功后應(yīng)答輸出XML數(shù)據(jù)
- * @param string $xml
- */
- public function replyNotify(){
- $data['return_code'] = 'SUCCESS';
- $data['return_msg'] = 'OK';
- $xml = $this->data_to_xml( $data );
- echo $xml;
- die();
- }
- /**
- * 生成APP端支付參數(shù)
- * @param $prepayid 預(yù)支付id
- */
- public function getAppPayParams( $prepayid ){
- $data['appid'] = $this->appid;
- $data['partnerid'] = $this->mch_id;
- $data['prepayid'] = $prepayid;
- $data['package'] = 'Sign=WXPay';
- $data['noncestr'] = $this->genRandomString();
- $data['timestamp'] = time();
- $data['sign'] = $this->MakeSign( $data );
- return $data;
- }
- /**
- * 生成簽名
- * @return 簽名
- */
- public function MakeSign( $params ){
- //簽名步驟一:按字典序排序數(shù)組參數(shù)
- ksort($params);
- $string = $this->ToUrlParams($params);
- //簽名步驟二:在string后加入KEY
- $string = $string . "&key=".$this->key;
- //簽名步驟三:MD5加密
- $string = md5($string);
- //簽名步驟四:所有字符轉(zhuǎn)為大寫
- $result = strtoupper($string);
- return $result;
- }
- /**
- * 將參數(shù)拼接為url: key=value&key=value
- * @param $params
- * @return string
- */
- public function ToUrlParams( $params ){
- $string = '';
- if( !empty($params) ){
- $array = array();
- foreach( $params as $key => $value ){
- $array[] = $key.'='.$value;
- }
- $string = implode("&",$array);
- }
- return $string;
- }
- /**
- * 輸出xml字符
- * @param $params 參數(shù)名稱
- * return string 返回組裝的xml
- **/
- public function data_to_xml( $params ){
- if(!is_array($params)|| count($params) <= 0)
- {
- return false;
- }
- $xml = "<xml>";
- foreach ($params as $key=>$val)
- {
- if (is_numeric($val)){
- $xml.="<".$key.">".$val."</".$key.">";
- }else{
- $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
- }
- }
- $xml.="</xml>";
- return $xml;
- }
- /**
- * 將xml轉(zhuǎn)為array
- * @param string $xml
- * return array
- */
- public function xml_to_data($xml){
- if(!$xml){
- return false;
- }
- //將XML轉(zhuǎn)為array
- //禁止引用外部xml實(shí)體
- libxml_disable_entity_loader(true);
- $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
- return $data;
- }
- /**
- * 獲取毫秒級別的時(shí)間戳
- */
- private static function getMillisecond(){
- //獲取毫秒的時(shí)間戳
- $time = explode ( " ", microtime () );
- $time = $time[1] . ($time[0] * 1000);
- $time2 = explode( ".", $time );
- $time = $time2[0];
- return $time;
- }
- /**
- * 產(chǎn)生一個(gè)指定長度的隨機(jī)字符串,并返回給用戶
- * @param type $len 產(chǎn)生字符串的長度
- * @return string 隨機(jī)字符串
- */
- private function genRandomString($len = 32) {
- $chars = array(
- "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
- "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
- "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
- "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
- "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
- "3", "4", "5", "6", "7", "8", "9"
- );
- $charsLen = count($chars) - 1;
- // 將數(shù)組打亂
- shuffle($chars);
- $output = "";
- for ($i = 0; $i < $len; $i++) {
- $output .= $chars[mt_rand(0, $charsLen)];
- }
- return $output;
- }
- /**
- * 以post方式提交xml到對應(yīng)的接口url
- *
- * @param string $xml 需要post的xml數(shù)據(jù)
- * @param string $url url
- * @param bool $useCert 是否需要證書,默認(rèn)不需要
- * @param int $second url執(zhí)行超時(shí)時(shí)間,默認(rèn)30s
- * @throws WxPayException
- */
- private function postXmlCurl($xml, $url, $useCert = false, $second = 30){
- $ch = curl_init();
- //設(shè)置超時(shí)
- curl_setopt($ch, CURLOPT_TIMEOUT, $second);
- curl_setopt($ch,CURLOPT_URL, $url);
- curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
- curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);
- //設(shè)置header
- curl_setopt($ch, CURLOPT_HEADER, FALSE);
- //要求結(jié)果為字符串且輸出到屏幕上
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
- if($useCert == true){
- //設(shè)置證書
- //使用證書:cert 與 key 分別屬于兩個(gè).pem文件
- curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
- //curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
- curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
- //curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
- }
- //post提交方式
- curl_setopt($ch, CURLOPT_POST, TRUE);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
- //運(yùn)行curl
- $data = curl_exec($ch);
- //返回結(jié)果
- if($data){
- curl_close($ch);
- return $data;
- } else {
- $error = curl_errno($ch);
- curl_close($ch);
- return false;
- }
- }
- /**
- * 錯誤代碼
- * @param $code 服務(wù)器輸出的錯誤代碼
- * return string
- */
- public function error_code( $code ){
- $errList = array(
- 'NOAUTH' => '商戶未開通此接口權(quán)限',
- 'NOTENOUGH' => '用戶帳號余額不足',
- 'ORDERNOTEXIST' => '訂單號不存在',
- 'ORDERPAID' => '商戶訂單已支付,無需重復(fù)操作',
- 'ORDERCLOSED' => '當(dāng)前訂單已關(guān)閉,無法支付',
- 'SYSTEMERROR' => '系統(tǒng)錯誤!系統(tǒng)超時(shí)',
- 'APPID_NOT_EXIST' => '參數(shù)中缺少APPID',
- 'MCHID_NOT_EXIST' => '參數(shù)中缺少M(fèi)CHID',
- 'APPID_MCHID_NOT_MATCH' => 'appid和mch_id不匹配',
- 'LACK_PARAMS' => '缺少必要的請求參數(shù)',
- 'OUT_TRADE_NO_USED' => '同一筆交易不能多次提交',
- 'SIGNERROR' => '參數(shù)簽名結(jié)果不正確',
- 'XML_FORMAT_ERROR' => 'XML格式錯誤',
- 'REQUIRE_POST_METHOD' => '未使用post傳遞參數(shù) ',
- 'POST_DATA_EMPTY' => 'post數(shù)據(jù)不能為空',
- 'NOT_UTF8' => '未使用指定編碼格式',
- );
- if( array_key_exists( $code , $errList ) ){
- return $errList[$code];
- }
- }
- }