525 lines
18 KiB
PHP
525 lines
18 KiB
PHP
<?php
|
||
/**
|
||
* Created by PhpStorm.
|
||
* User: xudong.ding
|
||
* Date: 16/5/19
|
||
* Time: 下午2:09
|
||
*/
|
||
namespace app\common\services\alipay\f2fpay\service;
|
||
use app\common\services\alipay\AlipayJsapiPayService;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayAuthTokenContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayInitializeContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayOrderSettleContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayRoyaltyContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayTradeCancelContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayTradePayContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayTradeQueryContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\builder\AlipayTradeWapPayContentBuilder;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayAuthTokenRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayInitializeRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayRoyaltyRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayTradeCancelRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayTradeOrderSettleRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayTradePayRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayTradePrecreateRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayTradeQueryRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayTradeWapPayRequest;
|
||
use app\common\services\alipay\f2fpay\model\request\AlipayTradeRefundRequest;
|
||
use app\common\services\alipay\f2fpay\model\result\AlipayF2FPayResult;
|
||
use app\common\services\alipay\f2fpay\model\result\AlipayF2FPrecreateResult;
|
||
use app\common\services\alipay\f2fpay\model\result\AlipayF2FQueryResult;
|
||
use app\common\services\alipay\f2fpay\model\result\AlipayF2FRefundResult;
|
||
use app\common\services\alipay\AopClient;
|
||
use Exception;
|
||
|
||
class AlipayTradeService {
|
||
|
||
//支付宝网关地址
|
||
public $gateway_url = "https://openapi.alipay.com/gateway.do";
|
||
|
||
//异步通知回调地址
|
||
public $notify_url;
|
||
|
||
//签名类型
|
||
public $sign_type;
|
||
|
||
//支付宝公钥地址
|
||
public $alipay_public_key;
|
||
|
||
//商户私钥地址
|
||
public $private_key;
|
||
|
||
//应用id
|
||
public $appid;
|
||
|
||
//编码格式
|
||
public $charset = "UTF-8";
|
||
|
||
|
||
public $token = NULL;
|
||
|
||
//重试次数
|
||
private $MaxQueryRetry;
|
||
|
||
//重试间隔
|
||
private $QueryDuration;
|
||
|
||
//返回数据格式
|
||
public $format = "json";
|
||
|
||
|
||
/**
|
||
* AlipayTradeService constructor.
|
||
* @param $alipay_config
|
||
* @throws Exception
|
||
*/
|
||
function __construct($alipay_config){
|
||
$this->gateway_url = $alipay_config['gatewayUrl'];
|
||
$this->appid = $alipay_config['app_id'];
|
||
$this->sign_type = $alipay_config['sign_type'];
|
||
//$this->private_key = $alipay_config['merchant_private_key_file'];
|
||
$this->private_key = $alipay_config['merchant_private_key'];
|
||
//$this->alipay_public_key = $alipay_config['alipay_public_key_file'];
|
||
$this->alipay_public_key = $alipay_config['alipay_public_key'];
|
||
$this->charset = $alipay_config['charset'];
|
||
$this->MaxQueryRetry = $alipay_config['MaxQueryRetry'];
|
||
$this->QueryDuration = $alipay_config['QueryDuration'];
|
||
$this->notify_url = $alipay_config['notify_url'];
|
||
|
||
if(empty($this->appid)||trim($this->appid)==""){
|
||
throw new Exception("appid should not be NULL!");
|
||
}
|
||
if(empty($this->private_key)||trim($this->private_key)==""){
|
||
throw new Exception("private_key should not be NULL!");
|
||
}
|
||
if(empty($this->alipay_public_key)||trim($this->alipay_public_key)==""){
|
||
throw new Exception("alipay_public_key should not be NULL!");
|
||
}
|
||
if(empty($this->charset)||trim($this->charset)==""){
|
||
throw new Exception("charset should not be NULL!");
|
||
}
|
||
if(empty($this->QueryDuration)||trim($this->QueryDuration)==""){
|
||
throw new Exception("QueryDuration should not be NULL!");
|
||
}
|
||
if(empty($this->gateway_url)||trim($this->gateway_url)==""){
|
||
throw new Exception("gateway_url should not be NULL!");
|
||
}
|
||
if(empty($this->MaxQueryRetry)||trim($this->MaxQueryRetry)==""){
|
||
throw new Exception("MaxQueryRetry should not be NULL!");
|
||
}
|
||
if(empty($this->sign_type)||trim($this->sign_type)==""){
|
||
throw new Exception("sign_type should not be NULL");
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* @param $alipay_config
|
||
* @throws Exception
|
||
*/
|
||
function AlipayWapPayService($alipay_config) {
|
||
$this->__construct($alipay_config);
|
||
}
|
||
|
||
/**
|
||
* * 获取授权令牌
|
||
* @param AlipayAuthTokenContentBuilder $req
|
||
* @return string
|
||
*/
|
||
public function authToken($req)
|
||
{
|
||
$bizContent = $req->getBizContent();
|
||
$appAuthToken = $req->getAppAuthToken();
|
||
$request = new AlipayAuthTokenRequest();
|
||
$request->setBizContent($bizContent);
|
||
$response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
|
||
|
||
//获取alipay_trade_pay_response对象数据,方便后续处理
|
||
$response = $response->alipay_open_auth_token_app_response;
|
||
return $response;
|
||
}
|
||
|
||
/**
|
||
* 人脸识别初始化
|
||
* @param AlipayInitializeContentBuilder $req
|
||
* @return string
|
||
* @throws \app\common\exceptions\AppException
|
||
*/
|
||
public function initialize($req)
|
||
{
|
||
$bizContent = $req->getBizContent();
|
||
$appAuthToken = $req->getAppAuthToken();
|
||
$request = new AlipayInitializeRequest();
|
||
$request->setBizContent($bizContent);
|
||
$response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
|
||
|
||
//获取zoloz_authentication_customer_smilepay_initialize_response对象数据,方便后续处理
|
||
$response = $response->zoloz_authentication_customer_smilepay_initialize_response;
|
||
return $response;
|
||
}
|
||
/**
|
||
* 分账关系绑定
|
||
* @param AlipayRoyaltyContentBuilder $req
|
||
* @return string
|
||
* @throws \app\common\exceptions\AppException
|
||
*/
|
||
public function royaltyBind($req)
|
||
{
|
||
$bizContent = $req->getBizContent();
|
||
$appAuthToken = $req->getAppAuthToken();
|
||
$request = new AlipayRoyaltyRequest();
|
||
$request->setBizContent($bizContent);
|
||
$response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
|
||
$response = $response->alipay_trade_royalty_relation_bind_response;
|
||
return $response;
|
||
}
|
||
/**
|
||
* 交易结算接口
|
||
* @param AlipayOrderSettleContentBuilder $req
|
||
* @return string
|
||
* @throws \app\common\exceptions\AppException
|
||
*/
|
||
public function tradeOrderSettle($req)
|
||
{
|
||
$bizContent = $req->getBizContent();
|
||
$appAuthToken = $req->getAppAuthToken();
|
||
$request = new AlipayTradeOrderSettleRequest();
|
||
$request->setBizContent($bizContent);
|
||
$response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
|
||
$response = $response->alipay_trade_order_settle_response;
|
||
return $response;
|
||
}
|
||
|
||
/**
|
||
* WapPay
|
||
* @param AlipayTradeWapPayContentBuilder $builder
|
||
* @param $return_url
|
||
* @param $notify_url
|
||
* @return \app\common\services\alipay\提交表单HTML文本|mixed|string
|
||
* @throws \app\common\exceptions\AppException
|
||
*/
|
||
function wapPay($builder,$return_url,$notify_url) {
|
||
|
||
$biz_content = $builder->getBizContent();
|
||
$appAuthToken = $builder->getAppAuthToken();
|
||
$request = new AlipayTradeWapPayRequest();
|
||
$request->setNotifyUrl($notify_url);
|
||
$request->setReturnUrl($return_url);
|
||
$request->setBizContent($biz_content);
|
||
|
||
// 首先调用支付api
|
||
$response = $this->aopclientRequestPageExecute($request,true, $appAuthToken);
|
||
return $response;
|
||
}
|
||
|
||
/**
|
||
* @param AlipayTradePayContentBuilder $req
|
||
* @return AlipayF2FPayResult|mixed
|
||
*/
|
||
// 当面付2.0条码支付(带轮询逻辑)
|
||
public function barPay($req) {
|
||
|
||
$outTradeNo = $req->getOutTradeNo();
|
||
$bizContent = $req->getBizContent();
|
||
|
||
$appAuthToken = $req->getAppAuthToken();
|
||
|
||
$this->writeLog($bizContent);
|
||
|
||
//echo $bizContent;
|
||
$request = new AlipayTradePayRequest();
|
||
$request->setBizContent($bizContent);
|
||
$response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
|
||
|
||
//获取alipay_trade_pay_response对象数据,方便后续处理
|
||
$response = $response->alipay_trade_pay_response;
|
||
\Log::info('支付宝回调信息', $response);
|
||
|
||
$result = new AlipayF2FPayResult($response);
|
||
|
||
if (!empty($response)&&("10000" == $response->code)) {
|
||
// 支付交易明确成功
|
||
$result->setTradeStatus("SUCCESS");
|
||
|
||
} elseif (!empty($response)&&("10003" == $response->code)) {
|
||
// 返回用户处理中,则轮询查询交易是否成功,如果查询超时,则调用撤销
|
||
$queryContentBuilder = new AlipayTradeQueryContentBuilder();
|
||
$queryContentBuilder->setOutTradeNo($outTradeNo);
|
||
$queryContentBuilder->setAppAuthToken($appAuthToken);
|
||
|
||
$loopQueryResponse = $this->loopQueryResult($queryContentBuilder);
|
||
return $this->checkQueryAndCancel($outTradeNo, $appAuthToken, $result, $loopQueryResponse);
|
||
|
||
} elseif ($this->tradeError($response)) {
|
||
// 系统错误或者网络异常未响应,则查询一次交易,如果交易没有支付成功,则调用撤销
|
||
$queryContentBuilder = new AlipayTradeQueryContentBuilder();
|
||
$queryContentBuilder->setOutTradeNo($outTradeNo);
|
||
$queryContentBuilder->setAppAuthToken($appAuthToken);
|
||
|
||
$queryResponse = $this->query($queryContentBuilder);
|
||
|
||
return $this->checkQueryAndCancel($outTradeNo, $appAuthToken, $result, $queryResponse);
|
||
|
||
} else {
|
||
// 其他情况表明该订单支付明确失败
|
||
$result->setTradeStatus("FAILED");
|
||
}
|
||
|
||
return $result;
|
||
|
||
}
|
||
|
||
// 当面付2.0消费查询
|
||
public function queryTradeResult($req){
|
||
$response = $this->query($req);
|
||
$result = new AlipayF2FQueryResult($response);
|
||
|
||
if($this->querySuccess($response)){
|
||
// 查询返回该订单交易支付成功
|
||
$result->setTradeStatus("SUCCESS");
|
||
|
||
} elseif ($this->tradeError($response)){
|
||
//查询发生异常或无返回,交易状态未知
|
||
$result->setTradeStatus("UNKNOWN");
|
||
} else {
|
||
//其他情况均表明该订单号交易失败
|
||
$result->setTradeStatus("FAILED");
|
||
}
|
||
return $result;
|
||
|
||
}
|
||
|
||
// 当面付2.0消费退款,$req为对象变量
|
||
public function refund($req) {
|
||
$bizContent = $req->getBizContent();
|
||
$this->writeLog($bizContent);
|
||
$request = new AlipayTradeRefundRequest();
|
||
$request->setBizContent ( $bizContent );
|
||
$response = $this->aopclientRequestExecute ( $request , NULL ,$req->getAppAuthToken());
|
||
|
||
$response = $response->alipay_trade_refund_response;
|
||
|
||
$result = new AlipayF2FRefundResult($response);
|
||
if(!empty($response)&&("10000"==$response->code)){
|
||
$result->setTradeStatus("SUCCESS");
|
||
} elseif ($this->tradeError($response)){
|
||
$result->setTradeStatus("UNKNOWN");
|
||
} else {
|
||
$result->setTradeStatus("FAILED");
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
//当面付2.0预下单(生成二维码,带轮询)
|
||
public function qrPay($req) {
|
||
|
||
$bizContent = $req->getBizContent();
|
||
$this->writeLog($bizContent);
|
||
|
||
$request = new AlipayTradePrecreateRequest();
|
||
$request->setBizContent ( $bizContent );
|
||
$request->setNotifyUrl ( $this->notify_url );
|
||
|
||
// 首先调用支付api
|
||
$response = $this->aopclientRequestExecute ( $request, NULL ,$req->getAppAuthToken() );
|
||
$response = $response->alipay_trade_precreate_response;
|
||
|
||
$result = new AlipayF2FPrecreateResult($response);
|
||
if(!empty($response)&&("10000"==$response->code)){
|
||
$result->setTradeStatus("SUCCESS");
|
||
} elseif($this->tradeError($response)){
|
||
$result->setTradeStatus("UNKNOWN");
|
||
} else {
|
||
$result->setTradeStatus("FAILED");
|
||
}
|
||
|
||
return $result;
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* @param AlipayTradeQueryContentBuilder $queryContentBuilder
|
||
* @return mixed
|
||
*/
|
||
public function query($queryContentBuilder) {
|
||
$biz_content = $queryContentBuilder->getBizContent();
|
||
$this->writeLog($biz_content);
|
||
$request = new AlipayTradeQueryRequest();
|
||
$request->setBizContent ( $biz_content );
|
||
$response = $this->aopclientRequestExecute ( $request , NULL, $queryContentBuilder->getAppAuthToken() );
|
||
|
||
|
||
return $response->alipay_trade_query_response;
|
||
}
|
||
|
||
// 轮询查询订单支付结果
|
||
protected function loopQueryResult($queryContentBuilder){
|
||
$queryResult = NULL;
|
||
for ($i=1;$i<$this->MaxQueryRetry;$i++){
|
||
try{
|
||
sleep($this->QueryDuration);
|
||
}catch (Exception $e){
|
||
print $e->getMessage();
|
||
exit();
|
||
}
|
||
|
||
$queryResponse = $this->query($queryContentBuilder);
|
||
if(!empty($queryResponse)){
|
||
if($this->stopQuery($queryResponse)){
|
||
return $queryResponse;
|
||
}
|
||
$queryResult = $queryResponse;
|
||
}
|
||
}
|
||
return $queryResult;
|
||
}
|
||
|
||
// 判断是否停止查询
|
||
protected function stopQuery($response){
|
||
if("10000"==$response->code){
|
||
if("TRADE_FINISHED"==$response->trade_status||
|
||
"TRADE_SUCCESS"==$response->trade_status||
|
||
"TRADE_CLOSED"==$response->trade_status){
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// 根据查询结果queryResponse判断交易是否支付成功,如果支付成功则更新result并返回,如果不成功则调用撤销
|
||
private function checkQueryAndCancel($outTradeNo, $appAuthToken, $result, $queryResponse){
|
||
if($this->querySuccess($queryResponse)){
|
||
// 如果查询返回支付成功,则返回相应结果
|
||
$result->setTradeStatus("SUCCESS");
|
||
$result->setResponse($queryResponse);
|
||
return $result;
|
||
}elseif($this->queryClose($queryResponse)){
|
||
// 如果查询返回交易关闭,标记交易失败
|
||
$result->setTradeStatus("FAILED");
|
||
return $result;
|
||
}
|
||
|
||
// 如果查询结果不为成功,则调用撤销
|
||
$cancelContentBuilder = new AlipayTradeCancelContentBuilder();
|
||
$cancelContentBuilder->setAppAuthToken($appAuthToken);
|
||
$cancelContentBuilder->setOutTradeNo($outTradeNo);
|
||
$cancelResponse = $this->cancel($cancelContentBuilder);
|
||
if($this->tradeError($cancelResponse)){
|
||
// 如果第一次同步撤销返回异常,则标记支付交易为未知状态
|
||
$result->setTradeStatus("UNKNOWN");
|
||
}else{
|
||
// 标记支付为失败,如果撤销未能成功,产生的单边帐由人工处理
|
||
$result->setTradeStatus("FAILED");
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
// 查询返回“支付成功”
|
||
protected function querySuccess($queryResponse){
|
||
return !empty($queryResponse)&&
|
||
$queryResponse->code == "10000"&&
|
||
($queryResponse->trade_status == "TRADE_SUCCESS"||
|
||
$queryResponse->trade_status == "TRADE_FINISHED");
|
||
}
|
||
|
||
// 查询返回“交易关闭”
|
||
protected function queryClose($queryResponse){
|
||
return !empty($queryResponse)&&
|
||
$queryResponse->code == "10000"&&
|
||
$queryResponse->trade_status == "TRADE_CLOSED";
|
||
}
|
||
|
||
// 交易异常,或发生系统错误
|
||
protected function tradeError($response){
|
||
return empty($response)||
|
||
$response->code == "20000";
|
||
}
|
||
|
||
|
||
public function cancel($cancelContentBuilder) {
|
||
$biz_content= $cancelContentBuilder->getBizContent();
|
||
$this->writeLog($biz_content);
|
||
$request = new AlipayTradeCancelRequest();
|
||
$request->setBizContent ( $biz_content );
|
||
$response = $this->aopclientRequestExecute ( $request ,NULL ,$cancelContentBuilder->getAppAuthToken() );
|
||
return $response->alipay_trade_cancel_response;
|
||
}
|
||
|
||
/**
|
||
* 使用SDK执行提交页面接口请求
|
||
* @param $request
|
||
* @param string $token
|
||
* @param string $appAuthToken
|
||
* @return string $result
|
||
* @throws \app\common\exceptions\AppException
|
||
*/
|
||
private function aopclientRequestExecute($request, $token = NULL, $appAuthToken = NULL) {
|
||
|
||
$aop = new AopClient ();
|
||
$aop->gatewayUrl = $this->gateway_url;
|
||
$aop->appId = $this->appid;
|
||
$aop->signType = $this->sign_type;
|
||
//$aop->rsaPrivateKeyFilePath = $this->private_key;
|
||
$aop->rsaPrivateKey = $this->private_key;
|
||
//$aop->alipayPublicKey = $this->alipay_public_key;
|
||
$aop->alipayrsaPublicKey = $this->alipay_public_key;
|
||
$aop->apiVersion = "1.0";
|
||
$aop->postCharset = $this->charset;
|
||
$aop->format=$this->format;
|
||
// 开启页面信息输出
|
||
$aop->debugInfo=true;
|
||
$result = $aop->execute($request,$token,$appAuthToken);
|
||
$result = json_decode($result);
|
||
|
||
//打开后,将url形式请求报文写入log文件
|
||
//$this->writeLog("response: ".var_export($result,true));
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* @param $request
|
||
* @param bool $ispage
|
||
* @param null $appAuthToken
|
||
* @return \app\common\services\alipay\提交表单HTML文本|mixed|string
|
||
* @throws \app\common\exceptions\AppException
|
||
*/
|
||
private function aopclientRequestPageExecute($request,$ispage=false, $appAuthToken = NULL) {
|
||
|
||
$aop = new AopClient ();
|
||
$aop->gatewayUrl = $this->gateway_url;
|
||
$aop->appId = $this->appid;
|
||
$aop->rsaPrivateKey = $this->private_key;
|
||
$aop->alipayrsaPublicKey = $this->alipay_public_key;
|
||
$aop->apiVersion ="1.0";
|
||
$aop->postCharset = $this->charset;
|
||
$aop->format= $this->format;
|
||
$aop->signType=$this->sign_type;
|
||
if($ispage) {
|
||
$result = $aop->pageExecute($request,'GET', $appAuthToken);
|
||
} else {
|
||
$result = $aop->Execute($request);
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
function writeLog($text) {
|
||
// $text=iconv("GBK", "UTF-8//IGNORE", $text);
|
||
//$text = characet ( $text );
|
||
file_put_contents ( "log/log.txt", date ( "Y-m-d H:i:s" ) . " " . $text . "\r\n", FILE_APPEND );
|
||
}
|
||
|
||
/** *利用google api生成二维码图片
|
||
* $content:二维码内容参数
|
||
* $size:生成二维码的尺寸,宽度和高度的值
|
||
* $lev:可选参数,纠错等级
|
||
* $margin:生成的二维码离边框的距离
|
||
*/
|
||
function create_erweima($content, $size = '200', $lev = 'L', $margin= '0') {
|
||
$content = urlencode($content);
|
||
$image = '<img src="http://chart.apis.google.com/chart?chs='.$size.'x'.$size.'&cht=qr&chld='.$lev.'|'.$margin.'&chl='.$content.'" widht="'.$size.'" height="'.$size.'" />';
|
||
return $image;
|
||
}
|
||
|
||
} |