關于微信支付
1. 生活中的微信支付
??目前我們日常生活中接觸得比較多的線上電子支付方式主要有兩種,一種是支付寶,另一種就是微信支付了,微信支付是集成在微信客戶端的支付功能,所謂微信客戶端,主要是微信的移動應用,例如安卓(Android)微信APP、IOS微信APP,用戶可以通過手機的微信APP完成快速的支付流程,當然,其他的移動應用也可以接入微信支付的接口來達到完成微信支付的所有功能。
2. 微信支付方式
??主要的支付方式有:公眾號支付或稱網(wǎng)頁支付,掃描二維碼支付,APP支付,除此之外還有刷卡支付等,還有一點就是,微信支付以綁定銀行卡的快捷支付為基礎的。
3. 為什么要掌握
??對于我們開發(fā)者而言,熟練地掌握微信支付的接口功能是必不可少的,因為以后我的要做的互聯(lián)網(wǎng)產品中,可能是網(wǎng)頁,亦可能是移動應用APP,都可能會集成微信支付,那么接下來讓我們來學習如果使用PHP版的微信支付接口吧。
4. 關于本節(jié)課
?? 本門課程主要針對已經開通了微信商戶號且開通微信公眾平臺微信支付功能系統(tǒng)的學員,那我沒有開通這些東西怎么學習?如果沒有開通,也沒關系,可以直接使用本課程的代碼,因為本節(jié)課程使用的是所有支付配置信息使用的都是測試賬號提供的,在你學習了調起支付后,如果使用支付功能,那么會產生每次一分錢的費用,支付到微信PHP開發(fā)包代碼中提供的測試商戶號中,測試賬號歸屬于微信系統(tǒng)。
下載SDK
1. 復制下面的鏈接在瀏覽器中打開
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
2. 在所打開的頁面中選擇PHP版本的SDK下載
??目前的壓縮包名為:WxpayAPI_php_v3,下載完畢后,解壓到桌面,里面一共含有5個文件夾,和一個 index.php 文件
cert、doc、example、lib、logs、index.php
為了方便大家學習,我已經在右邊的文件管理處上傳了對應的一份SDK,大家可以參考學習,不過最好還是在自己的電腦下載一份,首先大家先在右邊的編輯框中按照順序,輸入命令ls,然后看下輸出的是不是下圖,如果輸出的是wxPay,那么就輸入命令cd wxPay

然后輸入命令:sudo php -S 0.0.0.0:80,看輸出的是不是下圖的內容,是的話,那么就可以往下面看了,如果不是的話,再重復上面的步驟,刷新頁面即可。

上面的操作完成后,大家點擊右邊的訪問測試就可以進入到支付樣例主頁面了,如下圖所示:

?頁面顯示出了三種支付方式,第一種jsapi是網(wǎng)頁支付,第二種刷卡支付,第三種掃碼支付,這時候如果你點擊jsapi支付的話,網(wǎng)頁會提示請在微信客戶端打開鏈接,為什么會這樣呢?這個我會在后面的課程說到,除此之外,掃碼支付如果你用微信的掃描二維碼掃描了的話,是真的會進入到支付頁面的哦。
文件說明
1. index.php
??這個是官方提供的所有支付功能集成化的入口,不過需要注意的是:如果使用到我們自己的項目中,記得修改對應的鏈接。

