电脑网站支付封装。以下是alipay.php的内容
<?php
/**
* @user : wy
* @date : 2018年7月23日
* @desc : 支付宝支付对接
**/
namespace Alipay;
use think\Exception;
class Alipay {
private $_config = [];
public function __construct(){
require_once 'config.php';
$this->_config = $config;
//注册自动加载方法
spl_autoload_register([__CLASS__,'loadFile']);
}
/**
* @param unknown $className
* @return boolean
* @desc:自动加载类文件
*/
private function loadFile($className){
$fileName = $className.'.php';
$currentPath = dirname(__FILE__).'/';
$pagepayPath = $currentPath.'./pagepay/';
$buildermodelPath = $currentPath.'pagepay/buildermodel/';
$servicePath = $currentPath.'pagepay/service/';
if(file_exists($pagepayPath.$fileName)){
require_once $pagepayPath.$fileName;
}elseif (file_exists($buildermodelPath.$fileName)){
require_once $buildermodelPath.$fileName;
}elseif (file_exists($servicePath.$fileName)){
require_once $servicePath.$fileName;
}else{
return false;
}
return true;
}
/**
* @param unknown $data
* 参数名|是否必填|描述
* out_trade_no|是|支付单号
* subject|是|订单名称
* total|是|支付金额
* body|否|商品描述
*
* @desc:
*/
public function unifiedOrder($data){
$this->setLog($data,'undifiedOrder-param:');
//商户订单号,商户网站订单系统中唯一支付单号,必填
$outTradeNo = trim($data['out_trade_no']);
//订单名称,必填
$subject = trim($data['subject']);
//付款金额,必填
$totalAmount = trim($data['total']);
//商品描述,可空
$body = isset($data['body'])?trim($data['body']):'';
//构造参数
$payRequestBuilder = new \AlipayTradePagePayContentBuilder();
$payRequestBuilder->setBody($body);
$payRequestBuilder->setSubject($subject);
$payRequestBuilder->setTotalAmount($totalAmount);
$payRequestBuilder->setOutTradeNo($outTradeNo);
$aop = new \AlipayTradeService($this->_config);
/**
* pagePay 电脑网站支付请求
* @param $builder 业务参数,使用buildmodel中的对象生成。
* @param $return_url 同步跳转地址,公网可以访问
* @param $notify_url 异步通知地址,公网可以访问
* @return $response 支付宝返回的信息
*/
$response = $aop->pagePay($payRequestBuilder,$this->_config['return_url'],$this->_config['notify_url']);
}
/**
* @param unknown $data
* @param boolean $sign 是否验签
* @throws Exception
* @return
* @desc:支付宝回调数据检测
*/
public function notify($data,$sign = false){
try {
if($sign){
//验证签名
$alipay = new \AlipayTradeService($this->_config);
$result = $alipay->check($data);
if(!$result) throw new Exception('验签失败');
}
//验证接口调用的app_id是否一致
$appid = $data['app_id'];
if($appid != $this->_config['app_id']){
throw new Exception('app_id不一致');
}
//订单查询支付结果
$queryData = ['transaction_id'=>$data['trade_no'],'out_trade_no'=>$data['out_trade_no']];
$result = $this->orderQuery($queryData);
if(!$result['state']) throw new Exception('订单查询结果:'.$result['msg']);
if($result['data']['total_amount'] != $data['total_amount']) throw new Exception('回调金额与订单查询金额不等');
return callback(true);
} catch (Exception $e) {
return callback(false,$e->getMessage());
}
}
/**
* 订单查询-支付宝
* @param unknown $data
* 参数名|是否必填|描述
* transaction_id|二选一|支付宝交易号
* out_trade_no|二选一|商户支付单号
* @desc:
*/
public function orderQuery($data){
try {
$this->setLog($data,'orderQuery-param:');
if(empty($data)) throw new Exception('参数为空');
//构造参数
$RequestBuilder = new \AlipayTradeQueryContentBuilder();
if(isset($data['transaction_id']) && !empty($data['transaction_id'])){
//支付宝交易号
$RequestBuilder->setTradeNo($data['transaction_id']);
}elseif(isset($data['out_trade_no']) && !empty($data['out_trade_no'])){
$RequestBuilder->setOutTradeNo($out_trade_no);
}else{
throw new Exception('交易单号与支付单号不能同时为空');
}
$aop = new \AlipayTradeService($this->_config);
/**
* alipay.trade.query (统一收单线下交易查询)
* @param $builder 业务参数,使用buildmodel中的对象生成。
* @return $response 支付宝返回的信息
*/
$response = $aop->Query($RequestBuilder);
$response = json_decode(json_encode($response),true);
$this->setLog($response,'orderQuery-response:');
if($response['code'] != '10000'){
throw new Exception($response['msg']);
}
return callback(true,'',$response);
} catch (Exception $e) {
$this->setLog($e->getMessage(),'orderQuery-error:');
return callback(false,$e->getMessage());
}
}
/**
* @param unknown $data
* 参数名|是否必填|描述
* transaction_id|二选一|支付宝交易号
* out_trade_no|二选一|商户支付单号
* refund_fee|是|退款总额,单位元
* out_refund_no|是|平台退款单号,
* @return 退款返回结果
{
"code": "10000",
"msg": "Success",
"buyer_logon_id": "nqy***@sandbox.com",
"buyer_user_id": "2088102175437002",
"fund_change": "N",
"gmt_refund_pay": "2018-07-24 16:22:23",
"out_trade_no": "610585760482976360",
"refund_fee": "30.00",
"send_back_fee": "0.00",
"trade_no": "2018072421001004000200631548"
}
* @desc:退款
*/
public function refund($data){
try {
$this->setLog($data,'refund-param:');
//参数构造
$RequestBuilder = new \AlipayTradeRefundContentBuilder();
if(isset($data['transaction_id']) && !empty($data['transaction_id'])){
$RequestBuilder->setTradeNo($data['transaction_id']);
}elseif(isset($data['out_trade_no']) && !empty($data['out_trade_no'])){
$RequestBuilder->setOutTradeNo($data['out_trade_no']);
}else{
throw new Exception('支付单号和支付宝交易号不能同时为空');
}
//退款总额,单位元
$RequestBuilder->setRefundAmount($data['refund_fee']);
//退款单号
$RequestBuilder->setOutRequestNo($data['out_refund_no']);
$aop = new \AlipayTradeService($this->_config);
$response = $aop->Refund($RequestBuilder);
$this->setLog($response,'refund-response:');
$response = json_decode(json_encode($response),true);
if($response['code'] != '10000'){
throw new Exception($response['msg']);
}
return callback(true,'退款申请成功',$response);
} catch (Exception $e) {
$this->setLog($e->getMessage(),'refund-error:');
return callback(false,$e->getMessage());
}
}
/**
* @param unknown $data
* 参数|是否必填|描述
* transaction_id|二选一|支付宝交易号
* out_trade_no|二选一|商户支付单号
* out_refund_no|是|平台退款单号,
* @return
* 返回参数
{
"code": "10000",
"msg": "Success",
"out_request_no": "2018072421001004000200631548",
"out_trade_no": "610585760482976360",
"refund_amount": "30.00",
"total_amount": "30.00",
"trade_no": "2018072421001004000200631548"
}
* @desc:退款查询
*/
public function refundQuery($data){
try {
$this->setLog($data,'refundQuery-param:');
$RequestBuilder = new \AlipayTradeFastpayRefundQueryContentBuilder();
if(isset($data['transaction_id']) && !empty($data['transaction_id'])){
$RequestBuilder->setTradeNo($data['transaction_id']);
}elseif(isset($data['out_trade_no']) && !empty($data['out_trade_no'])){
$RequestBuilder->setOutTradeNo($data['out_trade_no']);
}else{
throw new Exception('支付单号和支付宝交易号不能同时为空');
}
$RequestBuilder->setOutRequestNo($data['out_refund_no']);
$aop = new \AlipayTradeService($this->_config);
$response = $aop->refundQuery($RequestBuilder);
$this->setLog($response,'refundQuery-response:');
$response = json_decode(json_encode($response),true);
if($response['alipay_trade_fastpay_refund_query_response']['code'] != '10000'){
throw new Exception($response['alipay_trade_fastpay_refund_query_response']['msg']);
}
return callback(true,'',$response['alipay_trade_fastpay_refund_query_response']);
} catch (Exception $e) {
$this->setLog($e->getMessage(),'refundQuery-error:');
return callback(false,$e->getMessage());
}
}
/**
* @param unknown $content
* @param string $prefix
* @desc:记录日志
*/
public function setLog($contents,$prefix = ""){
$path = RUNTIME_PATH.'/log/alipay/';
setLog($contents,$prefix,$path);
}
}
以下是notify.php中的异步通知处理
/**
*
* @desc:支付宝支付结果同步回调
*/
public function alipayReturn(){
$param = $this->request->param();
$result = $this->dealNotify($param,false,1);
if($result['state']){
//支付成功
$this->redirect(url('index/buy/payok',['pay_sn'=>$param['out_trade_no']]));
}else{
//支付失败
$this->redirect(url(''));
}
}
/**
* @param unknown $data
* @param boolean $sign 是否验签
* @param boolean $type 1-同步处理 2-异步处理
* @desc:处理支付宝同步通知和异步通知数据
*/
private function dealNotify($data,$sign = false,$type = '2'){
try {
$typeDesc = ($type == 1)?'return':'notify';
$prefix = 'alipay-'.$typeDesc;
$alipay = new Alipay();
$alipay->setLog($data,$prefix."-param:");
//1-alipay数据验证
$result = $alipay->notify($data,$sign);
if(!$result['state']) throw new Exception($result['msg']);
//2-检测支付金额是否一致
$pay = new Pay();
$result = $pay->checkPayTotal($data['out_trade_no'], $data['total_amount']);
$alipay->setLog('账单实际金额:'.$result['data']['total'].",实际支付金额:".$data['total_amount']);
if(!$result['state']) throw new Exception($result['msg']);
//修改订单相关数据
$this->purOrderUpdate($data['out_trade_no'], $data['trade_no'],$data['total_amount']);
$alipay->setLog('success',$prefix."-end:");
return callback(true);
} catch (Exception $e) {
$alipay->setLog($e->getMessage(),$prefix."-end-error:");
return callback(false,$e->getMessage());
}
}
/**
*
* @desc:支付宝支付结果异步回调(包括部分退款异步通知。全额退款没有异步通知)
*/
public function alipayNotify(){
try {
if(!$this->request->isPost()) throw new Exception('非法请求');
$param = $this->request->param();
if(isset($param['refund_fee'])){
$alipay = new Alipay();
$alipay->setLog($param,'refund-notify:param:');
//退款状态修改
$this->_updateRefund($param['out_biz_no'],1);
$alipay->setLog('success','refund-notify-end:');
}else{
//支付结果异步通知
$result = $this->dealNotify($param);
if(!$result['state']) throw new Exception($result['msg']);
}
return 'success';
} catch (Exception $e) {
$alipay->setLog($e->getMessage(),'notify-end-error:');
return 'fail';
}
}
注意:申请退款后,部分退款才会有异步通知,全额退款不会触发退款结果的异步通知。退款结果的异步通知路径跟支付结果异步回调地址一致。退款回调参数中多refund_fee这个参数。退款回调参数如下:
{
"gmt_create": "2018-07-26 09:45:05",
"charset": "UTF-8",
"gmt_payment": "2018-07-26 09:45:24",
"notify_time": "2018-07-26 09:47:37",
"subject": "",
"gmt_refund": "2018-07-26 09:47:36.849",
"sign": "drGhgTe9Ly60hN0fgXlrcu+xSH5+cx3ZJsNDKyCFDsRhHhD2eqANbaqXKgPMOBdUon3aYWa7Akv55lel2AZWSPDpJsDeG04V2Xd7Dr4GB\/dtIDAcrZ6Bb7a3+HZFnc8q+VxKZAJmEMKgMNX86Evv55FxtsGByqi53UASa4OQ2\/yhayjPBlcujUXhzLBb1sVDttGS5UZx7pDGYPlOpUaLnymxAcbPCHcOZY1Gt0MjYd4m\/AUKs1gByyaJdrX34++gi7chlSUruSFzwlRmVyI2eLEdb23tISvOox21wCMq6YdBYcUNlmZ2Mt6itaEItGWx8D9\/VJYdj1bLjnCSKn8f1A==",
"out_biz_no": "R201807260946373238851",
"buyer_id": "2088102175437002",
"version": "1.0",
"notify_id": "00a13b3a2640169502675254b25572ag02",
"notify_type": "trade_status_sync",
"out_trade_no": "",
"total_amount": "340.00",
"trade_status": "TRADE_SUCCESS",
"refund_fee": "240.00",
"trade_no": "2018072621001004000200641757",
"auth_app_id": "",
"app_id": "",
"sign_type": "RSA2",
"seller_id": ""
}