一.准备工作
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
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>