这次开发中用的是tp5的框架,所以下面代码是相对tp5而言的,先将官方sdk放进框架中 App支付服务端DEMO&SDK
接下来,我创建了三个类,
Alipay : 支付接口对接核心类
Pay: 用于前端接口调用支付类
CallBack : 用于处理异步通知类
代码如下
<?php
namespace app\app_frontend\controller;
use app\common\lib\exception\NException;
use app\common\lib\helper\ConfigHelper;
use app\common\model\ChargeRecordModel;
use app\common\validate\ChargeRecordValidate;
use think\Request;
/**
* @desc app支付接口
*/
class Pay extends Common {
public function pay_order(){
$post_data['pay_type'] = Request::instance()->post('pay_type');
$post_data['body'] = Request::instance()->post('body');
$post_data['money'] = Request::instance()->post('money');
$validate = ChargeRecordValidate::getInstance();
$validate->payOrderRule();
if(!$validate->check($post_data)){
throw new NException( $validate->getError() );
}
//创建订单
$post_data['user_id'] = $this->getCurrentUserId();
$post_data['username'] = $this->getCurrentUserName()['username'];
$out_trade_no = '27201'.rand(1, 20).date('YmdHis',time()); //订单编号
$post_data['out_trade_no'] = $out_trade_no;
ChargeRecordModel::getInstance()->dataAdd($post_data);
switch ($post_data['pay_type']) {
case 'ali';
$ali = new Alipay();
$sign = $ali->alipay($post_data['body'], $post_data['money'], $out_trade_no);
if(!$sign){
throw new NException('支付接口调用失败');
}
return $sign;
break;
case 'wx';
$data['pay_type'] = ConfigHelper::getConfig('charge_record_type_id_wx');
break;
}
}
}
<?php
namespace app\app_frontend\controller;
use Alipay\aop\AopClient;
use Alipay\aop\request\AlipayTradeAppPayRequest;
use app\common\lib\helper\ConfigHelper;
/**
* @desc 支付宝支付第三方接口
*/
class Alipay extends Base {
public function aliPay($body, $money, $out_trade_no){
// $body = '测试支付';
// $out_trade_no = '27201'.rand(1, 20).date('YmdHis',time());
$aop = new AopClient();
$aop->gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
$aop->appId = ConfigHelper::getConfig('pay_Config')['app_id'];
$aop->rsaPrivateKey = ConfigHelper::getConfig('pay_Config')['rsaPrivateKey']; //应用私钥
$aop->format = "json";
$aop->charset = "UTF-8";
$aop->signType = "RSA2";
$aop->alipayrsaPublicKey = ConfigHelper::getConfig('pay_Config')['alipayrsaPublicKey']; //支付宝公钥
$request = new AlipayTradeAppPayRequest();
$arr['body'] = $body;
$arr['subject'] = $body;
$arr['out_trade_no'] = $out_trade_no;
$arr['timeout_express'] = '30m';
// $arr['total_amount'] = 9.00;
$arr['total_amount'] = $money;
$arr['product_code'] = 'QUICK_MSECURITY_PAY';
$json = json_encode($arr);
$request->setNotifyUrl(ConfigHelper::getConfig('pay_Config')['notify_url']);
$request->setBizContent($json);
$response = $aop->sdkExecute($request);
return $response;
}
}
<?php
namespace app\app_frontend\controller;
use Alipay\aop\AopClient;
use app\common\lib\helper\ConfigHelper;
use app\common\model\ChargeRecordModel;
use think\Request;
/**
* @desc 接收支付宝和微信异步通知
*/
class CallBack extends Base{
/**
* @return \think\response\Json
* @desc 支付宝异步通知
*/
public function aliPayBack(){
$content = Request::instance()->getContent();
$content = urldecode($content);
$res = explode('&', $content);
$arr = array();
foreach($res as $key =>$val){
$value = ltrim(strstr($val,'='), "=");
$date = explode('=', $val);
$arr[$date[0]] = $value;
}
$aop = new AopClient;
$aop->alipayrsaPublicKey = ConfigHelper::getConfig('pay_Config')['alipayrsaPublicKey']; //支付宝公钥
$flag = $aop->rsaCheckV1($arr, NULL, "RSA2");
if($flag){
//签名验证成功
if ($arr['trade_status'] == 'TRADE_SUCCESS'){
//交易支付成功
$res = ChargeRecordModel::getInstance()->dataUpdate($arr);
return $res;
}
echo "success";
}else{
//验证失败
echo "fail";
}
}
}
这是主要的代码段,以下是得到的数据,我们只需把这个数据传给前端,由前端去唤起支付即可
下面说一下大家可能埋坑的地方吧
1.支付宝公钥和应用公钥,私钥混淆
配置中我们只需要配置支付宝私钥(就是自己前面创建的那个) 和 支付宝公钥
2.参数错误
有些参数是必填的,结果你没填,这个坑相信很多人都走过,但是没办法只能自己一个一个比对了,官方文档中有说明哪些是必须的,请细心点
3.支付宝网关错误
沙箱测试的网关和正式的网关是不一样的
https://openapi.alipaydev.com/gateway.do //沙箱环境
https://openapi.alipay.com/gateway.do //正式
还有appid搞清楚自己是在沙箱环境还是正式线上
4.关于异步通知的
异步通知的url不需要在开放平台配置,代码中指定就可以了;
接收到的数据先验签,验签成功之后再操作;
注意接收到的数据是否需要urldecode,我当时就是没有decode,结果搞了半天,还是找技术人员解决的,这也是个好办法呀;