基于PHP的微信支付教程

關(guān)于微信支付

1. 生活中的微信支付

??目前我們?nèi)粘I钪薪佑|得比較多的線上電子支付方式主要有兩種,一種是支付寶,另一種就是微信支付了,微信支付是集成在微信客戶端的支付功能,所謂微信客戶端,主要是微信的移動(dòng)應(yīng)用,例如安卓(Android)微信APP、IOS微信APP,用戶可以通過(guò)手機(jī)的微信APP完成快速的支付流程,當(dāng)然,其他的移動(dòng)應(yīng)用也可以接入微信支付的接口來(lái)達(dá)到完成微信支付的所有功能。

2. 微信支付方式

??主要的支付方式有:公眾號(hào)支付或稱網(wǎng)頁(yè)支付,掃描二維碼支付,APP支付,除此之外還有刷卡支付等,還有一點(diǎn)就是,微信支付以綁定銀行卡的快捷支付為基礎(chǔ)的。

3. 為什么要掌握

??對(duì)于我們開(kāi)發(fā)者而言,熟練地掌握微信支付的接口功能是必不可少的,因?yàn)橐院笪业囊龅幕ヂ?lián)網(wǎng)產(chǎn)品中,可能是網(wǎng)頁(yè),亦可能是移動(dòng)應(yīng)用APP,都可能會(huì)集成微信支付,那么接下來(lái)讓我們來(lái)學(xué)習(xí)如果使用PHP版的微信支付接口吧。

4. 關(guān)于本節(jié)課

?? 本門(mén)課程主要針對(duì)已經(jīng)開(kāi)通了微信商戶號(hào)且開(kāi)通微信公眾平臺(tái)微信支付功能系統(tǒng)的學(xué)員,那我沒(méi)有開(kāi)通這些東西怎么學(xué)習(xí)?如果沒(méi)有開(kāi)通,也沒(méi)關(guān)系,可以直接使用本課程的代碼,因?yàn)楸竟?jié)課程使用的是所有支付配置信息使用的都是測(cè)試賬號(hào)提供的,在你學(xué)習(xí)了調(diào)起支付后,如果使用支付功能,那么會(huì)產(chǎn)生每次一分錢(qián)的費(fèi)用,支付到微信PHP開(kāi)發(fā)包代碼中提供的測(cè)試商戶號(hào)中,測(cè)試賬號(hào)歸屬于微信系統(tǒng)。

下載SDK

1. 復(fù)制下面的鏈接在瀏覽器中打開(kāi)

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

2. 在所打開(kāi)的頁(yè)面中選擇PHP版本的SDK下載

??目前的壓縮包名為:WxpayAPI_php_v3,下載完畢后,解壓到桌面,里面一共含有5個(gè)文件夾,和一個(gè) index.php 文件

cert、doc、example、lib、logs、index.php

為了方便大家學(xué)習(xí),我已經(jīng)在右邊的文件管理處上傳了對(duì)應(yīng)的一份SDK,大家可以參考學(xué)習(xí),不過(guò)最好還是在自己的電腦下載一份,首先大家先在右邊的編輯框中按照順序,輸入命令ls,然后看下輸出的是不是下圖,如果輸出的是wxPay,那么就輸入命令cd wxPay

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

上面的操作完成后,大家點(diǎn)擊右邊的訪問(wèn)測(cè)試就可以進(jìn)入到支付樣例主頁(yè)面了,如下圖所示:

?頁(yè)面顯示出了三種支付方式,第一種jsapi是網(wǎng)頁(yè)支付,第二種刷卡支付,第三種掃碼支付,這時(shí)候如果你點(diǎn)擊jsapi支付的話,網(wǎng)頁(yè)會(huì)提示請(qǐng)?jiān)谖⑿趴蛻舳舜蜷_(kāi)鏈接,為什么會(huì)這樣呢?這個(gè)我會(huì)在后面的課程說(shuō)到,除此之外,掃碼支付如果你用微信的掃描二維碼掃描了的話,是真的會(huì)進(jìn)入到支付頁(yè)面的哦。

文件說(shuō)明

1. index.php

??這個(gè)是官方提供的所有支付功能集成化的入口,不過(guò)需要注意的是:如果使用到我們自己的項(xiàng)目中,記得修改對(duì)應(yīng)的鏈接。

2. cert-證書(shū)存放路徑

??證書(shū)是商家在使用微信支付功能的時(shí)候,進(jìn)行身份驗(yàn)證用到的,起到一種安全的作用,但是,目前微信支付僅僅只在使用退款接口或者撤銷(xiāo)訂單的時(shí)候需要可能會(huì)用到證書(shū),為什么是可能呢?因?yàn)樵诮涌诤瘮?shù)中,我們可以選擇是否使用證書(shū),不使用也能使用退款或撤銷(xiāo)訂單接口,在我們下載的SDK中,文件夾cert里面的證書(shū)對(duì)應(yīng)的是微信的測(cè)試賬號(hào)的,如果,我們擁有自己的微信商戶平臺(tái)的賬號(hào),那么我們就可以登錄商戶平臺(tái),來(lái)下載我們自己的證書(shū)放到這個(gè)目錄。

