TP5.1接入支付宝实现网页/APP支付完整请求回调流程(沙箱环境)

随声附和 提交于 2020-04-08 08:54:21

  目前互联网项目如果涉及到第三方支付模块,那么支付宝/微信无非是最好的选择,此文先以支付宝为例讲解,想了解微信支付的可以看我之后的文章,当然支付也分很多种形式,比如扫码付、当面付、声波付、调用APP付,网页直接付等等。但最常用的形式还是服务端+APP+调用支付宝APP或服务端+网页扫码/调用支付宝APP/直接支付,所以接下来我就以ThinkPHP5.1作为服务端从接入SDK到实现支付请求以及回调业务流程完整的操作讲解一下,虽然我用的是TP5.1但是TP5和TP5.1在此使用过程中没有太大的区别,无非TP5.1使用了一些TP5没有的静态方法而已,所以使用TP5的也可以通过本文无障碍的接入使用。至于使用沙箱的原因是考虑到有些没有接触具体项目而且自己也没有申请商户资格的用户,使用沙箱环境便不用考虑这些,直接使用支付宝提供的沙箱号接入测试即可,当然如果你是将上线的项目只需将APPID等信息改为项目需求的即可正常使用,接下来进入正文。

目录
一、接入支付宝SDK
1.下载SDK放入框架
2.为SDK所需类添加命名空间
3.控制器中引用
二、沙箱环境
1.获取商家/用户沙箱账号
2.配置公钥,私钥
三、APP支付(服务端提供串码供APP调用支付宝APP)
四、网页支付(服务端调用API生成付款页并添加回调方法完成业务流程)
1.生成订单调用API生成付款页
2.通过回调方法验签并处理业务逻辑
一、接入支付宝SDK
1.下载SDK放入框架
首先第一步当然是下载支付宝提供的SDK,这里我们选择支付宝的服务端PHP SDK下载即可(点我进入下载页)

下载得到的是一个压缩包,接下来我们打开TP5.1框架,在extend文件夹下新建一个Alipay(文件夹命名随意,但要和之后命名空间对应,本文全程以Alipay为例)的文件夹,然后将压缩包内容全部解压进Alipay中,效果如下:


2.为SDK所需类添加命名空间
先整理一下之后所需要的SDK类

生成供APP使用的支付串码:AlipayTradeAppPayRequest.php、AopClient.php
网页支付:AlipayTradePagePayRequest、AopClient.php
异步通知回调验签:AopClient.php
综上我们需要使用SDK中这三个类,首先找到这三个类,手动为其添加命名空间
AopClient.php位置:extend/Alipay/aop/AopClient.php
AlipayTradeAppPayRequest.php位置:extend/Alipay/aop/request/AlipayTradeAppPayRequest.php
AlipayTradePagePayRequest.php位置:extend/Alipay/aop/request/AlipayTradePagePayRequest

分别为其添加命名空间如下
AopClient.php需添加此命名空间namespace Alipay\aop;
AlipayTradeAppPayRequest.php和AlipayTradePagePayRequest需添加命名空间namespace Alipay\aop\request;

3.控制器中引用
为所需类库文件添加好命名空间后就可以在控制器引用了,只需要简单的使用use即可,如下:


二、沙箱环境
1.获取商家/用户沙箱账号
首先使用你的支付宝账号登录支付宝开放平台然后点击进入我的开放平台,顶部导航栏开发中心中选择研发服务,即可跳转到沙箱页面。

在沙箱页面我们可以看到支付宝为我们生成的相应信息和账号,之后我们使用SDK时要使用这些相应信息:

记得下载沙箱版支付宝,可以用于之后测试支付,余额可以自己充值。


2.配置公钥,私钥
SDK中主要需要的是四个参数,分别是APPID、支付宝网关、应用私钥,支付宝公钥。
想要得到支付宝公钥需要先生成一个私钥然后将对应的公钥提交才会获取支付宝公钥,生成私钥需要我们下载支付宝的支付宝开放平台开发助手。打开后生成即可,记得选择非JAVA适用

将公钥复制到沙箱页面提交即可获取支付宝公钥,至此我们就得到了之后所需的私钥和支付宝公钥。

三、APP支付(服务端提供串码供APP调用支付宝APP)
具体环境和参数得到后使用起来就很简单了,只需要将需要的参数写入然后调用SDK提供的api即可生成可供APP端调起支付宝所需的串码。