2. cert-證書存放路徑
??證書是商家在使用微信支付功能的時候,進行身份驗證用到的,起到一種安全的作用,但是,目前微信支付僅僅只在使用退款接口或者撤銷訂單的時候需要可能會用到證書,為什么是可能呢?因為在接口函數(shù)中,我們可以選擇是否使用證書,不使用也能使用退款或撤銷訂單接口,在我們下載的SDK中,文件夾cert里面的證書對應的是微信的測試賬號的,如果,我們擁有自己的微信商戶平臺的賬號,那么我們就可以登錄商戶平臺,來下載我們自己的證書放到這個目錄。
3. doc-官方文檔目錄
??里面含有一些的SDK使用指南信息
4. example-官方接口例子目錄
??在為完全掌握微信支付接口功能實現(xiàn)之前,我們主要依賴官方的例子代碼來進行學習,進而進行修改,含有:
文件夾-phpqrode存放了二維碼功能相關文件
jsapi.php"網(wǎng)頁調起支付頁面;"
notify.php"網(wǎng)頁支付后的回調的頁面;"
native.php"付款二維碼信息組裝頁面;"
qrcode.php"生成二維碼的頁面"
native_notify.php"掃描所生成二維碼進入的頁面;"
notify.php"網(wǎng)頁支付后的回調頁面;"
orderquery.php"訂單查詢頁面;"
download.php"查退款單頁面;"
refund.php"退款的頁面;"
refundquery.php"退款單查詢的頁面;"
WxPay.JsApiPay.php"網(wǎng)頁支付核心類;"
WxPay.NativePay.php和WxPay.MicroPay.php"是刷卡支付類"
5. lib-核心庫
前兩個很重要!
WxPay.Api.php"接口訪問類,包含所有微信支付API列表的封裝"
WxPay.Config.php"配置信息所在文件"
WxPay.Data.php"簽名相關類,含簽名生成"
WxPay.Exception.php"異常類"
WxPay.Notify.php"回調函數(shù)的父類"
6. logs-這個主要用來存放在支付過程中生成的各種日志文件
接下來我們進行文件配置
lib文件夾下的WxPay.Config.php
??對應文件管理中l(wèi)ib文件夾下的WxPay.Config.php文件
1,公眾號與商戶平臺
??首先,我們簡單了解一下微信公眾號和微信商戶平臺在微信支付中扮演的角色,公眾號是我們在網(wǎng)頁要進行支付的場所,而用戶支付了的錢,我們怎樣對它進行操作呢,這就需要商戶平臺了,我們在商戶平臺里能夠進行支付賬單查詢、款數(shù)提現(xiàn)等操作,現(xiàn)在我們采用軟件打開lib文件下的WxPay.Config.php,可以采用 PhpStorm,sublime,記事本,或者參照右邊的文件管理,由于cert文件夾和doc文件夾里面的內容目前不支持上傳,所以右邊文件管理處,沒有上傳這2個文件夾里面的文件。
2,AppId和AppSecret
??微信公眾號的AppId和公眾號秘鑰,AppId是用來唯一標識公眾號用戶,AppSecret可以理解為密碼,如果沒有公眾號,那么我們就使用微信的測試AppId,如果我們有的話,那么我們可以先登錄微信公眾,在這里,還要求我們的公眾號必須已經開通微信支付的接口權限,否則我們的AppId是不具備支付權限的。然后在左邊的菜單欄滑到最低,找到并點擊開發(fā)->基本配置->找到AppId 和 AppSecret

constAPPID='wx426b3015555a46be';//這個是微信提供的測試AppId,我們學習用它足以
constAPPSECRET='01c6d59a3f9024db6336662ac95c8e74';//也是微信提供的測試AppSecret
lib文件夾下的WxPay.Config.php
1,商戶號MCHID
??商戶號MCHID,它用來唯一標識微信商戶用戶,它在我們注冊成功成為商戶的時候,官方會發(fā)來一封開戶郵件,在這封郵件中可查看,如果沒有商戶號,我們一樣可以使用微信的測試商戶號,如果有的話,那么我們可以登陸微信商戶平臺。
constMCHID='1225312702';//這個也是微信提供的測試商戶號
2,商戶支付密鑰KEY
??商戶支付密鑰KEY,必須由商戶自己設置,如果我們有自己的商戶,那么可以在商戶平臺的:賬戶設置->API安全中可以設置,沒有的話也可以使用微信提供的來測試和學習。

constKEY='e10adc3949ba59abbe56e057f20f883e';//微信提供的測試支付密鑰
1,證書文件apiclient_cert與apiclient_key
??下面的是支付所用的存儲私鑰文件[apiclient_cert]、存儲公鑰文件[apiclient_key],在前面文件說明這節(jié)課中有說到,證書是商家在使用微信支付功能的時候,進行身份驗證用到的,起到一種安全的作用,但是,目前微信支付僅僅只在使用退款接口或者撤銷訂單的時候需要可能會用到證書,為什么是可能呢?因為在接口函數(shù)中,我們可以選擇是否使用證書,不使用也能使用退款或撤銷訂單接口。
證書下載:證書不是在公眾平臺下載的,是在商戶平臺的賬戶設置->API安全里面下載。下面的是微信提供的測試證書,我們測試和學習可以使用它們。?