3. doc-官方文檔目錄

??里面含有一些的SDK使用指南信息

4. example-官方接口例子目錄

??在為完全掌握微信支付接口功能實(shí)現(xiàn)之前,我們主要依賴官方的例子代碼來(lái)進(jìn)行學(xué)習(xí),進(jìn)而進(jìn)行修改,含有:

文件夾-phpqrode存放了二維碼功能相關(guān)文件

jsapi.php"網(wǎng)頁(yè)調(diào)起支付頁(yè)面;"

notify.php"網(wǎng)頁(yè)支付后的回調(diào)的頁(yè)面;"

native.php"付款二維碼信息組裝頁(yè)面;"

qrcode.php"生成二維碼的頁(yè)面"

native_notify.php"掃描所生成二維碼進(jìn)入的頁(yè)面;"

notify.php"網(wǎng)頁(yè)支付后的回調(diào)頁(yè)面;"

orderquery.php"訂單查詢頁(yè)面;"

download.php"查退款單頁(yè)面;"

refund.php"退款的頁(yè)面;"

refundquery.php"退款單查詢的頁(yè)面;"

WxPay.JsApiPay.php"網(wǎng)頁(yè)支付核心類;"

WxPay.NativePay.php和WxPay.MicroPay.php"是刷卡支付類"

5. lib-核心庫(kù)

前兩個(gè)很重要!

WxPay.Api.php"接口訪問(wèn)類,包含所有微信支付API列表的封裝"

WxPay.Config.php"配置信息所在文件"

WxPay.Data.php"簽名相關(guān)類,含簽名生成"

WxPay.Exception.php"異常類"

WxPay.Notify.php"回調(diào)函數(shù)的父類"

6. logs-這個(gè)主要用來(lái)存放在支付過(guò)程中生成的各種日志文件

接下來(lái)我們進(jìn)行文件配置

lib文件夾下的WxPay.Config.php

??對(duì)應(yīng)文件管理中l(wèi)ib文件夾下的WxPay.Config.php文件

1,公眾號(hào)與商戶平臺(tái)

??首先,我們簡(jiǎn)單了解一下微信公眾號(hào)和微信商戶平臺(tái)在微信支付中扮演的角色,公眾號(hào)是我們?cè)诰W(wǎng)頁(yè)要進(jìn)行支付的場(chǎng)所,而用戶支付了的錢(qián),我們?cè)鯓訉?duì)它進(jìn)行操作呢,這就需要商戶平臺(tái)了,我們?cè)谏虘羝脚_(tái)里能夠進(jìn)行支付賬單查詢、款數(shù)提現(xiàn)等操作,現(xiàn)在我們采用軟件打開(kāi)lib文件下的WxPay.Config.php,可以采用 PhpStorm,sublime,記事本,或者參照右邊的文件管理,由于cert文件夾和doc文件夾里面的內(nèi)容目前不支持上傳,所以右邊文件管理處,沒(méi)有上傳這2個(gè)文件夾里面的文件。

2,AppId和AppSecret

??微信公眾號(hào)的AppId和公眾號(hào)秘鑰,AppId是用來(lái)唯一標(biāo)識(shí)公眾號(hào)用戶,AppSecret可以理解為密碼,如果沒(méi)有公眾號(hào),那么我們就使用微信的測(cè)試AppId,如果我們有的話,那么我們可以先登錄微信公眾,在這里,還要求我們的公眾號(hào)必須已經(jīng)開(kāi)通微信支付的接口權(quán)限,否則我們的AppId是不具備支付權(quán)限的。然后在左邊的菜單欄滑到最低,找到并點(diǎn)擊開(kāi)發(fā)->基本配置->找到AppId 和 AppSecret

constAPPID='wx426b3015555a46be';//這個(gè)是微信提供的測(cè)試AppId,我們學(xué)習(xí)用它足以

constAPPSECRET='01c6d59a3f9024db6336662ac95c8e74';//也是微信提供的測(cè)試AppSecret

lib文件夾下的WxPay.Config.php

1,商戶號(hào)MCHID

??商戶號(hào)MCHID,它用來(lái)唯一標(biāo)識(shí)微信商戶用戶,它在我們注冊(cè)成功成為商戶的時(shí)候,官方會(huì)發(fā)來(lái)一封開(kāi)戶郵件,在這封郵件中可查看,如果沒(méi)有商戶號(hào),我們一樣可以使用微信的測(cè)試商戶號(hào),如果有的話,那么我們可以登陸微信商戶平臺(tái)。

constMCHID='1225312702';//這個(gè)也是微信提供的測(cè)試商戶號(hào)

2,商戶支付密鑰KEY

??商戶支付密鑰KEY,必須由商戶自己設(shè)置,如果我們有自己的商戶,那么可以在商戶平臺(tái)的:賬戶設(shè)置->API安全中可以設(shè)置,沒(méi)有的話也可以使用微信提供的來(lái)測(cè)試和學(xué)習(xí)。