public function appAlipay()
{
$aop = new AopClient;
$aop->gatewayUrl = "https://openapi.alipaydev.com/gateway.do"; //网关地址要使用沙箱网关alipaydev
$aop->appId = "填写你自己的APPID";
$aop->rsaPrivateKey = '填写你自己的应用私钥';
$aop->format = "json";
$aop->postCharset = "UTF-8";
$aop->signType = "RSA2";
$aop->alipayrsaPublicKey = '填写沙箱页面给你的支付宝公钥';
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
$request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数,沙箱环境的product_code只能是FAST_INSTANT_TRADE_PAY
$info = json_encode(['body'=>'商品简述','subject'=>'商品名','out_trade_no'=>md5(time()),
'timeout_express'=>'30m','total_amount'=>'5000','product_code'=>'FAST_INSTANT_TRADE_PAY'],JSON_UNESCAPED_UNICODE);
$request->setNotifyUrl("请填写你的异步回调通知地址,需要无任何验证即可访问");
$request->setBizContent($info);
//这里和普通的接口调用不同,使用的是sdkExecute
$response = $aop->sdkExecute($request);
//htmlspecialchars是为了输出到页面时防止被浏览器将关键参数html转义,实际打印到日志以及http传输不会有这个问题
echo htmlspecialchars($response);//就是orderString 可以直接给客户端请求,无需再做处理。
}

这里要注意的是如果你的PHP版本>7的话AopClient中一行代码会报错,这是因为语法被废弃需要我们手动修改,打开AopClient.php定位到420行(因人而异)

/**
* 建立请求,以表单HTML形式构造(默认)
* @param $para_temp 请求参数数组
* @return 提交表单HTML文本
*/
protected function buildRequestForm($para_temp) {

$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->gatewayUrl."?charset=".trim($this->postCharset)."' method='POST'>";
foreach ($para_temp as $key => $val) { //修改的是这一行,将被PHP7废弃的each语法改为foreach即可
if (false === $this->checkEmpty($val)) {
//$val = $this->characet($val, $this->postCharset);
$val = str_replace("'","&apos;",$val);
//$val = str_replace("\"","&quot;",$val);
$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
}
}

然后我们只需要将这个方法作为API提供给APP端即可让APP端开发人员使用此串码调用起支付宝进行支付,至于支付后的异步回调通知验签处理业务逻辑等放入网页支付中说明。

四、网页支付(服务端调用API生成付款页并添加回调方法完成业务流程)
1.生成订单调用API生成付款页
public function webAlipay()
{
$aop = new AopClient;
$aop->gatewayUrl = "https://openapi.alipaydev.com/gateway.do"; //网关地址要使用沙箱网关alipaydev
$aop->appId = "填写你的APPID";
$aop->rsaPrivateKey = '填写你自己的应用私钥';
$aop->format = "json";
$aop->apiVersion = '1.0';
$aop->postCharset='UTF-8';
$aop->signType = "RSA2";
$aop->alipayrsaPublicKey = '填写沙箱页面给你的支付宝公钥';
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
$request = new AlipayTradePagePayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数
$info = json_encode(['body'=>'商品简述','subject'=>'商品名','out_trade_no'=>md5(time()),
'timeout_express'=>'30m','total_amount'=>'5000.00','product_code'=>'FAST_INSTANT_TRADE_PAY'],JSON_UNESCAPED_UNICODE);
$request->setBizContent($info);
$request->setReturnUrl("请填写你的付款后页面返回地址");
$request->setNotifyUrl("请填写你的异步回调通知地址,需要无任何验证即可访问");
$result = $aop->pageExecute($request);
return $result;
}

这里要注意的是如果你的PHP版本>7的话AopClient中一行代码会报错,这是因为语法被废弃需要我们手动修改。请参考APP支付中,我已说明过如何修改。

2.通过回调方法验签并处理业务逻辑
这里的returnback和notify分别是之前填的返回地址和回调地址所调用的方法:
$request->setReturnUrl(“请填写你的付款后页面返回地址”);
$request->setNotifyUrl(“请填写你的异步回调通知地址,需要无任何验证即可访问”);

//异步通知回调
public function notify()
{
try{
$info = Request::param();
$aop = new AopClient;
$aop->alipayrsaPublicKey = '填写你的支付宝公钥';
$flag = $aop->rsaCheckV1($info,NULL,"RSA2"); //验签
if(!$flag)
{
Log::write('验签失败','ALIPAY_THORW');
}
else if($info['trade_status']=='TRADE_SUCCESS') //支付状态
{
if(!Db::table('order')->where('ordernum','=',$info['out_trade_no'])->find())
{
$insertData = ['create_time'=>time(),'update_time'=>time(),'goodname'=>$info['subject'],'ordernum'=>$info['out_trade_no'],
'alipaynum'=>$info['trade_no'],'total_money'=>$info['total_amount'],'status'=>1];
Db::table('order')->insert($insertData);}
}
}
}
catch (Exception $e)
{
Log::write($e->getMessage(),'ALIPAY_THORW');
}
}

//网页付款成功后返回页面
public function returnback()
{
echo "<h1>支付成功<h1>";
halt(Request::param());
}

在异步通知回调中首先要验签,通过后再根据trade_status的状态来处理相应的业务逻辑,这里注意支付宝会在支付成功后24小时内分时通知,不一定只发一次,所以要在此方法中做相应判断避免重复处理同一订单。
————————————————
版权声明:本文为CSDN博主「SolKnight」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38280150/java/article/details/100100271

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!