constSSLCERT_PATH='../cert/apiclient_cert.pem';//測試提供的私鑰
constSSLKEY_PATH='../cert/apiclient_key.pem';//測試提供的公鑰
2,代理服務器和錯誤上報
??下面的為代理服務器和程序錯誤信息上報等級相關設置,如無特殊情況,默認即可。
constCURL_PROXY_HOST="0.0.0.0";// 代理的IP,不需要代理,請設置為0.0.0.0和0
constCURL_PROXY_PORT=0;//代理的端口,此時不開啟代理(如有需要才設置)
constREPORT_LEVENL=1;//錯誤信息上報等級,0.關閉上報; 1.僅錯誤出錯上報; 2.全量上報
網(wǎng)頁設置
1,OpenId簡介
??OpenId是微信用來唯一標識用戶的一串字符,通俗來說就是微信用戶的id。在前面的課程中我們知道了在微信支付中調起支付需要在代碼設置參數(shù),而且要設置的還不止一個,其中還要設置的就有用戶的OpenId,哪個用戶呢?我們知道每一次的交易,都有一個付款者,那么在這次交易中,我們要設置的OpenId就是他的,上面談到,OpenId是微信唯一標識用戶的,我們不可能隨便就獲取到,因此微信提供了一個專門用來獲取用戶OpenId的接口給我們。
2,獲取OpenId的準備
??如果我們有自己的公眾號,而且公眾號開通了微信支付權限的話,那么為了獲取OpenId,我們需要登錄公眾平臺,然后在左邊的菜單欄滑到最低,找到并點擊開發(fā)->接口權限

再到右邊的功能列表中找到網(wǎng)頁授權獲取用戶基本信息,然后點擊修改字體

然后在輸入框中輸入我們要獲取用戶OpenId的網(wǎng)頁頁面的所在路徑的域名即可,記住,輸入域名就行了,前面不用再添加協(xié)議字符,即http://或https://的字符,還有不要填域名的ip哦

1,支付相關代碼路徑授權
??現(xiàn)在我們已經下載好了微信支付 PHP 的 SDK,默認所有配置信息都是微信提供的,如果我們有自己的公眾號且開通了支付權限,除了上面的獲取OpenId的準備工作之外,我們還要把我們寫好了的微信支付的相關代碼,放到我們自己的服務器里面,然后需要到公眾平臺授權該路徑。
??首先,在公眾號的左邊菜單欄找到微信支付并點擊,然后在右邊點擊開發(fā)配置

這里有兩個目錄,一個是支付授權目錄,另一個是支付測試目錄,支付授權目錄和支付測試目錄的區(qū)別僅僅在于:支付測試目錄中可以設置測試微信號,也就是說,在這個目錄里只有我設置了的賬號才可以支付,而授權目錄是所有人都可以支付的。在測試白名單里設置微信號。

點擊支付授權目錄的修改,我們就可以設置授權目錄了,需要注意的是:發(fā)起支付請求的鏈接地址,都必須在支付授權目錄之下,例如:我們把PHP版的SDK全部放在一個叫做 WeChatPay 的文件夾下,那么我們的授權目錄路徑就是:www.xxxx.com:xx/WeChatPay,為了保證路徑沒錯,拿SDK的文件夾 example 為例,因為發(fā)起支付的文件 jsapi.php 在example里面,所以,我們還可以添加多一個目錄為:www.xxxx.com:xx/WeChatPay/example。

測試支付目錄的修改參照授權目錄,如果你設置了測試授權目錄,記得到測試白名單中添加測試賬號