constKEY='e10adc3949ba59abbe56e057f20f883e';//微信提供的測(cè)試支付密鑰

1,證書(shū)文件apiclient_cert與apiclient_key


??下面的是支付所用的存儲(chǔ)私鑰文件[apiclient_cert]、存儲(chǔ)公鑰文件[apiclient_key],在前面文件說(shuō)明這節(jié)課中有說(shuō)到,證書(shū)是商家在使用微信支付功能的時(shí)候,進(jìn)行身份驗(yàn)證用到的,起到一種安全的作用,但是,目前微信支付僅僅只在使用退款接口或者撤銷(xiāo)訂單的時(shí)候需要可能會(huì)用到證書(shū),為什么是可能呢?因?yàn)樵诮涌诤瘮?shù)中,我們可以選擇是否使用證書(shū),不使用也能使用退款或撤銷(xiāo)訂單接口。

證書(shū)下載:證書(shū)不是在公眾平臺(tái)下載的,是在商戶平臺(tái)的賬戶設(shè)置->API安全里面下載。下面的是微信提供的測(cè)試證書(shū),我們測(cè)試和學(xué)習(xí)可以使用它們。?

constSSLCERT_PATH='../cert/apiclient_cert.pem';//測(cè)試提供的私鑰

constSSLKEY_PATH='../cert/apiclient_key.pem';//測(cè)試提供的公鑰

2,代理服務(wù)器和錯(cuò)誤上報(bào)

??下面的為代理服務(wù)器和程序錯(cuò)誤信息上報(bào)等級(jí)相關(guān)設(shè)置,如無(wú)特殊情況,默認(rèn)即可。

constCURL_PROXY_HOST="0.0.0.0";// 代理的IP,不需要代理,請(qǐng)?jiān)O(shè)置為0.0.0.0和0

constCURL_PROXY_PORT=0;//代理的端口,此時(shí)不開(kāi)啟代理(如有需要才設(shè)置)

constREPORT_LEVENL=1;//錯(cuò)誤信息上報(bào)等級(jí),0.關(guān)閉上報(bào); 1.僅錯(cuò)誤出錯(cuò)上報(bào); 2.全量上報(bào)

網(wǎng)頁(yè)設(shè)置

1,OpenId簡(jiǎn)介

??OpenId是微信用來(lái)唯一標(biāo)識(shí)用戶的一串字符,通俗來(lái)說(shuō)就是微信用戶的id。在前面的課程中我們知道了在微信支付中調(diào)起支付需要在代碼設(shè)置參數(shù),而且要設(shè)置的還不止一個(gè),其中還要設(shè)置的就有用戶的OpenId,哪個(gè)用戶呢?我們知道每一次的交易,都有一個(gè)付款者,那么在這次交易中,我們要設(shè)置的OpenId就是他的,上面談到,OpenId是微信唯一標(biāo)識(shí)用戶的,我們不可能隨便就獲取到,因此微信提供了一個(gè)專門(mén)用來(lái)獲取用戶OpenId的接口給我們。

2,獲取OpenId的準(zhǔn)備

??如果我們有自己的公眾號(hào),而且公眾號(hào)開(kāi)通了微信支付權(quán)限的話,那么為了獲取OpenId,我們需要登錄公眾平臺(tái),然后在左邊的菜單欄滑到最低,找到并點(diǎn)擊開(kāi)發(fā)->接口權(quán)限

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

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

1,支付相關(guān)代碼路徑授權(quán)

??現(xiàn)在我們已經(jīng)下載好了微信支付 PHP 的 SDK,默認(rèn)所有配置信息都是微信提供的,如果我們有自己的公眾號(hào)且開(kāi)通了支付權(quán)限,除了上面的獲取OpenId的準(zhǔn)備工作之外,我們還要把我們寫(xiě)好了的微信支付的相關(guān)代碼,放到我們自己的服務(wù)器里面,然后需要到公眾平臺(tái)授權(quán)該路徑。

??首先,在公眾號(hào)的左邊菜單欄找到微信支付并點(diǎn)擊,然后在右邊點(diǎn)擊開(kāi)發(fā)配置

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

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

測(cè)試支付目錄的修改參照授權(quán)目錄,如果你設(shè)置了測(cè)試授權(quán)目錄,記得到測(cè)試白名單中添加測(cè)試賬號(hào)


下面的課程我們講從代碼的角度去學(xué)習(xí)微信支付

example文件夾下的 WxPay.JsApiPay.php

??對(duì)應(yīng)文件管理中example文件夾下的 WxPay.JsApiPay.php文件

1,靜態(tài)函數(shù) unifiedOrder

??它負(fù)責(zé)統(tǒng)一下單,除刷卡支付外的支付都是由它進(jìn)行,如果我們是在網(wǎng)頁(yè)中進(jìn)行支付的話,這個(gè)函數(shù)是先行的,所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayUnifiedOrder?類,它主要負(fù)責(zé)設(shè)置一些訂單的信息,例如設(shè)置商戶訂單號(hào):

$input->SetOut_trade_no("32個(gè)字符內(nèi)、可包含字母的商戶訂單號(hào)");

