Laravel使用EasyWechat,3分鐘完成微信支付
阿新 • • 發佈:2019-01-08
一.準備工作
1.下載微信官方PHP的SDK,裡面有個rootca.pem要用到,在php.ini裡配置curl.cainfo=你存放rootca.pem的絕對路徑,重啟PHP
2.composer整合easywechat的laravel版本,具體怎麼使用點這裡
2.1
composer require "overtrue/laravel-wechat:~3.0"
2.2
Laravel 應用
- 註冊
ServiceProvider
:
Overtrue\LaravelWechat\ServiceProvider::class,
- 建立配置檔案:
php artisan vendor:publish --provider="Overtrue\LaravelWechat\ServiceProvider"
-
請修改應用根目錄下的
config/wechat.php
中對應的項即可; -
(可選)新增外觀到
config/app.php
中的aliases
部分:
'EasyWeChat' => Overtrue\LaravelWechat\Facade::class,
二.建立控制器WechatController.php
或許有些人看到這裡有一些懵,講一下流程:
1.自己建立一個訂單(就是資料庫裡新建一個訂單記錄,相信誰都會吧。。),這個訂單裡有金額,購買人的user_id,支付狀態status等資訊
2.建立好訂單後,這時我們就要去微信端申請支付了,目的是申請微信的預支付ID,有了預支付ID才能付款。拿訂單id是為了拿到裡面的金額money資訊,而且還要給這個訂單新增一個out_trade_no的欄位資訊,這個out_trade_no的資訊,就是將來微信回撥的時候來找你這個訂單的。
3.支付完成後,微信會一直POST你的回撥地址(注意是post,所以要去中介軟體裡,關掉這個回撥地址的csrf驗證),這個回撥方法就是通過out_trade_no找到這個訂單,然後更改訂單狀態的。
PS:我這裡給出的都是function方法,具體路由還是去routes.php需要自己建哦。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Input; use Auth,Redirect; use Validator; use App\Models\ExampleOrder; //這是我的模型 use EasyWeChat\Foundation\Application; use EasyWeChat\Payment\Order; use EasyWeChat; class WechatController extends Controller { protected function options(){ //選項設定 return [ // 前面的appid什麼的也得保留哦 'app_id' => 'xxxxxxxxx', //你的APPID 'secret' => 'xxxxxxxxx', // AppSecret // 'token' => 'your-token', // Token // 'aes_key' => '', // EncodingAESKey,安全模式下請一定要填寫!!! // ... // payment 'payment' => [ 'merchant_id' => '你的商戶ID,MCH_ID', 'key' => '你的KEY', // 'cert_path' => 'path/to/your/cert.pem', // XXX: 絕對路徑!!!! // 'key_path' => 'path/to/your/key', // XXX: 絕對路徑!!!! 'notify_url' => '你的回撥地址', // 你也可以在下單時單獨設定來想覆蓋它 // 'device_info' => '013467007045764', // 'sub_app_id' => '', // 'sub_merchant_id' => '', // ... ], ]; } //傳入訂單ID即可,我這裡是通過訂單,來查詢該訂單的金額,當然你也可以自定義金額 public function pay(){ $id = Input::get('order_id');//傳入訂單ID $order_find = ExampleOrder::find($id); //找到該訂單 $mch_id = xxxxxxx;//你的MCH_ID $options = $this->options(); $app = new Application($options); $payment = $app->payment; $out_trade_no = $mch_id.date("YmdHis"); //拼一下訂單號 $attributes = [ 'trade_type' => 'APP', // JSAPI,NATIVE,APP... 'body' => '購買CSDN產品', 'detail' => $order_find->info, //我這裡是通過訂單找到商品詳情,你也可以自定義 'out_trade_no' => $out_trade_no, 'total_fee' => $order_find->money*100, //因為是以分為單位,所以訂單裡面的金額乘以100 // 'notify_url' => 'http://xxx.com/order-notify', // 支付結果通知網址,如果不設定則會使用配置裡的預設地址 // 'openid' => '當前使用者的 openid', // trade_type=JSAPI,此引數必傳,使用者在商戶appid下的唯一標識, // ... ]; $order = new Order($attributes); $result = $payment->prepare($order); if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS'){ $order_find->out_trade_no = $out_trade_no; //在這裡更新訂單的支付ID $order_find->save(); // return response()->json(['result'=>$result]); $prepayId = $result->prepay_id; $config = $payment->configForAppPayment($prepayId); return response()->json($config); } } //下面是回撥函式 public function paySuccess(){ $options = $this->options(); $app = new Application($options); $response = $app->payment->handleNotify(function($notify, $successful){ // 使用通知裡的 "微信支付訂單號" 或者 "商戶訂單號" 去自己的資料庫找到訂單 $order = ExampleOrder::where('out_trade_no',$notify->out_trade_no)->first(); if (count($order) == 0) { // 如果訂單不存在 return 'Order not exist.'; // 告訴微信,我已經處理完了,訂單沒找到,別再通知我了 } // 如果訂單存在 // 檢查訂單是否已經更新過支付狀態 if ($order->pay_time) { // 假設訂單欄位“支付時間”不為空代表已經支付 return true; // 已經支付成功了就不再更新了 } // 使用者是否支付成功 if ($successful) { // 不是已經支付狀態則修改為已經支付狀態 $order->pay_time = time(); // 更新支付時間為當前時間 $order->status = 6; //支付成功, } else { // 使用者支付失敗 $order->status = 2; //待付款 } $order->save(); // 儲存訂單 return true; // 返回處理完成 }); } }
大功告成,是不是很EASY呀~
改成微信網頁端支付也很簡單,多傳一個引數open_id,然後把型別改為JSAPI,然後去渲染一個頁面就行
public function pay(){
$id = Input::get('order_id');//傳入訂單ID
$order_find = ExampleOrder::find($id); //找到該訂單
$mch_id = xxxxxxx;//你的MCH_ID
$options = $this->options();
$app = new Application($options);
$payment = $app->payment;
$out_trade_no = $mch_id.date("YmdHis"); //拼一下訂單號
$attributes = [
'trade_type' => 'JSAPI', // JSAPI,NATIVE,APP...
'body' => '購買CSDN產品',
'detail' => $order_find->info, //我這裡是通過訂單找到商品詳情,你也可以自定義
'out_trade_no' => $out_trade_no,
'total_fee' => $order_find->money*100, //因為是以分為單位,所以訂單裡面的金額乘以100
// 'notify_url' => 'http://xxx.com/order-notify', // 支付結果通知網址,如果不設定則會使用配置裡的預設地址
'openid' => '當前使用者的 openid', // trade_type=JSAPI,此引數必傳,使用者在商戶appid下的唯一標識,
// ...
];
$order = new Order($attributes);
$result = $payment->prepare($order);
if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS'){
$order_find->out_trade_no = $out_trade_no; //在這裡更新訂單的支付ID
$order_find->save();
// return response()->json(['result'=>$result]);
$prepayId = $result->prepay_id;
$config = $payment->configForAppPayment($prepayId);
return response()->json($config);
}
}
渲染頁面的方法
public function payOrder(){ //支付訂單頁面
$order_id = Input::get('order_id');
$order = ExampleOrder::find($order_id);
$config = $this->payment($order->pay_id);
$js = EasyWeChat::js();
return view('home.mobile.pay_order')
->withConfig($config)
->withJs($js)
->withOrder($order);
}
然後前端實現
<div>
<h1>支付{{$order->money}}元</h1>
<br>
<input type="button" value="支付" id="pay">
</div>
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
wx.config(<?php echo $js->config(array('chooseWXPay'), false) ?>); //這裡改成true就可以開啟微信js的除錯模式
// wx.ready(function(){
// wx.chooseWXPay({
// timestamp: {{$config["timestamp"]}},
// nonceStr: '{{$config["nonceStr"]}}',
// package: '{{$config["package"]}}',
// signType: '{{$config["signType"]}}',
// paySign: '{{$config["paySign"]}}', // 支付簽名
// success: function (res) {
// // 支付成功後的回撥函式
// window.location.href='/myorder';
// }
// });
// });
$('#pay').click(function(){
wx.chooseWXPay({
timestamp: {{$config['timestamp']}},
nonceStr: '{{$config['nonceStr']}}',
package: '{{$config['package']}}',
signType: '{{$config['signType']}}',
paySign: '{{$config['paySign']}}', // 支付簽名
success: function (res) {
// 支付成功後的回撥函式
window.location.href='/mobile';
}
});
});
</script>