下面的課程我們講從代碼的角度去學習微信支付
example文件夾下的 WxPay.JsApiPay.php
??對應文件管理中example文件夾下的 WxPay.JsApiPay.php文件
1,靜態(tài)函數(shù) unifiedOrder
??它負責統(tǒng)一下單,除刷卡支付外的支付都是由它進行,如果我們是在網(wǎng)頁中進行支付的話,這個函數(shù)是先行的,所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayUnifiedOrder?類,它主要負責設置一些訂單的信息,例如設置商戶訂單號:
$input->SetOut_trade_no("32個字符內、可包含字母的商戶訂單號");
返回值是一個數(shù)組,包含的狀態(tài)碼和支付信息,但是不能由這個來判斷是否支付成功!官方文檔
??還有一個要注意的是:要設置的訂單信息項,不止一個,下面是一個例子,在下面的課程我會逐個解釋。
$input=newWxPayUnifiedOrder();
$input->SetOut_trade_no("32個字符內、可包含字母的商戶訂單號");
//其他的設置
$order=WxPayApi::unifiedOrder($input);
2,靜態(tài)函數(shù) refund
??它負責退款,所有支付方式的退款都是由它進行,它所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayRefund?類,它主要負責設置一些要退款的訂單的信息*,例如設置要退款的商戶訂單號。
注意:每次退款的商戶訂單號或微信訂單號,都是和下單時候的一樣,它們是配對的。
$input->SetOut_trade_no("對應下單時的訂單號");
返回值是一個數(shù)組,款數(shù)數(shù)目、時間、退款結果等,下面是一個例子。
$input=newWxPayRefund();
$input->SetOut_trade_no("下單時的商戶訂單號");
//其他的設置
$order=WxPayApi::refund($input);
example文件下的WxPay.MicroPay.php
??對應文件管理中example文件夾下的WxPay.MicroPay.php文件
3,刷卡支付 pay
??它負責刷卡支付下訂單,所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayMicroPay?類,它主要負責設置要刷卡支付的訂單信息,例子如下。
$input->SetOut_trade_no("下單時的商戶訂單號");
返回值是一個數(shù)組,含有訂單下單時間、支付的狀態(tài)結果等,下面是一個例子。
$input=newWxPayMicroPay();
$input->SetOut_trade_no("下單時的訂單號");
//其他的設置
$microPay=newMicroPay();
$order=$microPay->pay($input);
1,靜態(tài)函數(shù) orderQuery
??它負責查詢訂單,所有支付方式的訂單都可以調用它來查詢,它所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayOrderQuery?類,它主要負責設置要查詢的訂單的信息,除此之外,我們還可以利用它來判斷商戶號、AppId等信息是否存在,根據(jù)商戶訂單號查詢,設置如下。
注意:每次查詢的訂單,它所設置的商戶訂單號或微信訂單號,都是和下單時候的一樣,它們是配對的。
$input->SetOut_trade_no("對應下單時的訂單號");
返回值是一個數(shù)組,含有訂單下單時間、支付的狀態(tài)結果、訂單是否存在等,下面是一個例子。
$input=newWxPayOrderQuery();
$input->SetOut_trade_no("下單時的商戶訂單號");
//其他的設置
$order=WxPayApi::orderQuery($input);
2,靜態(tài)函數(shù) refundQuery
??它負責查詢退款訂單,相比于orderQuery,我們可以理解為是相比于orderQuery的一部分,它所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayRefundQuery?類,它主要負責設置要查詢的退款訂單的信息,除此之外,我們還可以利用它來判斷商戶號、AppId等信息是否存在,這部分和WxPayOrderQuery幾乎一樣,根據(jù)商戶訂單號查詢,設置如下。
注意:每次查詢的退款訂單,它所設置的商戶訂單號或微信訂單號,都是和下單時候的一樣,它們是配對的。
$input->SetOut_trade_no("下單時的商戶訂單號");
返回值是一個數(shù)組,含有訂單下單時間、支付的狀態(tài)結果、訂單是否存在等,下面是一個例子。
$input=newWxPayRefundQuery();
$input->SetOut_trade_no("下單時的訂單號");
//其他的設置
$order=WxPayApi::refundQuery($input);
注意事項
1,參數(shù)設置個數(shù)
??無論是下訂單還是發(fā)起退款等操作,其設置的信息都限制了不能只有一個。
2,參數(shù)設置要求
??1)商戶訂單號是由用戶設置的,對應每條訂單必須唯一;
??2)下單中的款數(shù)設置,是int類型,微信規(guī)定了其單位是分,也就是說如果我們設置了100,事實付款1元,退款結果中的款數(shù)也是分作單位,切記;
??3)下單中的貨幣類型,默認是CNY即人民幣,若設置了其他的幣種,要注意換算!
3,訂單唯一性
??每條訂單可以由商戶訂單號,這個我們在每次下單一次生成一次的號碼確定之外,還可以由微信訂單號唯一確定,但是,微信訂單號由微信支付自己生成,我們可以通過查詢訂單獲得或者登陸商戶平臺查看。
在JavaScript處理支付結果
在發(fā)起支付請求后,我們需要如果可以通過下面兩種方式來判斷是否支付成功。第一種是在JavaScript回調函數(shù)中處理。
??在jsapi.php文件的下面有幾個JavaScript函數(shù),他們分別是jsApiCall(),callpay(),editAddress()
??editAddress()的功能是獲取用戶的位置信息,具體表現(xiàn)是,當用戶進入支付頁面,如果調用這個函數(shù),那么就會調起選擇地址的界面,等用戶選擇完成后,才返回進入下一步,對于它,我們默認即可
//獲取用戶地址
function?editAddress()
{
WeixinJSBridge.invoke(
'editAddress',
,
function(res)
{
var?value1?=?res.proviceFirstStageName;
var?value2?=?res.addressCitySecondStageName;
var?value3?=?res.addressCountiesThirdStageName;
var?value4?=?res.addressDetailInfo;
var?tel?=?res.telNumber;
alert(value1?+?value2?+?value3?+?value4?+?":"?+?tel);
}
);
}
??callpay()的功能是在確保WeixinJSBridge對象存在的情況下再進入jsApiCall()函數(shù),此時把支付接口返回的數(shù)據(jù)進行解析并回調支付結果,在這里我們就能大致判斷下用戶支付是否成功,為什么是大致判斷呢,因為微信團隊告知了我們,在這里處理支付結果不可靠!切記。
//調用微信JS?api?支付
function?jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
,
function(res){
WeixinJSBridge.log(res.err_msg);
alert(res.err_code+res.err_desc+res.err_msg);
//?使用以上方式判斷前端返回,微信團隊鄭重提示:
//?res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對可靠。
if(res.err_msg?==?"get_brand_wcpay_request:ok"?)?{
//?支付成功
}else?if((res.err_msg?=="get_brand_wcpay_request:fail"){
//?支付失敗
}else?if((res.err_msg?=="get_brand_wcpay_request:cancel"){
//?支付過程中用戶取消
}
}
);
}
在回調鏈接中處理結果的入口
?? 在發(fā)起訂單組合訂單參數(shù)的時候,我們有下面的一個設置,它就是用來在支持成功回調通知中處理成功之后事宜的,也就是說,我們可以在這個代碼文件里面可靠地處理支付結果,下面的鏈接設置是默認的測試路徑。
$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");
notify.php的例子文件在example文件夾下面,對應文件管理中example文件夾下的notify.php文件。
必須引入的頭文件,以SDK的路徑為例子
require_once?"../lib/WxPay.Api.php";
require_once?'../lib/WxPay.Notify.php';
回調信息處理的入口
$notify?=?new?PayNotifyCallBack();
$notify->Handle(false);
現(xiàn)在打開lib文件夾下的WxPay.Notify.php文件,找到WxPayNotify類,入口函數(shù)Handler如下。
/**
*?回調入口
*?@param?bool?$needSign?是否需要簽名輸出
*/
final?public?function?Handle($needSign?=?true)
{
$msg?=?"OK";
//當返回false的時候,表示notify中調用NotifyCallBack回調失敗
//若傳入需要簽名即傳入true,獲取簽名校驗失敗,此時直接返回失敗
//notify函數(shù)里面?zhèn)魅肓薔otifyCallBack回調函數(shù)名,這時候它會被調用
//$msg作為變量也傳入了NotifyCallBack回調函數(shù)里面,$msg包含有支付信息
$result?=?WxpayApi::notify(array($this,?'NotifyCallBack'),?$msg);
if($result?==?false)
{
$this->SetReturn_code("FAIL");
$this->SetReturn_msg($msg);
$this->ReplyNotify(false);
return;
}else{
//該分支在成功回調到NotifyCallBack方法,處理完成之后流程
$this->SetReturn_code("SUCCESS");
$this->SetReturn_msg("OK");
}
$this->ReplyNotify($needSign);
}
重寫回調函數(shù)自定義處理
?? notify的回調方法在lib文件夾下的WxPay.Notify.php文件中,在NotifyCallBack函數(shù)里面,它調用了NotifyProcess,注意,此時就相當于調用了notify.php中的PayNotifyCallBack類里面的NotifyProcess函數(shù)。
/**
*?notify的回調方法,該方法中需要賦值需要輸出的參數(shù)
*?@param?array?$data
*?@return?true回調出來完成不需要繼續(xù)回調,false回調處理未完成需要繼續(xù)回調
*/
final?public?function?NotifyCallBack($data)?//?$msg傳進來
{
$msg?=?"OK";
"http://NotifyProcess就是我們要重寫的函數(shù)"
$result?=?$this->NotifyProcess($data,?$msg);
if($result?==?true){
$this->SetReturn_code("SUCCESS");
$this->SetReturn_msg("OK");
}else{
$this->SetReturn_code("FAIL");
$this->SetReturn_msg($msg);
}
return?$result;
}
在notify.php中重寫,NotifyProcess函數(shù)。
class?PayNotifyCallBack?extends?WxPayNotify
{
//查詢訂單
public?function?Queryorder($transaction_id)
{
$input?=?new?WxPayOrderQuery();
$input->SetTransaction_id($transaction_id);
$result?=?WxPayApi::orderQuery($input);
Log::DEBUG("query:"?.?json_encode($result));
if(array_key_exists("return_code",?$result)
&&?array_key_exists("result_code",?$result)
&&?$result["return_code"]?==?"SUCCESS"
&&?$result["result_code"]?==?"SUCCESS")
{
return?true;
}
return?false;
}
//重寫回調處理函數(shù)
public?function?NotifyProcess($data,&$msg)
{
//"$data"?是NotifyCallBack函數(shù)傳進來的含有支付信息的參數(shù)
$notfiyOutput?=?array();
//?下面這句判斷支付參數(shù)中是否含有微信訂單號transaction_id
if(!array_key_exists("transaction_id",?$data)){
$msg?=?"輸入?yún)?shù)不正確";
return?false;
}
//查詢訂單,判斷訂單真實性,二重判斷
if(!$this->Queryorder($data["transaction_id"])){
$msg?=?"訂單查詢失敗";
return?false;
}
//?"這里返回真,證明支付成功了"
//?"我們也可以直接在這里做支付成功后的操作"
return?true;
}
}
訂單查詢
??對應文件管理中example文件夾下的orderquery.php文件
1,頭文件引入
必須引入的頭文件,以SDK的路徑為例子
require_once"../lib/WxPay.Api.php";
可選的頭文件引入,該頭文件只是微信支付用于記錄操作日志
require_once'log.php';
2,查詢條件
?? 每條訂單可以由商戶訂單號,這個我們在每次下單一次生成一次的號碼確定之外,還可以由微信訂單號唯一確定,那么查詢訂單的時候也需要這兩個參數(shù)之中的一個,由于微信訂單的獲取比較麻煩,所以一般我們采用商戶訂單號來進行查詢,微信訂單號和商戶訂單號最少填一個,微信訂單號優(yōu)先。
3,采用商戶訂單號查詢
?? 首先我們要這這個頁面里面獲取到要查詢的商戶訂單號,例如通過get的形式來獲取。
$tradeId?=?$_GET["out_trade_no"];
然后就能調用接口函數(shù)來進行查詢了。
if(isset($tradeId)?&&?$tradeId?!=?"")
{
$input?=?new?WxPayOrderQuery();
$input->SetOut_trade_no($tradeId);?//?設置好要查詢的訂單
$order?=?WxPayApi::orderQuery($input));?//?進行查詢
var_dump($order);?//?打印出訂單信息
}
常用的訂單信息:
if($order['err_code_des']?=="order?not?exist"){
//?訂單不存在
}else{
$money?=?$order['total_fee'];?//所付款數(shù),單位分
if($order['trade_state']?=="SUCCESS"){
//支付成功
}else?if($order['trade_state']?=="REFUND"){
//已退款
}else?if($order['trade_state']?=="NOTPAY"){
//用戶還沒支付
}else?if($order['trade_state']?=="CLOSED"){
//訂單關閉
}else?if($order['trade_state']?=="REVOKED"){
//已撤銷(刷卡支付)
}else?if($order['trade_state']?=="USERPAYING"){
//用戶支付中
}else?if($order['trade_state']?=="PAYERROR"){
//支付失敗(其他原因,例如銀行返回失敗)
}
}
更多查詢訂單返回值,參考官方文檔
4,采用微信訂單號查詢
$wxId?=?$_GET["transaction_id"];
if(isset($wxId)?&&?$wxId?!=?"")
{
$input?=?new?WxPayOrderQuery();
$input->SetOut_trade_no($wxId);?//?設置好要查詢的訂單
$order?=?WxPayApi::orderQuery($input));?//?進行查詢
var_dump($order);?//?打印出訂單信息
}
申請退款
??對應文件管理中example文件夾下的refund.php文件
1,頭文件引入
必須引入的頭文件,以SDK的路徑為例子
require_once"../lib/WxPay.Api.php";
可選的頭文件引入,該頭文件只是微信支付用于記錄操作日志
require_once'log.php';
2,退款參數(shù)
?? 除了要輸入要退款的訂單號之外,退款還需要商戶號、退款的款數(shù)、商戶訂單號、為該次退款設置一個退款單號等,在這里要注意退款的款數(shù)要化為單位分,例如要退款2元,那么設置時要設置為200。
2,發(fā)起退款
?? 這里我們以REQUEST的方式獲取傳過來的參數(shù)為例子,這種方式對發(fā)送端是get還是post沒要求,無論是get的方式還是post方式,都能接收到,在安全方面不夠post形式好。
if(isset($_REQUEST["out_trade_no"])?&&?$_REQUEST["out_trade_no"]?!=?""){
$out_trade_no?=?$_REQUEST["out_trade_no"];?//?要退款的訂單的商戶訂單號
$total_fee?=?$_REQUEST["total_fee"];?//?該訂單的一共支付總額
$refund_fee?=?$_REQUEST["refund_fee"];?//?要退款的錢數(shù)
$input?=?new?WxPayRefund();
/**?SetOut_trade_no?設置該訂單的商戶訂單號,憑借這個唯一確定?*/
$input->SetOut_trade_no($out_trade_no);
/**?SetTotal_fee?設置訂單的當時支付的總額?*/
$input->SetTotal_fee($total_fee);
/**?SetRefund_fee?設置要退款多少錢?*/
$input->SetRefund_fee($refund_fee);
/**?SetOut_refund_no?設置此次商戶退款的單號,它不是商戶訂單號?*/
$input->SetOut_refund_no(WxPayConfig::MCHID.date("YmdHis"));
/**?SetOp_user_id?設置商戶號?*/
$input->SetOp_user_id(WxPayConfig::MCHID);
/**?發(fā)起退款?*/
$order?=?WxPayApi::refund($input);
/**?在返回的數(shù)組中,我們能夠獲取鍵名return_code?*/
if($order["return_code"]=="SUCCESS"){
//?退款申請成功
}else?if($order["return_code"]=="FAIL"){
//?退款申請失敗
}else{
//?未知狀態(tài)
}
var_dump($order);
}
3,退款效果
??一旦申請退款成功,那么該訂單號對應的用戶便會在微信客戶端收到退款的憑據(jù),同時在商家的商戶平臺也會有該退款記錄生成。
查詢退款
??對應文件管理中example文件夾下的refundquery.php文件
1,頭文件引入
必須引入的頭文件,以SDK的路徑為例子
require_once"../lib/WxPay.Api.php";
可選的頭文件引入,該頭文件只是微信支付用于記錄操作日志
require_once'log.php';
2,根據(jù)微信訂單號查詢
?? 微信訂單號在上面提到,它是微信支付系統(tǒng)自己幫我們生成的,如果要獲知的話,目前我們可以在查詢訂單處獲得,或者直接登錄微信商戶平臺查看獲得,由微信訂單號查退款的靈活度不高,下面是例子代碼。
if(isset($_REQUEST["transaction_id"])?&&?$_REQUEST["transaction_id"]?!=?""){
$transaction_id?=?$_REQUEST["transaction_id"];
$input?=?new?WxPayRefundQuery();
$input->SetTransaction_id($transaction_id);
$order?=?WxPayApi::refundQuery($input);
var_dump($order)$order;
};
3,根據(jù)商戶訂單號查詢
?? 商戶訂單號查詢的靈活性高,因為商戶訂單號是我們自己生成的,在下訂單生成的時候,我們在處理下單結果確認支付成功后,就可以把它存到數(shù)據(jù)庫,查詢的時候再讀取出來。
if(isset($_REQUEST["out_trade_no"])?&&?$_REQUEST["out_trade_no"]?!=?""){
$out_trade_no?=?$_REQUEST["out_trade_no"];
$input?=?new?WxPayRefundQuery();
$input->SetOut_trade_no($out_trade_no);
$order?=?WxPayApi::refundQuery($input);
var_dump($order)$order;
}
4,根據(jù)商戶退款單號查詢
?? 還記得在退款操作的時候有這么一句設置嗎,如下所示,它就是設置商戶退款單號的,也是由我們生成,一樣要確保它對于每條退款的唯一性。
/**?SetOut_refund_no?設置此次退款的商戶單號,它不是商戶訂單號?*/
$input->SetOut_refund_no(WxPayConfig::MCHID.date("YmdHis"));
if(isset($_REQUEST["out_refund_no"])?&&?$_REQUEST["out_refund_no"]?!=?""){
$out_refund_no?=?$_REQUEST["out_refund_no"];
$input?=?new?WxPayRefundQuery();
$input->SetOut_refund_no($out_refund_no);
$order?=?WxPayApi::refundQuery($input);
var_dump($order)$order;
}
5,根據(jù)退款單號查詢
?? 退款單號的生成和微信訂單號一樣,也是微信支付系統(tǒng)幫我們生成的。
if(isset($_REQUEST["refund_id"])?&&?$_REQUEST["refund_id"]?!=?""){
$refund_id?=?$_REQUEST["refund_id"];
$input?=?new?WxPayRefundQuery();
$input->SetRefund_id($refund_id);
$order?=?WxPayApi::refundQuery($input);
var_dump($order)$order;
}
?? 上面的四種退款查詢方式,各有所長,我們可以根據(jù)我們的實際情況的選擇使用,一般來說,微信支付系統(tǒng)幫我們生成的單號的優(yōu)先級別是大于我們自己生成的。
使用環(huán)境
?? 一定要記住,微信支付的網(wǎng)頁版支付方式只能在微信的內置瀏覽器里面進行,如果你在電腦瀏覽器打開了鏈接支付,它是會提示你錯誤的,那么怎么在電腦使用呢?可以安裝手機虛擬機,例如Genymotion或者夜神虛擬機,再到手機虛擬機里面安裝一個微信APP,就可以了。
???測試的時候,你可以直接通過發(fā)送測試鏈接到你的微信里面,再打開就行了。
支付憑據(jù)
?? 在每一次的訂單支付成功后,微信都會發(fā)一條電子支付憑據(jù)給所付款的用戶,支付憑據(jù)中的重要信息有微信訂單號和商戶訂單號,除此之外還有商品名稱,下單時間,支付狀態(tài)。其中商戶訂單號由我們代碼設置,商品名稱也是,商品名稱對應的是$input->SetBody("test");,下單時間對應的是$input->SetTime_start(date("YmdHis"));。
?? 支付憑據(jù)可以讓用戶自己恢復訂單。想象一下,用戶購買了商品且支付成功,但是我們自己的數(shù)據(jù)庫系統(tǒng)卻因為其他問題漏單了,這時候我們可以在我們的網(wǎng)頁中設置一個訂單恢復系統(tǒng),由用戶輸入訂單號,然后我們后臺進行訂單查詢,若訂單的確支付成功了,而數(shù)據(jù)庫沒對應記錄,那么我們就進而恢復訂單。
?? 微信支付嚴格要求支付的錢數(shù)最少是 1 分,在代碼里面少于這個數(shù)會支付失敗。


