背景知识:
1.首先在vendor下新建一个alipay目录,将下载好的sdk拖入该目录中:
2.在配置文件中配置支付相关信息:
<?php
return [
'alipay'=>[
//应用的ID
'app_id'=>"",
//商户私钥
'merchant_private_key' => "",
//异步通知地址(注意地址不能有get参数)
//例如:http://blog.w.labyun.com.cn/notify.php
'notify_url'=>"",
//同步通知地址(可以有get参数)
//例如:http://blog.w.labyun.com.cn/index.php?r=pay/return
'return_url'=>"",
'charset'=>'UTF-8',
//签名方式
'sign_type'=>'RSA2',
//支付宝网关
'gatewayUrl' => "https://openapi.alipay.com/gateway.do",
//支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
'alipay_public_key' => "",
]
];
关于同步通知和异步通知:由于同步通知有着不稳定性,例如用户在支付完成之后关闭了页面或者服务器网络抖
动等等都会导致同步回调的失败,因此需要异步回调来保证通知结果一定传达到。
3.笔者是在应用目录下新建来一个services目录,并新建了一个Pay类:
4.Pay类中的核心代码如下:
<?php
namespace app\services;
//引入官方demo中封装好的类
require '../vendor/alipay/pagepay/service/AlipayTradeService.php';
require '../vendor/alipay/pagepay/buildermodel/AlipayTradePagePayContentBuilder.php';
class Pay{
//发起支付
public static function alipay(){
//注意在使用类的时候加上"\",因为是通过require的方式引入的类(在公共空间中)
//并且本文件中又声明了app\services命名空间,因此需要加上\显示表明
//使用公共空间中的类
$payRequestBuilder = new \AlipayTradePagePayContentBuilder();
$payRequestBuilder->setBody('描述信息');
$payRequestBuilder->setSubject('主题');
$payRequestBuilder->setTotalAmount('金额');
$payRequestBuilder->setOutTradeNo('订单号');
//加载alipay相关的配置文件
$config=\Yii::$app->params['alipay'];
$aop = new \AlipayTradeService($config);
$response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
echo $response;
\Yii::$app->end();
}
}
5.由于我设置了如下回调参数:
'notify_url'=>'http://blog.w.labyun.com.cn/notify.php',
'return_url'=>'http://blog.w.labyun.com.cn/index.php?r=pay/return',
因此当支付成功时,支付宝的同步回调会调用Pay控制器下的return方法,相应的代码如下:
//PayController控制器中的方法
//同步回调(注意是:GET方式)
public function actionReturn(){
if(\Yii::$app->request->isGet){
$get = \Yii::$app->request->get();
Pay::handleReturn($get);
$this->redirect(['order/my-order']);
\Yii::$app->end();
}
}
//services下Pay类新增handleReturn方法
public static function handleReturn($get){
$config=\Yii::$app->params['alipay'];
$alipaySevice = new \AlipayTradeService($config);
try{
//注意由于同步回调的地址是http://blog.w.labyun.com.cn/index.php?r=pay/return
//因此$get数组中会有'r'=>'pay/return'这一项,但是这一项是多余的需要删除
//否则校验会一直失败
unset($get['r']);
$result = $alipaySevice->check($get);
if(!$result){
\Yii::$app->getSession()->setFlash('Error','验证失败');
return false;
}
//这里可以做自己相应的业务处理
return true;
}catch(\Exception $e){
\Yii::$app->getSession()->setFlash('Error','验证失败');
return false;
}
}
由于支付宝的异步通知地址不能携带任何参数,这也是为什么异步地址不像同步地址那样设置成:http://blog.w.labyun.com.cn/index.php?r=pay/notify 而设置成 http://blog.w.labyun.com.cn/notify.php 的原因。
在web目录下新建notify.php文件,如下:
编写如下代码:
<?php
$url="http://blog.w.labyun.com.cn/index.php?r=pay/notify";
//获得支付宝异步传递的数据(注意是post请求,与同步不同)
$post = $_POST;
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
//将支付宝异步回调的数据传递给指定的url解析
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
$out=curl_exec($ch);
curl_close($ch);
echo $out;
从上面我们可以看出notify.php相当于是一个中间件做了一次转发,接下来是异步通知的核心代码:
//PayController控制器中的方法
//需要关闭yii2默认post方式提交的csrf验证
public $enableCsrfValidation=false;
//只能返回success或者fail,这是支付宝规定的
//success表示成功响应了异步通知,之后支付宝就不会再发送异步通知了
//fail表示未成功响应,支付宝会陆续发送异步通知,具体周期可以百度
public function actionNotify(){
if(\Yii::$app->request->isPost){
$post=\Yii::$app->request->post();
if(Pay::handleNotify($post)){
echo 'success';exit;
}else{
echo 'fail';exit;
}
}
}
//services下的Pay类新增如下方法
public static function handleNotify($post){
$config=\Yii::$app->params['alipay'];
$alipaySevice = new \AlipayTradeService($config);
//校验
$result = $alipaySevice->check($post);
if(!$result){
return false;
}
//订单号
$out_trade_no = $post['out_trade_no'];
//交易状态
$status = $post['trade_status'];
//支付宝交易号
$trade_no = $post['trade_no'];
//支付金额
$amount = $post['total_amount'];
if('TRADE_SUCCESS'===$status||'TRADE_FINISHED'===$status){
try{
//自己的业务处理,例如检查订单的价格和付款的钱是否一致
}catch(\Exception $e){
return false;
}
}
return false;
}
以上就是Yii2集成支付宝的过程。