第一個博客
寫這個的原因是因爲以前配置過很多環境,過一段就會忘掉,當需要在用的時候就要重新花費好久來搞。這詞做這個關於微信支付的項目,在如何使用php的laravel框架加入微信掃碼支付的功能上花了太久的時間,不希望自己以後再踩同樣的坑,也希望可以幫到別人。第一次寫博客,可能寫不清楚,請大家見諒。
說明:本文說的是微信支付的第二種模式
準備工作:
- 在微信支付官網的SDK下載中下載對應的php代碼
- 配置好laravel需要的基本環境
- 獲得支付所需的配置信息:appid、cmhid、key,獲取方式在sdk中有說明
/**
* TODO: 修改這裏配置爲您自己申請的商戶信息
* 微信公衆號信息配置
*
* APPID:綁定支付的APPID(必須配置,開戶郵件中可查看)
*
* MCHID:商戶號(必須配置,開戶郵件中可查看)
*
* KEY:商戶支付密鑰,參考開戶郵件設置(必須配置,登錄商戶平臺自行設置)
* 設置地址:https://pay.weixin.qq.com/index.php/account/api_cert
*
* APPSECRET:公衆帳號secert(僅JSAPI支付的時候需要配置, 登錄公衆平臺,進入開發者中心可設置),
* 獲取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
* @var string
*/
const APPID = 'wx8dce35348ad73e3';
const MCHID = '131547990';
const KEY = '5f980c0c9548833f3260e82dc2ce33';
const APPSECRET = '01c6d59a3f9024db6336662ac95c8e74';
配置當然就是寫在sdk的這個配置文件中:WxPay.config.php,就是上面貼的那段代碼。
重要的坑
sdk中的所有文件引用都是 相對路徑,但是laravel的所有相對路徑都是以單入口文件public/index.php爲當前文件的,所以 要把sdk中所有的require_once 以及log的目錄地址,都換成以public/index.php爲當前目錄的相對路徑。比如:我把整個sdk放在了項目路徑app/Http/下面,和controller並立(不要吐槽我),那麼我的sdk中的相對路徑就是 require_once "../app/Http/WxPaySDK/lib/WxPay.Exception.php";
這樣的。其中lib是對應sdk中的lib,當然也有是example的,根據需要換掉就行。換掉所有的相對路徑後,就可以開始做支付功能了。
順便吐槽,本來想用namespace 和 use 來處理的 可是微信的sdk中一個文件裏好幾個類,還有log這樣的很容易衝突的類名,最後懶得處理,就還用require引用了。
生成二維碼連接
在sdk中,負責生成二維碼的是native.php這個文件,其中的有用代碼是:
//模式一
/**
* 流程:
* 1、組裝包含支付信息的url,生成二維碼
* 2、用戶掃描二維碼,進行支付
* 3、確定支付之後,微信服務器會回調預先配置的回調地址,在【微信開放平臺-微信支付-支付配置】中進行配置
* 4、在接到回調通知之後,用戶進行統一下單支付,並返回支付信息以完成支付(見:native_notify.php)
* 5、支付完成之後,微信服務器會通知支付成功
* 6、在支付成功通知中需要查單確認是否真正支付成功(見:notify.php)
*/
$notify = new NativePay();
$url1 = $notify->GetPrePayUrl("123456789");
//模式二
/**
* 流程:
* 1、調用統一下單,取得code_url,生成二維碼
* 2、用戶掃描二維碼,進行支付
* 3、支付完成之後,微信服務器會通知支付成功
* 4、在支付成功通知中需要查單確認是否真正支付成功(見:notify.php)
*/
$input = new WxPayUnifiedOrder();
$input->SetBody("test");
$input->SetAttach("ljm");
$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("test");
$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");
$input->SetTrade_type("NATIVE");
$input->SetProduct_id("123456789");
$result = $notify->GetPayUrl($input);
// var_dump($result);die;
$url2 = $result["code_url"];
注意模式一的第一行new的對象,在模式二中最後有用,我用的是模式二的方式。以上代碼,其實是用來生成一個$result,這是sdk根據設置的參數生成好的,參數裏SetBody是掃碼支付時最上面的標題,SetOut_trade_no是設置商戶訂單號(支付結果會帶回來,以便對相應訂單狀態做更改)。SetTotal_fee是支付金額,單位是分。其他具體參數,參看統一訂單(不太需要了)。
知道了怎麼配置參數,那接下來就需要把這些代碼拷貝到controller的某處,做一個接口來調用,接口傳入商家要支付的商品的那個訂單號(不是微信的支付號,是商家自己的訂單編號),然後用某種方式生成out_trade_no就行了。不廢話,貼代碼
/**
*GET localhost/youge/blog/public/File/getQrcode
*
*獲取付款二維碼url的參數
*
*/
require_once "../app/Http/WxPaySDK/lib/WxPay.Api.php";
require_once "../app/Http/WxPaySDK/example/WxPay.NativePay.php";
//注意引入文件的路徑
public function getQrcode(Request $request)
{
$file_id = $request->input('file_id', '');
$out_trade_no = WxPayConfig::MCHID . date("YmdHis") . $file_id;
//我的out_trade_no是這麼做的 由於我的file_id(就是我的商家訂單)是唯一的,所以無論如何這個結果都是唯一的
$notify = new NativePay();
$input = new WxPayUnifiedOrder();
$input->SetBody("這裏寫這是什麼服務項目的支付");
$input->SetAttach("ljm");
$input->SetOut_trade_no($out_trade_no);
$input->SetTotal_fee("600");
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag("test");
$input->SetNotify_url("http://127.0.0.1/youge/blog/public/index.php/payNotify");
//這裏設置支付成功後的回調接口,不能有參數。還有,這裏的127.0.0.1是收不到微信後臺發出的回調函數的,只能用服務器來測試了。
$input->SetTrade_type("NATIVE");
$input->SetProduct_id("123456789");
$result = $notify->GetPayUrl($input);
$url = $result["code_url"];
$file = File::where('id', $file_id)->first();
if (!empty($file)) {
$file->out_trade_no = $out_trade_no;
$file->save();
}
//這段是把out_trade_no和要處理的訂單關聯起來
return "http://paysdk.weixin.qq.com/example/qrcode.php?data=" . $url;
}
最後的return是一個微信的連接,data後面的值是sdk生成的一小串字符串,用來生成二維碼。把這個return的完整字符串放入HTML的img標籤,就是一個二維碼了。
支付通知獲取
根據官網的說明 點這裏,支付成功後,微信會發送POST的請求,到上面你設置的通知回調接口,在sdk中,回調接口是example/notify.php
但是在laravel中,接口要放在controller中,所以我們新建一個controller,寫個route文件接口,從這個controller中調用這個notify.php,怎麼調用呢。
首先,把notify中的最下面的幾行和最上面的幾行不在函數中的代碼
$logHandler= new CLogFileHandler("../app/Http/WxPaySDK/logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);
Log::DEBUG("begin notify");
$notify = new PayNotifyCallBack();
$notify->Handle(false);
然後寫個public static function notifyReceive()放進去,這樣就可以從controller中直接調用它了
PayNotifyCallBack::notifyReceive();
//PayNotifyCallBack 是notify.php中的類名
至此,應該說掃碼支付的模式二就實現了。
此外,在notify.php的回調函數中可以把自己業務的邏輯代碼放在這裏
public function NotifyProcess($data, &$msg)
{
Log::DEBUG("call back:" . json_encode($data));
$notfiyOutput = array();
if(!array_key_exists("transaction_id", $data)){
$msg = "輸入參數不正確";
return false;
}
//查詢訂單,判斷訂單真實性
if(!$this->Queryorder($data["transaction_id"])){
$msg = "訂單查詢失敗";
return false;
}
//這裏以下////////////////////////
$file = File::where('out_trade_no', $data['out_trade_no'])->first();
if (!empty($file)) {
$file->status = File::FILE_PAYED;
$file->save();
}
//這裏以上///////////////////////就是在這個return true之前,表示驗證沒有問題,支付成功時執行這部分業務邏輯
return true;
}