前言
首先,微信有四種支付方式骡和,如下圖所示:
其次樊销,PHP能夠?qū)崿F(xiàn)的只有前三種。因?yàn)锳PP支付很顯然是需要iOS和Android來開發(fā)的声诸。而本文針對(duì)的是公眾號(hào)支付的PHP開發(fā)酱讶。
開發(fā)步驟
申請(qǐng)微信公眾號(hào),這里注意必須是服務(wù)號(hào)才可以
開通微信支付彼乌。微信支付需要相關(guān)的企業(yè)資質(zhì)認(rèn)證泻肯。這個(gè)流程快的話1天就能下來,慢也不會(huì)超過3慰照、4天软免。微信的員工效率還是很高的。
-
當(dāng)公眾號(hào)微信支付開通后焚挠,微信會(huì)給你的郵箱中發(fā)一封郵件。這封郵件內(nèi)含有以下內(nèi)容:
Paste_Image.png
你需要登錄商戶平臺(tái)進(jìn)行相關(guān)設(shè)置漓骚,而登陸的賬號(hào)密碼正是郵件中所提供的賬號(hào)密碼蝌衔。
-
登錄商戶平臺(tái)后,第一步需要進(jìn)行銀行賬號(hào)的綁定驗(yàn)證蝌蹂。第二步則需要你設(shè)置API密鑰噩斟。這個(gè)密鑰為32位,是之后調(diào)用微信支付接口的關(guān)鍵參數(shù)之一孤个,如果你不知道怎么生成密匙剃允,可以使用這個(gè)密碼隨機(jī)生成器。密鑰如果忘記可以重新設(shè)置齐鲤,但是相關(guān)的微信支付接口設(shè)置也要記得更改斥废。還有就是在API密鑰設(shè)置界面你還需要下載相關(guān)的證書,證書也是微信支付的必要條件之一给郊,這一點(diǎn)之后會(huì)詳細(xì)說明牡肉。
Paste_Image.png -
到了這一步,商戶平臺(tái)的操作就全部完成了∠牛現(xiàn)在需要返回公眾號(hào)平臺(tái)统锤,設(shè)置測試目錄。因?yàn)槟壳爸皇菧y試階段炭庙,所以可以不設(shè)置正式授權(quán)目錄饲窿,但是注意授權(quán)目錄不能與測試目錄url地址相同。同時(shí)請(qǐng)測試人員將自己的微信號(hào)加入白名單中焕蹄。
Paste_Image.png 到此為止逾雄,所有的前期準(zhǔn)備工作就全部做完了。之后便是真正的代碼開發(fā)階段。為了快速了解微信的支付流程嘲驾,我們可以下載微信支付的官方DEMO淌哟。官方DEMO目前支持三種語言,分別是:JAVA辽故、PHP和.NET C#徒仓。點(diǎn)擊DEMO可以跳轉(zhuǎn)到下載鏈接。
整個(gè)微信公眾號(hào)支付的流程如下:
用戶點(diǎn)擊公眾號(hào)內(nèi)微信商城打開H5的支付頁面
H5頁面通過JS調(diào)用微信支付接口
微信服務(wù)器通過判斷輸入的JSON數(shù)據(jù)誊垢,返回給客戶端相應(yīng)的成功或失敗信息
DEMO
請(qǐng)點(diǎn)擊上面提供的連接掉弛,下載PHP微信支付的DEMO。解壓縮后喂走,我們會(huì)看到如下結(jié)構(gòu)的數(shù)個(gè)PHP文件:
SDK目錄結(jié)構(gòu)
|-- cert
| |-- apiclient_cert.pem ----- 微信證書
| `-- apiclient_key.pem ----- 微信證書
|-- index.php ----- 入口
|-- lib ----- 封裝好的類(一般不需要?jiǎng)樱? | |-- WxPay.Api.php ----- 包括所有微信支付API接口的封裝
| |-- WxPay.Config.php ----- 商戶配置
| |-- WxPay.Data.php ----- 輸入?yún)?shù)封裝
| |-- WxPay.Exception.php ----- 異常類
| `-- WxPay.Notify.php ----- 回調(diào)通知基類
`-- example ----- DEMO
|-- WxPay.JsApiPay.php ----- 微信公眾號(hào)支付類
|-- WxPay.MicroPay.php ----- 刷卡支付類
|-- WxPay.NativePay.php ----- 二維碼支付類
|-- download.php ----- 下載訂單
|-- micropay.php ----- 刷卡支付
|-- native.php ----- 掃碼支付
|-- native_notify.php ----- 回調(diào)處理(二維碼支付)
|-- notify.php ----- 回調(diào)處理
|-- orderquery.php ----- 訂單查詢
|-- qrcode.php ----- 生成二維碼
|-- refund.php ----- 訂單退款
|-- refundquery.php ----- 退款查詢
|-- jsapi.php ----- 公眾號(hào)支付
|-- log.php ----- 日志
`-- phpqrcode ----- 開源二維碼代碼
如果僅僅是為了調(diào)通微信支付接口的話殃饿,我們僅需要修改4個(gè)文件:
- cert文件夾中的兩個(gè)證書替換為我們公眾號(hào)自己的證書
- 修改
WxPay.Config.php
文件中的參數(shù) - 修改
jsapi.php
文件。該文件甚至不修改也能成功調(diào)用接口芋肠,但是我們可以在該文件中設(shè)置具體支付的金額等訂單信息
證書
點(diǎn)擊證書下載公眾號(hào)相關(guān)證書乎芳。
下載下來的壓縮包內(nèi)一共包含有4個(gè)證書:
cert
├── apiclient_cert.p12
├── apiclient_cert.pem
├── apiclient_key.pem
└── rootca.pem
- apiclient_cert.p12是商戶證書文件,除PHP外的開發(fā)均使用此證書文件帖池。
- 商戶如果使用.NET環(huán)境開發(fā)奈惑,請(qǐng)確認(rèn)Framework版本大于2.0,必須在操作系統(tǒng)上雙擊安裝證書apiclient_cert.p12后才能被正常調(diào)用睡汹。
- 商戶證書調(diào)用或安裝都需要使用到密碼肴甸,該密碼的值為微信商戶號(hào)(mch_id)
- PHP開發(fā)環(huán)境請(qǐng)使用商戶證書文件apiclient_cert.pem和apiclient_key.pem ,rootca.pem是CA證書囚巴。
這里因?yàn)槲覀兪褂肞HP開發(fā)原在,所以只需要其中的兩個(gè)證書apiclient_cert.pem
和apiclient_key.pem
。將證書復(fù)制粘貼到DEMO的cert文件夾彤叉,并替換原有文件即可
WxPay.Config.php 參數(shù)配置
代碼中的注釋寫的非常明確庶柿,我們只需要設(shè)置基本信息中的4個(gè)常量即可,其他一般情況下保持默認(rèn)就行秽浇。
<?php
/**
* 配置賬號(hào)信息
*/
class WxPayConfig
{
//=======【基本信息設(shè)置】=====================================
//
/**
* TODO: 修改這里配置為您自己申請(qǐng)的商戶信息
* 微信公眾號(hào)信息配置
*
* APPID:綁定支付的APPID(必須配置澳泵,開戶郵件中可查看)
*
* MCHID:商戶號(hào)(必須配置,開戶郵件中可查看)
*
* KEY:商戶支付密鑰兼呵,參考開戶郵件設(shè)置(必須配置兔辅,登錄商戶平臺(tái)自行設(shè)置)
* 設(shè)置地址:https://pay.weixin.qq.com/index.php/account/api_cert
*
* APPSECRET:公眾帳號(hào)secert(僅JSAPI支付的時(shí)候需要配置, 登錄公眾平臺(tái)击喂,進(jìn)入開發(fā)者中心可設(shè)置)维苔,
* 獲取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
* @var string
*/
const APPID = 'wx426b3015555a46be';
const MCHID = '1225312702';
const KEY = 'e10adc3949ba59abbe56e057f20f883e';
const APPSECRET = '01c6d59a3f9024db6336662ac95c8e74';
//=======【證書路徑設(shè)置】=====================================
/**
* TODO:設(shè)置商戶證書路徑
* 證書路徑,注意應(yīng)該填寫絕對(duì)路徑(僅退款、撤銷訂單時(shí)需要懂昂,可登錄商戶平臺(tái)下載介时,
* API證書下載地址:https://pay.weixin.qq.com/index.php/account/api_cert,下載之前需要安裝商戶操作證書)
* @var path
*/
const SSLCERT_PATH = '../cert/apiclient_cert.pem';
const SSLKEY_PATH = '../cert/apiclient_key.pem';
//=======【curl代理設(shè)置】===================================
/**
* TODO:這里設(shè)置代理機(jī)器,只有需要代理的時(shí)候才設(shè)置沸柔,不需要代理循衰,請(qǐng)?jiān)O(shè)置為0.0.0.0和0
* 本例程通過curl使用HTTP POST方法,此處可修改代理服務(wù)器褐澎,
* 默認(rèn)CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0会钝,此時(shí)不開啟代理(如有需要才設(shè)置)
* @var unknown_type
*/
const CURL_PROXY_HOST = "0.0.0.0";//"10.152.18.220";
const CURL_PROXY_PORT = 0;//8080;
//=======【上報(bào)信息配置】===================================
/**
* TODO:接口調(diào)用上報(bào)等級(jí),默認(rèn)緊錯(cuò)誤上報(bào)(注意:上報(bào)超時(shí)間為【1s】工三,上報(bào)無論成敗【永不拋出異城ㄋ幔】,
* 不會(huì)影響接口調(diào)用流程)俭正,開啟上報(bào)之后奸鬓,方便微信監(jiān)控請(qǐng)求調(diào)用的質(zhì)量,建議至少
* 開啟錯(cuò)誤上報(bào)掸读。
* 上報(bào)等級(jí)串远,0.關(guān)閉上報(bào); 1.僅錯(cuò)誤出錯(cuò)上報(bào); 2.全量上報(bào)
* @var int
*/
const REPORT_LEVENL = 1;
}
修改 jsapi.php文件
jsapi.php
中代碼的工作順序:
- 頁面加載后通過
window.onload = function()
會(huì)自動(dòng)跳轉(zhuǎn)到地址選擇頁面,并觸發(fā)editAddress()
事件 - 選擇住址后頁面返回支付頁面儿惫,同時(shí)彈出警告框顯示剛才選擇的地址
- 點(diǎn)擊支付澡罚,觸發(fā)
callpay()
方法。如果當(dāng)前瀏覽器為微信APP姥闪,則觸發(fā)jsApiCall()
方法調(diào)用微信支付接口 - 最后是在
notify.php
處理回調(diào)通知
注意1:
jsapi.php
原文件中調(diào)用的是官方網(wǎng)址的notify.php
文件。你需要改為調(diào)用自己服務(wù)器上的notify.php
文件砌烁,不然無法再log
文件夾中生成相應(yīng)的日志筐喳。而日志會(huì)包含兩部分:第一條是訂單信息,第二條是訂單信息加一個(gè)額外的trade_state
參數(shù)函喉。trade_state
參數(shù)如果是success
則表示訂單支付成功避归,其他則失敗
注意2:
$input->SetTotal_fee("1")
可以用來設(shè)置支付的金額。但是該金額必須為整數(shù)管呵。這里的數(shù)字1梳毙,代表的是金額1分。如果想將金額設(shè)置為1元捐下,則需要$input->SetTotal_fee("100")
<?php
ini_set('date.timezone','Asia/Shanghai');
//error_reporting(E_ERROR);
require_once "../lib/WxPay.Api.php";
require_once "WxPay.JsApiPay.php";
require_once 'log.php';
//初始化日志
$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);
//打印輸出數(shù)組信息
function printf_info($data)
{
foreach($data as $key=>$value){
echo "<font color='#00ff55;'>$key</font> : $value <br/>";
}
}
//①账锹、獲取用戶openid
$tools = new JsApiPay();
$openId = $tools->GetOpenid();
//②、統(tǒng)一下單
$input = new WxPayUnifiedOrder();
$input->SetBody("創(chuàng)源測試");
$input->SetAttach("測試attach");
$input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));
$input->SetTotal_fee("1");
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag("立減優(yōu)惠");
$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");
$input->SetTrade_type("JSAPI");
$input->SetOpenid($openId);
$order = WxPayApi::unifiedOrder($input);
echo '<font color="#f00"><b>統(tǒng)一下單支付單信息</b></font><br/>';
printf_info($order);
$jsApiParameters = $tools->GetJsApiParameters($order);
//獲取共享收貨地址js函數(shù)參數(shù)
$editAddress = $tools->GetEditAddressParameters();
//③坷襟、在支持成功回調(diào)通知中處理成功之后的事宜奸柬,見 notify.php
/**
* 注意:
* 1、當(dāng)你的回調(diào)地址不可訪問的時(shí)候婴程,回調(diào)通知會(huì)失敗廓奕,可以通過查詢訂單來確認(rèn)支付是否成功
* 2、jsapi支付時(shí)需要填入用戶openid,WxPay.JsApiPay.php中有獲取openid流程 (文檔可以參考微信公眾平臺(tái)“網(wǎng)頁授權(quán)接口”桌粉,
* 參考http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)
*/
?>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>微信支付樣例-支付</title>
<script type="text/javascript">
//調(diào)用微信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 ){
//從事件冒泡開始執(zhí)行蒸绩,也就是從內(nèi)到外,從小到大開始執(zhí)行
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}else{
jsApiCall();
}
}
</script>
<script type="text/javascript">
//獲取共享地址
function editAddress()
{
WeixinJSBridge.invoke(
'editAddress',
<?php echo $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);
}
);
}
//進(jìn)入支付頁面后铃肯,直接跳轉(zhuǎn)地址選擇頁面
window.onload = function(){
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', editAddress, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', editAddress);
document.attachEvent('onWeixinJSBridgeReady', editAddress);
}
}else{
editAddress();
}
};
</script>
</head>
<body>
<br/>
<font color="#9ACD32"><b>該筆訂單支付金額為<span style="color:#f00;font-size:50px">1分</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>