返回值是一個(gè)數(shù)組,包含的狀態(tài)碼和支付信息,但是不能由這個(gè)來(lái)判斷是否支付成功!官方文檔

??還有一個(gè)要注意的是:要設(shè)置的訂單信息項(xiàng),不止一個(gè),下面是一個(gè)例子,在下面的課程我會(huì)逐個(gè)解釋。

$input=newWxPayUnifiedOrder();

$input->SetOut_trade_no("32個(gè)字符內(nèi)、可包含字母的商戶訂單號(hào)");

//其他的設(shè)置

$order=WxPayApi::unifiedOrder($input);

2,靜態(tài)函數(shù) refund

??它負(fù)責(zé)退款,所有支付方式的退款都是由它進(jìn)行,它所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayRefund?類,它主要負(fù)責(zé)設(shè)置一些要退款的訂單的信息*,例如設(shè)置要退款的商戶訂單號(hào)。

注意:每次退款的商戶訂單號(hào)或微信訂單號(hào),都是和下單時(shí)候的一樣,它們是配對(duì)的。

$input->SetOut_trade_no("對(duì)應(yīng)下單時(shí)的訂單號(hào)");

返回值是一個(gè)數(shù)組,款數(shù)數(shù)目、時(shí)間、退款結(jié)果等,下面是一個(gè)例子。

$input=newWxPayRefund();

$input->SetOut_trade_no("下單時(shí)的商戶訂單號(hào)");

//其他的設(shè)置

$order=WxPayApi::refund($input);

example文件下的WxPay.MicroPay.php

??對(duì)應(yīng)文件管理中example文件夾下的WxPay.MicroPay.php文件

3,刷卡支付 pay

??它負(fù)責(zé)刷卡支付下訂單,所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayMicroPay?類,它主要負(fù)責(zé)設(shè)置要刷卡支付的訂單信息,例子如下。

$input->SetOut_trade_no("下單時(shí)的商戶訂單號(hào)");

返回值是一個(gè)數(shù)組,含有訂單下單時(shí)間、支付的狀態(tài)結(jié)果等,下面是一個(gè)例子。

$input=newWxPayMicroPay();

$input->SetOut_trade_no("下單時(shí)的訂單號(hào)");

//其他的設(shè)置

$microPay=newMicroPay();

$order=$microPay->pay($input);

1,靜態(tài)函數(shù) orderQuery

??它負(fù)責(zé)查詢訂單,所有支付方式的訂單都可以調(diào)用它來(lái)查詢,它所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayOrderQuery?類,它主要負(fù)責(zé)設(shè)置要查詢的訂單的信息,除此之外,我們還可以利用它來(lái)判斷商戶號(hào)、AppId等信息是否存在,根據(jù)商戶訂單號(hào)查詢,設(shè)置如下。

注意:每次查詢的訂單,它所設(shè)置的商戶訂單號(hào)或微信訂單號(hào),都是和下單時(shí)候的一樣,它們是配對(duì)的。

$input->SetOut_trade_no("對(duì)應(yīng)下單時(shí)的訂單號(hào)");

返回值是一個(gè)數(shù)組,含有訂單下單時(shí)間、支付的狀態(tài)結(jié)果、訂單是否存在等,下面是一個(gè)例子。

$input=newWxPayOrderQuery();

$input->SetOut_trade_no("下單時(shí)的商戶訂單號(hào)");

//其他的設(shè)置

$order=WxPayApi::orderQuery($input);

2,靜態(tài)函數(shù) refundQuery

??它負(fù)責(zé)查詢退款訂單,相比于orderQuery,我們可以理解為是相比于orderQuery的一部分,它所傳入的參數(shù)是 lib文件夾下WxPay.Data.php的WxPayRefundQuery?類,它主要負(fù)責(zé)設(shè)置要查詢的退款訂單的信息,除此之外,我們還可以利用它來(lái)判斷商戶號(hào)、AppId等信息是否存在,這部分和WxPayOrderQuery幾乎一樣,根據(jù)商戶訂單號(hào)查詢,設(shè)置如下。

注意:每次查詢的退款訂單,它所設(shè)置的商戶訂單號(hào)或微信訂單號(hào),都是和下單時(shí)候的一樣,它們是配對(duì)的。

$input->SetOut_trade_no("下單時(shí)的商戶訂單號(hào)");

返回值是一個(gè)數(shù)組,含有訂單下單時(shí)間、支付的狀態(tài)結(jié)果、訂單是否存在等,下面是一個(gè)例子。

$input=newWxPayRefundQuery();

$input->SetOut_trade_no("下單時(shí)的訂單號(hào)");

//其他的設(shè)置

$order=WxPayApi::refundQuery($input);

注意事項(xiàng)

1,參數(shù)設(shè)置個(gè)數(shù)

??無(wú)論是下訂單還是發(fā)起退款等操作,其設(shè)置的信息都限制了不能只有一個(gè)。

2,參數(shù)設(shè)置要求

??1)商戶訂單號(hào)是由用戶設(shè)置的,對(duì)應(yīng)每條訂單必須唯一;