獲取 OpenId
?? 還記得獲取OpenId的時候,頁面會怎樣嗎?沒錯,它會重定向的,為了不丟失我們傳過去的數(shù)據(jù),最好的方法就是改寫。
lib文件夾下的?WxPay.Api.php?函數(shù)
public?function?GetOpenid($userName,$userSex)
{
//通過code獲得openid
//code在微信服務處理完成之后重定向時帶回來的
if?(!isset($_GET['code']))
{
//?假設現(xiàn)在我的支付代碼文件的鏈接是:
//?http://hubwiz.com/WeChatPay/example/jsapi.php,那么下面就是
$baseUrl?=?urlencode("http://hubwiz.com/WeChatPay/example/jsapi.php?userName=".$userName."&userSex=".$userSex);
$url?=?$this->__CreateOauthUrlForCode($baseUrl);
Header("Location:?$url");?//?重定向
exit();
}else{
//獲取code碼,以獲取openid
$code?=?$_GET['code'];
$openid?=?$this->getOpenidFromMp($code);
return?$openid;//?返回OpenId
}
}
確保已下訂單
?? 在處理支付結果回調之后,建議再進行一次訂單查詢,以確保萬無一失,除此之外,設置一個訂單恢復系統(tǒng)也是可以的,例如下面的例子。
if(isset($tradeId)?&&?$tradeId?!=?"")
{
$input?=?new?WxPayOrderQuery();
$input->SetOut_trade_no($tradeId);?//?設置好要查詢的訂單
$order?=?WxPayApi::orderQuery($input));?//?進行查詢
if($order['err_code_des']?=="order?not?exist"){
//?訂單不存在
}else{
$money?=?$order['total_fee'];?//所付款數(shù),單位分
if($order['trade_state']?=="SUCCESS"){
//支付成功
//數(shù)據(jù)庫操作
//兩者對比
//若數(shù)據(jù)庫中沒記錄,就恢復訂單
}else?if($order['trade_state']?=="REFUND"){
//已退款
}else?if($order['trade_state']?=="NOTPAY"){
//用戶還沒支付
}else?if($order['trade_state']?=="CLOSED"){
//訂單關閉
}else?if($order['trade_state']?=="REVOKED"){
//已撤銷(刷卡支付)
}else?if($order['trade_state']?=="USERPAYING"){
//用戶支付中
}else?if($order['trade_state']?=="PAYERROR"){
//支付失敗(其他原因,例如銀行返回失敗)
}
}
}
基于SDK修改的Demo
?? 用法:先到 index.php 的上面修改鏈接數(shù)據(jù),再把整個工程放到你的服務器,就可以測試使用了。

? 下載好之后,在index.php 文件里面配置下路徑信息,如下面所示,當然,如果你不使用微信自帶的測試支付配置,別忘了還要到lib文件夾下修改WxPay.Config.php文件里面的配置信息。
/**?請在下面設置你服務器的路徑,默認是測試的,如果您沒有自己的服務器,可以使用測試的?*/
$jsApiPay?=?"http://paysdk.weixin.qq.com/example/jsapi.php";
/**?刷卡支付?*/
$micropyPay?=?"http://paysdk.weixin.qq.com/example/micropay.php";
/**?掃碼支付?*/
$nativePay?=?"http://paysdk.weixin.qq.com/example/native.php";
/**?訂單查詢?*/
$orderQuery?=?"http://paysdk.weixin.qq.com/example/orderquery.php";
/**?退款?*/
$refundPay?=?"http://paysdk.weixin.qq.com/example/refund.php";
/**?退款查詢?*/
$refundQueryPay?=?"http://paysdk.weixin.qq.com/example/refundquery.php";
?>