??2)下單中的款數(shù)設(shè)置,是int類型,微信規(guī)定了其單位是分,也就是說(shuō)如果我們?cè)O(shè)置了100,事實(shí)付款1元,退款結(jié)果中的款數(shù)也是分作單位,切記;

??3)下單中的貨幣類型,默認(rèn)是CNY即人民幣,若設(shè)置了其他的幣種,要注意換算!

3,訂單唯一性

??每條訂單可以由商戶訂單號(hào),這個(gè)我們?cè)诿看蜗聠我淮紊梢淮蔚奶?hào)碼確定之外,還可以由微信訂單號(hào)唯一確定,但是,微信訂單號(hào)由微信支付自己生成,我們可以通過(guò)查詢訂單獲得或者登陸商戶平臺(tái)查看。

在JavaScript處理支付結(jié)果

在發(fā)起支付請(qǐng)求后,我們需要如果可以通過(guò)下面兩種方式來(lái)判斷是否支付成功。第一種是在JavaScript回調(diào)函數(shù)中處理。

??在jsapi.php文件的下面有幾個(gè)JavaScript函數(shù),他們分別是jsApiCall(),callpay(),editAddress()

??editAddress()的功能是獲取用戶的位置信息,具體表現(xiàn)是,當(dāng)用戶進(jìn)入支付頁(yè)面,如果調(diào)用這個(gè)函數(shù),那么就會(huì)調(diào)起選擇地址的界面,等用戶選擇完成后,才返回進(jìn)入下一步,對(duì)于它,我們默認(rèn)即可

//獲取用戶地址

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對(duì)象存在的情況下再進(jìn)入jsApiCall()函數(shù),此時(shí)把支付接口返回的數(shù)據(jù)進(jìn)行解析并回調(diào)支付結(jié)果,在這里我們就能大致判斷下用戶支付是否成功,為什么是大致判斷呢,因?yàn)槲⑿艌F(tuán)隊(duì)告知了我們,在這里處理支付結(jié)果不可靠!切記。

調(diào)起支付官網(wǎng)文檔

//調(diào)用微信JS?api?支付

function?jsApiCall()

{

WeixinJSBridge.invoke(

'getBrandWCPayRequest',

,

function(res){

WeixinJSBridge.log(res.err_msg);

alert(res.err_code+res.err_desc+res.err_msg);

//?使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示:

//?res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對(duì)可靠。

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"){

//?支付過(guò)程中用戶取消

}

}

);

}


在回調(diào)鏈接中處理結(jié)果的入口

?? 在發(fā)起訂單組合訂單參數(shù)的時(shí)候,我們有下面的一個(gè)設(shè)置,它就是用來(lái)在支持成功回調(diào)通知中處理成功之后事宜的,也就是說(shuō),我們可以在這個(gè)代碼文件里面可靠地處理支付結(jié)果,下面的鏈接設(shè)置是默認(rèn)的測(cè)試路徑。

$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");

notify.php的例子文件在example文件夾下面,對(duì)應(yīng)文件管理中example文件夾下的notify.php文件。

必須引入的頭文件,以SDK的路徑為例子

require_once?"../lib/WxPay.Api.php";

require_once?'../lib/WxPay.Notify.php';

回調(diào)信息處理的入口

$notify?=?new?PayNotifyCallBack();

$notify->Handle(false);

現(xiàn)在打開(kāi)lib文件夾下的WxPay.Notify.php文件,找到WxPayNotify類,入口函數(shù)Handler如下。

/**

*?回調(diào)入口

*?@param?bool?$needSign?是否需要簽名輸出

*/

final?public?function?Handle($needSign?=?true)

{

$msg?=?"OK";

//當(dāng)返回false的時(shí)候,表示notify中調(diào)用NotifyCallBack回調(diào)失敗

//若傳入需要簽名即傳入true,獲取簽名校驗(yàn)失敗,此時(shí)直接返回失敗

//notify函數(shù)里面?zhèn)魅肓薔otifyCallBack回調(diào)函數(shù)名,這時(shí)候它會(huì)被調(diào)用

//$msg作為變量也傳入了NotifyCallBack回調(diào)函數(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{

//該分支在成功回調(diào)到NotifyCallBack方法,處理完成之后流程

$this->SetReturn_code("SUCCESS");

$this->SetReturn_msg("OK");

}

$this->ReplyNotify($needSign);

}

重寫(xiě)回調(diào)函數(shù)自定義處理

?? notify的回調(diào)方法在lib文件夾下的WxPay.Notify.php文件中,在NotifyCallBack函數(shù)里面,它調(diào)用了NotifyProcess,注意,此時(shí)就相當(dāng)于調(diào)用了notify.php中的PayNotifyCallBack類里面的NotifyProcess函數(shù)。

/**

*?notify的回調(diào)方法,該方法中需要賦值需要輸出的參數(shù)

*?@param?array?$data

*?@return?true回調(diào)出來(lái)完成不需要繼續(xù)回調(diào),false回調(diào)處理未完成需要繼續(xù)回調(diào)

*/

final?public?function?NotifyCallBack($data)?//?$msg傳進(jìn)來(lái)

{

$msg?=?"OK";

"http://NotifyProcess就是我們要重寫(xiě)的函數(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中重寫(xiě),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;

}

//重寫(xiě)回調(diào)處理函數(shù)

public?function?NotifyProcess($data,&$msg)

{

//"$data"?是NotifyCallBack函數(shù)傳進(jìn)來(lái)的含有支付信息的參數(shù)

$notfiyOutput?=?array();

//?下面這句判斷支付參數(shù)中是否含有微信訂單號(hào)transaction_id

if(!array_key_exists("transaction_id",?$data)){

$msg?=?"輸入?yún)?shù)不正確";

return?false;

}

//查詢訂單,判斷訂單真實(shí)性,二重判斷

if(!$this->Queryorder($data["transaction_id"])){

$msg?=?"訂單查詢失敗";

return?false;

}

//?"這里返回真,證明支付成功了"

//?"我們也可以直接在這里做支付成功后的操作"

return?true;

}

}

訂單查詢

??對(duì)應(yīng)文件管理中example文件夾下的orderquery.php文件

1,頭文件引入

必須引入的頭文件,以SDK的路徑為例子

require_once"../lib/WxPay.Api.php";

可選的頭文件引入,該頭文件只是微信支付用于記錄操作日志

require_once'log.php';

2,查詢條件

?? 每條訂單可以由商戶訂單號(hào),這個(gè)我們?cè)诿看蜗聠我淮紊梢淮蔚奶?hào)碼確定之外,還可以由微信訂單號(hào)唯一確定,那么查詢訂單的時(shí)候也需要這兩個(gè)參數(shù)之中的一個(gè),由于微信訂單的獲取比較麻煩,所以一般我們采用商戶訂單號(hào)來(lái)進(jìn)行查詢,微信訂單號(hào)和商戶訂單號(hào)最少填一個(gè),微信訂單號(hào)優(yōu)先。

3,采用商戶訂單號(hào)查詢

?? 首先我們要這這個(gè)頁(yè)面里面獲取到要查詢的商戶訂單號(hào),例如通過(guò)get的形式來(lái)獲取。

$tradeId?=?$_GET["out_trade_no"];

然后就能調(diào)用接口函數(shù)來(lái)進(jìn)行查詢了。

if(isset($tradeId)?&&?$tradeId?!=?"")

{

$input?=?new?WxPayOrderQuery();

$input->SetOut_trade_no($tradeId);?//?設(shè)置好要查詢的訂單

$order?=?WxPayApi::orderQuery($input));?//?進(jìn)行查詢

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"){

//用戶還沒(méi)支付

}else?if($order['trade_state']?=="CLOSED"){

//訂單關(guān)閉

}else?if($order['trade_state']?=="REVOKED"){

//已撤銷(xiāo)(刷卡支付)

}else?if($order['trade_state']?=="USERPAYING"){

//用戶支付中

}else?if($order['trade_state']?=="PAYERROR"){

//支付失敗(其他原因,例如銀行返回失敗)

}

}

更多查詢訂單返回值,參考官方文檔

4,采用微信訂單號(hào)查詢

$wxId?=?$_GET["transaction_id"];

if(isset($wxId)?&&?$wxId?!=?"")

{

$input?=?new?WxPayOrderQuery();

$input->SetOut_trade_no($wxId);?//?設(shè)置好要查詢的訂單

$order?=?WxPayApi::orderQuery($input));?//?進(jìn)行查詢

var_dump($order);?//?打印出訂單信息

}

申請(qǐng)退款

??對(duì)應(yīng)文件管理中example文件夾下的refund.php文件

1,頭文件引入

必須引入的頭文件,以SDK的路徑為例子

require_once"../lib/WxPay.Api.php";

可選的頭文件引入,該頭文件只是微信支付用于記錄操作日志

require_once'log.php';

2,退款參數(shù)

?? 除了要輸入要退款的訂單號(hào)之外,退款還需要商戶號(hào)、退款的款數(shù)、商戶訂單號(hào)、為該次退款設(shè)置一個(gè)退款單號(hào)等,在這里要注意退款的款數(shù)要化為單位分,例如要退款2元,那么設(shè)置時(shí)要設(shè)置為200。

2,發(fā)起退款

?? 這里我們以REQUEST的方式獲取傳過(guò)來(lái)的參數(shù)為例子,這種方式對(duì)發(fā)送端是get還是post沒(méi)要求,無(wú)論是get的方式還是post方式,都能接收到,在安全方面不夠post形式好。

if(isset($_REQUEST["out_trade_no"])?&&?$_REQUEST["out_trade_no"]?!=?""){

$out_trade_no?=?$_REQUEST["out_trade_no"];?//?要退款的訂單的商戶訂單號(hào)

$total_fee?=?$_REQUEST["total_fee"];?//?該訂單的一共支付總額

$refund_fee?=?$_REQUEST["refund_fee"];?//?要退款的錢(qián)數(shù)

$input?=?new?WxPayRefund();

/**?SetOut_trade_no?設(shè)置該訂單的商戶訂單號(hào),憑借這個(gè)唯一確定?*/

$input->SetOut_trade_no($out_trade_no);

/**?SetTotal_fee?設(shè)置訂單的當(dāng)時(shí)支付的總額?*/

$input->SetTotal_fee($total_fee);

/**?SetRefund_fee?設(shè)置要退款多少錢(qián)?*/

$input->SetRefund_fee($refund_fee);

/**?SetOut_refund_no?設(shè)置此次商戶退款的單號(hào),它不是商戶訂單號(hào)?*/

$input->SetOut_refund_no(WxPayConfig::MCHID.date("YmdHis"));

/**?SetOp_user_id?設(shè)置商戶號(hào)?*/

$input->SetOp_user_id(WxPayConfig::MCHID);

/**?發(fā)起退款?*/

$order?=?WxPayApi::refund($input);

/**?在返回的數(shù)組中,我們能夠獲取鍵名return_code?*/

if($order["return_code"]=="SUCCESS"){

//?退款申請(qǐng)成功

}else?if($order["return_code"]=="FAIL"){

//?退款申請(qǐng)失敗

}else{

//?未知狀態(tài)

}

var_dump($order);

}

更多查詢訂單返回值,參考官方文檔

3,退款效果

??一旦申請(qǐng)退款成功,那么該訂單號(hào)對(duì)應(yīng)的用戶便會(huì)在微信客戶端收到退款的憑據(jù),同時(shí)在商家的商戶平臺(tái)也會(huì)有該退款記錄生成。


查詢退款

??對(duì)應(yīng)文件管理中example文件夾下的refundquery.php文件

1,頭文件引入

必須引入的頭文件,以SDK的路徑為例子

require_once"../lib/WxPay.Api.php";

可選的頭文件引入,該頭文件只是微信支付用于記錄操作日志

require_once'log.php';

2,根據(jù)微信訂單號(hào)查詢

?? 微信訂單號(hào)在上面提到,它是微信支付系統(tǒng)自己幫我們生成的,如果要獲知的話,目前我們可以在查詢訂單處獲得,或者直接登錄微信商戶平臺(tái)查看獲得,由微信訂單號(hào)查退款的靈活度不高,下面是例子代碼。

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ù)商戶訂單號(hào)查詢

?? 商戶訂單號(hào)查詢的靈活性高,因?yàn)樯虘粲唵翁?hào)是我們自己生成的,在下訂單生成的時(shí)候,我們?cè)谔幚硐聠谓Y(jié)果確認(rèn)支付成功后,就可以把它存到數(shù)據(jù)庫(kù),查詢的時(shí)候再讀取出來(lái)。

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ù)商戶退款單號(hào)查詢

?? 還記得在退款操作的時(shí)候有這么一句設(shè)置嗎,如下所示,它就是設(shè)置商戶退款單號(hào)的,也是由我們生成,一樣要確保它對(duì)于每條退款的唯一性。

/**?SetOut_refund_no?設(shè)置此次退款的商戶單號(hào),它不是商戶訂單號(hào)?*/

$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ù)退款單號(hào)查詢

?? 退款單號(hào)的生成和微信訂單號(hào)一樣,也是微信支付系統(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;

}

?? 上面的四種退款查詢方式,各有所長(zhǎng),我們可以根據(jù)我們的實(shí)際情況的選擇使用,一般來(lái)說(shuō),微信支付系統(tǒng)幫我們生成的單號(hào)的優(yōu)先級(jí)別是大于我們自己生成的。

官方的查詢返回值文檔


使用環(huán)境

?? 一定要記住,微信支付的網(wǎng)頁(yè)版支付方式只能在微信的內(nèi)置瀏覽器里面進(jìn)行,如果你在電腦瀏覽器打開(kāi)了鏈接支付,它是會(huì)提示你錯(cuò)誤的,那么怎么在電腦使用呢?可以安裝手機(jī)虛擬機(jī),例如Genymotion或者夜神虛擬機(jī),再到手機(jī)虛擬機(jī)里面安裝一個(gè)微信APP,就可以了。

???測(cè)試的時(shí)候,你可以直接通過(guò)發(fā)送測(cè)試鏈接到你的微信里面,再打開(kāi)就行了。


支付憑據(jù)

?? 在每一次的訂單支付成功后,微信都會(huì)發(fā)一條電子支付憑據(jù)給所付款的用戶,支付憑據(jù)中的重要信息有微信訂單號(hào)和商戶訂單號(hào),除此之外還有商品名稱,下單時(shí)間,支付狀態(tài)。其中商戶訂單號(hào)由我們代碼設(shè)置,商品名稱也是,商品名稱對(duì)應(yīng)的是$input->SetBody("test");,下單時(shí)間對(duì)應(yīng)的是$input->SetTime_start(date("YmdHis"));。

?? 支付憑據(jù)可以讓用戶自己恢復(fù)訂單。想象一下,用戶購(gòu)買(mǎi)了商品且支付成功,但是我們自己的數(shù)據(jù)庫(kù)系統(tǒng)卻因?yàn)槠渌麊?wèn)題漏單了,這時(shí)候我們可以在我們的網(wǎng)頁(yè)中設(shè)置一個(gè)訂單恢復(fù)系統(tǒng),由用戶輸入訂單號(hào),然后我們后臺(tái)進(jìn)行訂單查詢,若訂單的確支付成功了,而數(shù)據(jù)庫(kù)沒(méi)對(duì)應(yīng)記錄,那么我們就進(jìn)而恢復(fù)訂單。

?? 微信支付嚴(yán)格要求支付的錢(qián)數(shù)最少是 1 分,在代碼里面少于這個(gè)數(shù)會(huì)支付失敗。

獲取 OpenId

?? 還記得獲取OpenId的時(shí)候,頁(yè)面會(huì)怎樣嗎?沒(méi)錯(cuò),它會(huì)重定向的,為了不丟失我們傳過(guò)去的數(shù)據(jù),最好的方法就是改寫(xiě)。

lib文件夾下的?WxPay.Api.php?函數(shù)

public?function?GetOpenid($userName,$userSex)

{

//通過(guò)code獲得openid

//code在微信服務(wù)處理完成之后重定向時(shí)帶回來(lái)的

if?(!isset($_GET['code']))

{

//?假設(shè)現(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

}

}


確保已下訂單

?? 在處理支付結(jié)果回調(diào)之后,建議再進(jìn)行一次訂單查詢,以確保萬(wàn)無(wú)一失,除此之外,設(shè)置一個(gè)訂單恢復(fù)系統(tǒng)也是可以的,例如下面的例子。

if(isset($tradeId)?&&?$tradeId?!=?"")

{

$input?=?new?WxPayOrderQuery();

$input->SetOut_trade_no($tradeId);?//?設(shè)置好要查詢的訂單

$order?=?WxPayApi::orderQuery($input));?//?進(jìn)行查詢

if($order['err_code_des']?=="order?not?exist"){

//?訂單不存在

}else{

$money?=?$order['total_fee'];?//所付款數(shù),單位分

if($order['trade_state']?=="SUCCESS"){

//支付成功

//數(shù)據(jù)庫(kù)操作

//兩者對(duì)比

//若數(shù)據(jù)庫(kù)中沒(méi)記錄,就恢復(fù)訂單

}else?if($order['trade_state']?=="REFUND"){

//已退款

}else?if($order['trade_state']?=="NOTPAY"){

//用戶還沒(méi)支付

}else?if($order['trade_state']?=="CLOSED"){

//訂單關(guān)閉

}else?if($order['trade_state']?=="REVOKED"){

//已撤銷(xiāo)(刷卡支付)

}else?if($order['trade_state']?=="USERPAYING"){

//用戶支付中

}else?if($order['trade_state']?=="PAYERROR"){

//支付失敗(其他原因,例如銀行返回失敗)

}

}

}


基于SDK修改的Demo

?? 用法:先到 index.php 的上面修改鏈接數(shù)據(jù),再把整個(gè)工程放到你的服務(wù)器,就可以測(cè)試使用了。

PHP版Demo下載


? 下載好之后,在index.php 文件里面配置下路徑信息,如下面所示,當(dāng)然,如果你不使用微信自帶的測(cè)試支付配置,別忘了還要到lib文件夾下修改WxPay.Config.php文件里面的配置信息。


/**?請(qǐng)?jiān)谙旅嬖O(shè)置你服務(wù)器的路徑,默認(rèn)是測(cè)試的,如果您沒(méi)有自己的服務(wù)器,可以使用測(cè)試的?*/

$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";

?>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)于微信支付 生活中的微信支付 目前我們?nèi)粘I钪薪佑|得比較多的線上電子支付方式主要有兩種,一種是支付寶,另一種就...
    積_漸閱讀 4,027評(píng)論 3 26
  • 本文主要和大家分享PHP實(shí)現(xiàn)微信支付流程,最近接觸到一個(gè)項(xiàng)目,涉及到微信支付,搞微信開(kāi)發(fā)這么久以來(lái),還沒(méi)搞過(guò)支付,...
    小流歌_閱讀 1,708評(píng)論 0 0
  • 1.調(diào)用前準(zhǔn)備 1)查看商戶平臺(tái) appid,key,secret,mchid(商戶號(hào)); 獲取地址:https:...
    XuJiaxin_閱讀 1,234評(píng)論 0 1
  • 引言 秋高氣爽,天氣轉(zhuǎn)涼,正是學(xué)習(xí)工作做的好時(shí)候。(~ ̄▽ ̄)~~(~ ̄▽ ̄)~ 我是個(gè)phper最近在寫(xiě)微信支付...
    恩就是這個(gè)名閱讀 8,249評(píng)論 2 15
  • 《我的綜藝評(píng)論》目錄 最近一段時(shí)間,我迷上了浙江衛(wèi)視的綜藝節(jié)目:《演員的誕生》。導(dǎo)師、主持人、Boss團(tuán)和演員們?cè)?..
    瀟湘月明閱讀 1,209評(píng)論 13 18

友情鏈接更多精彩內(nèi)容