AlipayTradeService.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: xudong.ding
  5. * Date: 16/5/19
  6. * Time: 下午2:09
  7. */
  8. namespace app\common\services\alipay\f2fpay\service;
  9. use app\common\services\alipay\AlipayJsapiPayService;
  10. use app\common\services\alipay\f2fpay\model\builder\AlipayAuthTokenContentBuilder;
  11. use app\common\services\alipay\f2fpay\model\builder\AlipayInitializeContentBuilder;
  12. use app\common\services\alipay\f2fpay\model\builder\AlipayOrderSettleContentBuilder;
  13. use app\common\services\alipay\f2fpay\model\builder\AlipayRoyaltyContentBuilder;
  14. use app\common\services\alipay\f2fpay\model\builder\AlipayTradeCancelContentBuilder;
  15. use app\common\services\alipay\f2fpay\model\builder\AlipayTradePayContentBuilder;
  16. use app\common\services\alipay\f2fpay\model\builder\AlipayTradeQueryContentBuilder;
  17. use app\common\services\alipay\f2fpay\model\builder\AlipayTradeWapPayContentBuilder;
  18. use app\common\services\alipay\f2fpay\model\request\AlipayAuthTokenRequest;
  19. use app\common\services\alipay\f2fpay\model\request\AlipayInitializeRequest;
  20. use app\common\services\alipay\f2fpay\model\request\AlipayRoyaltyRequest;
  21. use app\common\services\alipay\f2fpay\model\request\AlipayTradeCancelRequest;
  22. use app\common\services\alipay\f2fpay\model\request\AlipayTradeOrderSettleRequest;
  23. use app\common\services\alipay\f2fpay\model\request\AlipayTradePayRequest;
  24. use app\common\services\alipay\f2fpay\model\request\AlipayTradePrecreateRequest;
  25. use app\common\services\alipay\f2fpay\model\request\AlipayTradeQueryRequest;
  26. use app\common\services\alipay\f2fpay\model\request\AlipayTradeWapPayRequest;
  27. use app\common\services\alipay\f2fpay\model\request\AlipayTradeRefundRequest;
  28. use app\common\services\alipay\f2fpay\model\result\AlipayF2FPayResult;
  29. use app\common\services\alipay\f2fpay\model\result\AlipayF2FPrecreateResult;
  30. use app\common\services\alipay\f2fpay\model\result\AlipayF2FQueryResult;
  31. use app\common\services\alipay\f2fpay\model\result\AlipayF2FRefundResult;
  32. use app\common\services\alipay\AopClient;
  33. use Exception;
  34. class AlipayTradeService {
  35. //支付宝网关地址
  36. public $gateway_url = "https://openapi.alipay.com/gateway.do";
  37. //异步通知回调地址
  38. public $notify_url;
  39. //签名类型
  40. public $sign_type;
  41. //支付宝公钥地址
  42. public $alipay_public_key;
  43. //商户私钥地址
  44. public $private_key;
  45. //应用id
  46. public $appid;
  47. //编码格式
  48. public $charset = "UTF-8";
  49. public $token = NULL;
  50. //重试次数
  51. private $MaxQueryRetry;
  52. //重试间隔
  53. private $QueryDuration;
  54. //返回数据格式
  55. public $format = "json";
  56. /**
  57. * AlipayTradeService constructor.
  58. * @param $alipay_config
  59. * @throws Exception
  60. */
  61. function __construct($alipay_config){
  62. $this->gateway_url = $alipay_config['gatewayUrl'];
  63. $this->appid = $alipay_config['app_id'];
  64. $this->sign_type = $alipay_config['sign_type'];
  65. //$this->private_key = $alipay_config['merchant_private_key_file'];
  66. $this->private_key = $alipay_config['merchant_private_key'];
  67. //$this->alipay_public_key = $alipay_config['alipay_public_key_file'];
  68. $this->alipay_public_key = $alipay_config['alipay_public_key'];
  69. $this->charset = $alipay_config['charset'];
  70. $this->MaxQueryRetry = $alipay_config['MaxQueryRetry'];
  71. $this->QueryDuration = $alipay_config['QueryDuration'];
  72. $this->notify_url = $alipay_config['notify_url'];
  73. if(empty($this->appid)||trim($this->appid)==""){
  74. throw new Exception("appid should not be NULL!");
  75. }
  76. if(empty($this->private_key)||trim($this->private_key)==""){
  77. throw new Exception("private_key should not be NULL!");
  78. }
  79. if(empty($this->alipay_public_key)||trim($this->alipay_public_key)==""){
  80. throw new Exception("alipay_public_key should not be NULL!");
  81. }
  82. if(empty($this->charset)||trim($this->charset)==""){
  83. throw new Exception("charset should not be NULL!");
  84. }
  85. if(empty($this->QueryDuration)||trim($this->QueryDuration)==""){
  86. throw new Exception("QueryDuration should not be NULL!");
  87. }
  88. if(empty($this->gateway_url)||trim($this->gateway_url)==""){
  89. throw new Exception("gateway_url should not be NULL!");
  90. }
  91. if(empty($this->MaxQueryRetry)||trim($this->MaxQueryRetry)==""){
  92. throw new Exception("MaxQueryRetry should not be NULL!");
  93. }
  94. if(empty($this->sign_type)||trim($this->sign_type)==""){
  95. throw new Exception("sign_type should not be NULL");
  96. }
  97. }
  98. /**
  99. * @param $alipay_config
  100. * @throws Exception
  101. */
  102. function AlipayWapPayService($alipay_config) {
  103. $this->__construct($alipay_config);
  104. }
  105. /**
  106. * * 获取授权令牌
  107. * @param AlipayAuthTokenContentBuilder $req
  108. * @return string
  109. */
  110. public function authToken($req)
  111. {
  112. $bizContent = $req->getBizContent();
  113. $appAuthToken = $req->getAppAuthToken();
  114. $request = new AlipayAuthTokenRequest();
  115. $request->setBizContent($bizContent);
  116. $response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
  117. //获取alipay_trade_pay_response对象数据,方便后续处理
  118. $response = $response->alipay_open_auth_token_app_response;
  119. return $response;
  120. }
  121. /**
  122. * 人脸识别初始化
  123. * @param AlipayInitializeContentBuilder $req
  124. * @return string
  125. * @throws \app\common\exceptions\AppException
  126. */
  127. public function initialize($req)
  128. {
  129. $bizContent = $req->getBizContent();
  130. $appAuthToken = $req->getAppAuthToken();
  131. $request = new AlipayInitializeRequest();
  132. $request->setBizContent($bizContent);
  133. $response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
  134. //获取zoloz_authentication_customer_smilepay_initialize_response对象数据,方便后续处理
  135. $response = $response->zoloz_authentication_customer_smilepay_initialize_response;
  136. return $response;
  137. }
  138. /**
  139. * 分账关系绑定
  140. * @param AlipayRoyaltyContentBuilder $req
  141. * @return string
  142. * @throws \app\common\exceptions\AppException
  143. */
  144. public function royaltyBind($req)
  145. {
  146. $bizContent = $req->getBizContent();
  147. $appAuthToken = $req->getAppAuthToken();
  148. $request = new AlipayRoyaltyRequest();
  149. $request->setBizContent($bizContent);
  150. $response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
  151. $response = $response->alipay_trade_royalty_relation_bind_response;
  152. return $response;
  153. }
  154. /**
  155. * 交易结算接口
  156. * @param AlipayOrderSettleContentBuilder $req
  157. * @return string
  158. * @throws \app\common\exceptions\AppException
  159. */
  160. public function tradeOrderSettle($req)
  161. {
  162. $bizContent = $req->getBizContent();
  163. $appAuthToken = $req->getAppAuthToken();
  164. $request = new AlipayTradeOrderSettleRequest();
  165. $request->setBizContent($bizContent);
  166. $response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
  167. $response = $response->alipay_trade_order_settle_response;
  168. return $response;
  169. }
  170. /**
  171. * WapPay
  172. * @param AlipayTradeWapPayContentBuilder $builder
  173. * @param $return_url
  174. * @param $notify_url
  175. * @return \app\common\services\alipay\提交表单HTML文本|mixed|string
  176. * @throws \app\common\exceptions\AppException
  177. */
  178. function wapPay($builder,$return_url,$notify_url) {
  179. $biz_content = $builder->getBizContent();
  180. $appAuthToken = $builder->getAppAuthToken();
  181. $request = new AlipayTradeWapPayRequest();
  182. $request->setNotifyUrl($notify_url);
  183. $request->setReturnUrl($return_url);
  184. $request->setBizContent($biz_content);
  185. // 首先调用支付api
  186. $response = $this->aopclientRequestPageExecute($request,true, $appAuthToken);
  187. return $response;
  188. }
  189. /**
  190. * @param AlipayTradePayContentBuilder $req
  191. * @return AlipayF2FPayResult|mixed
  192. */
  193. // 当面付2.0条码支付(带轮询逻辑)
  194. public function barPay($req) {
  195. $outTradeNo = $req->getOutTradeNo();
  196. $bizContent = $req->getBizContent();
  197. $appAuthToken = $req->getAppAuthToken();
  198. $this->writeLog($bizContent);
  199. //echo $bizContent;
  200. $request = new AlipayTradePayRequest();
  201. $request->setBizContent($bizContent);
  202. $response = $this->aopclientRequestExecute($request, NULL, $appAuthToken);
  203. //获取alipay_trade_pay_response对象数据,方便后续处理
  204. $response = $response->alipay_trade_pay_response;
  205. \Log::info('支付宝回调信息', $response);
  206. $result = new AlipayF2FPayResult($response);
  207. if (!empty($response)&&("10000" == $response->code)) {
  208. // 支付交易明确成功
  209. $result->setTradeStatus("SUCCESS");
  210. } elseif (!empty($response)&&("10003" == $response->code)) {
  211. // 返回用户处理中,则轮询查询交易是否成功,如果查询超时,则调用撤销
  212. $queryContentBuilder = new AlipayTradeQueryContentBuilder();
  213. $queryContentBuilder->setOutTradeNo($outTradeNo);
  214. $queryContentBuilder->setAppAuthToken($appAuthToken);
  215. $loopQueryResponse = $this->loopQueryResult($queryContentBuilder);
  216. return $this->checkQueryAndCancel($outTradeNo, $appAuthToken, $result, $loopQueryResponse);
  217. } elseif ($this->tradeError($response)) {
  218. // 系统错误或者网络异常未响应,则查询一次交易,如果交易没有支付成功,则调用撤销
  219. $queryContentBuilder = new AlipayTradeQueryContentBuilder();
  220. $queryContentBuilder->setOutTradeNo($outTradeNo);
  221. $queryContentBuilder->setAppAuthToken($appAuthToken);
  222. $queryResponse = $this->query($queryContentBuilder);
  223. return $this->checkQueryAndCancel($outTradeNo, $appAuthToken, $result, $queryResponse);
  224. } else {
  225. // 其他情况表明该订单支付明确失败
  226. $result->setTradeStatus("FAILED");
  227. }
  228. return $result;
  229. }
  230. // 当面付2.0消费查询
  231. public function queryTradeResult($req){
  232. $response = $this->query($req);
  233. $result = new AlipayF2FQueryResult($response);
  234. if($this->querySuccess($response)){
  235. // 查询返回该订单交易支付成功
  236. $result->setTradeStatus("SUCCESS");
  237. } elseif ($this->tradeError($response)){
  238. //查询发生异常或无返回,交易状态未知
  239. $result->setTradeStatus("UNKNOWN");
  240. } else {
  241. //其他情况均表明该订单号交易失败
  242. $result->setTradeStatus("FAILED");
  243. }
  244. return $result;
  245. }
  246. // 当面付2.0消费退款,$req为对象变量
  247. public function refund($req) {
  248. $bizContent = $req->getBizContent();
  249. $this->writeLog($bizContent);
  250. $request = new AlipayTradeRefundRequest();
  251. $request->setBizContent ( $bizContent );
  252. $response = $this->aopclientRequestExecute ( $request , NULL ,$req->getAppAuthToken());
  253. $response = $response->alipay_trade_refund_response;
  254. $result = new AlipayF2FRefundResult($response);
  255. if(!empty($response)&&("10000"==$response->code)){
  256. $result->setTradeStatus("SUCCESS");
  257. } elseif ($this->tradeError($response)){
  258. $result->setTradeStatus("UNKNOWN");
  259. } else {
  260. $result->setTradeStatus("FAILED");
  261. }
  262. return $result;
  263. }
  264. //当面付2.0预下单(生成二维码,带轮询)
  265. public function qrPay($req) {
  266. $bizContent = $req->getBizContent();
  267. $this->writeLog($bizContent);
  268. $request = new AlipayTradePrecreateRequest();
  269. $request->setBizContent ( $bizContent );
  270. $request->setNotifyUrl ( $this->notify_url );
  271. // 首先调用支付api
  272. $response = $this->aopclientRequestExecute ( $request, NULL ,$req->getAppAuthToken() );
  273. $response = $response->alipay_trade_precreate_response;
  274. $result = new AlipayF2FPrecreateResult($response);
  275. if(!empty($response)&&("10000"==$response->code)){
  276. $result->setTradeStatus("SUCCESS");
  277. } elseif($this->tradeError($response)){
  278. $result->setTradeStatus("UNKNOWN");
  279. } else {
  280. $result->setTradeStatus("FAILED");
  281. }
  282. return $result;
  283. }
  284. /**
  285. * @param AlipayTradeQueryContentBuilder $queryContentBuilder
  286. * @return mixed
  287. */
  288. public function query($queryContentBuilder) {
  289. $biz_content = $queryContentBuilder->getBizContent();
  290. $this->writeLog($biz_content);
  291. $request = new AlipayTradeQueryRequest();
  292. $request->setBizContent ( $biz_content );
  293. $response = $this->aopclientRequestExecute ( $request , NULL, $queryContentBuilder->getAppAuthToken() );
  294. return $response->alipay_trade_query_response;
  295. }
  296. // 轮询查询订单支付结果
  297. protected function loopQueryResult($queryContentBuilder){
  298. $queryResult = NULL;
  299. for ($i=1;$i<$this->MaxQueryRetry;$i++){
  300. try{
  301. sleep($this->QueryDuration);
  302. }catch (Exception $e){
  303. print $e->getMessage();
  304. exit();
  305. }
  306. $queryResponse = $this->query($queryContentBuilder);
  307. if(!empty($queryResponse)){
  308. if($this->stopQuery($queryResponse)){
  309. return $queryResponse;
  310. }
  311. $queryResult = $queryResponse;
  312. }
  313. }
  314. return $queryResult;
  315. }
  316. // 判断是否停止查询
  317. protected function stopQuery($response){
  318. if("10000"==$response->code){
  319. if("TRADE_FINISHED"==$response->trade_status||
  320. "TRADE_SUCCESS"==$response->trade_status||
  321. "TRADE_CLOSED"==$response->trade_status){
  322. return true;
  323. }
  324. }
  325. return false;
  326. }
  327. // 根据查询结果queryResponse判断交易是否支付成功,如果支付成功则更新result并返回,如果不成功则调用撤销
  328. private function checkQueryAndCancel($outTradeNo, $appAuthToken, $result, $queryResponse){
  329. if($this->querySuccess($queryResponse)){
  330. // 如果查询返回支付成功,则返回相应结果
  331. $result->setTradeStatus("SUCCESS");
  332. $result->setResponse($queryResponse);
  333. return $result;
  334. }elseif($this->queryClose($queryResponse)){
  335. // 如果查询返回交易关闭,标记交易失败
  336. $result->setTradeStatus("FAILED");
  337. return $result;
  338. }
  339. // 如果查询结果不为成功,则调用撤销
  340. $cancelContentBuilder = new AlipayTradeCancelContentBuilder();
  341. $cancelContentBuilder->setAppAuthToken($appAuthToken);
  342. $cancelContentBuilder->setOutTradeNo($outTradeNo);
  343. $cancelResponse = $this->cancel($cancelContentBuilder);
  344. if($this->tradeError($cancelResponse)){
  345. // 如果第一次同步撤销返回异常,则标记支付交易为未知状态
  346. $result->setTradeStatus("UNKNOWN");
  347. }else{
  348. // 标记支付为失败,如果撤销未能成功,产生的单边帐由人工处理
  349. $result->setTradeStatus("FAILED");
  350. }
  351. return $result;
  352. }
  353. // 查询返回“支付成功”
  354. protected function querySuccess($queryResponse){
  355. return !empty($queryResponse)&&
  356. $queryResponse->code == "10000"&&
  357. ($queryResponse->trade_status == "TRADE_SUCCESS"||
  358. $queryResponse->trade_status == "TRADE_FINISHED");
  359. }
  360. // 查询返回“交易关闭”
  361. protected function queryClose($queryResponse){
  362. return !empty($queryResponse)&&
  363. $queryResponse->code == "10000"&&
  364. $queryResponse->trade_status == "TRADE_CLOSED";
  365. }
  366. // 交易异常,或发生系统错误
  367. protected function tradeError($response){
  368. return empty($response)||
  369. $response->code == "20000";
  370. }
  371. public function cancel($cancelContentBuilder) {
  372. $biz_content= $cancelContentBuilder->getBizContent();
  373. $this->writeLog($biz_content);
  374. $request = new AlipayTradeCancelRequest();
  375. $request->setBizContent ( $biz_content );
  376. $response = $this->aopclientRequestExecute ( $request ,NULL ,$cancelContentBuilder->getAppAuthToken() );
  377. return $response->alipay_trade_cancel_response;
  378. }
  379. /**
  380. * 使用SDK执行提交页面接口请求
  381. * @param $request
  382. * @param string $token
  383. * @param string $appAuthToken
  384. * @return string $result
  385. * @throws \app\common\exceptions\AppException
  386. */
  387. private function aopclientRequestExecute($request, $token = NULL, $appAuthToken = NULL) {
  388. $aop = new AopClient ();
  389. $aop->gatewayUrl = $this->gateway_url;
  390. $aop->appId = $this->appid;
  391. $aop->signType = $this->sign_type;
  392. //$aop->rsaPrivateKeyFilePath = $this->private_key;
  393. $aop->rsaPrivateKey = $this->private_key;
  394. //$aop->alipayPublicKey = $this->alipay_public_key;
  395. $aop->alipayrsaPublicKey = $this->alipay_public_key;
  396. $aop->apiVersion = "1.0";
  397. $aop->postCharset = $this->charset;
  398. $aop->format=$this->format;
  399. // 开启页面信息输出
  400. $aop->debugInfo=true;
  401. $result = $aop->execute($request,$token,$appAuthToken);
  402. $result = json_decode($result);
  403. //打开后,将url形式请求报文写入log文件
  404. //$this->writeLog("response: ".var_export($result,true));
  405. return $result;
  406. }
  407. /**
  408. * @param $request
  409. * @param bool $ispage
  410. * @param null $appAuthToken
  411. * @return \app\common\services\alipay\提交表单HTML文本|mixed|string
  412. * @throws \app\common\exceptions\AppException
  413. */
  414. private function aopclientRequestPageExecute($request,$ispage=false, $appAuthToken = NULL) {
  415. $aop = new AopClient ();
  416. $aop->gatewayUrl = $this->gateway_url;
  417. $aop->appId = $this->appid;
  418. $aop->rsaPrivateKey = $this->private_key;
  419. $aop->alipayrsaPublicKey = $this->alipay_public_key;
  420. $aop->apiVersion ="1.0";
  421. $aop->postCharset = $this->charset;
  422. $aop->format= $this->format;
  423. $aop->signType=$this->sign_type;
  424. if($ispage) {
  425. $result = $aop->pageExecute($request,'GET', $appAuthToken);
  426. } else {
  427. $result = $aop->Execute($request);
  428. }
  429. return $result;
  430. }
  431. function writeLog($text) {
  432. // $text=iconv("GBK", "UTF-8//IGNORE", $text);
  433. //$text = characet ( $text );
  434. file_put_contents ( "log/log.txt", date ( "Y-m-d H:i:s" ) . " " . $text . "\r\n", FILE_APPEND );
  435. }
  436. /** *利用google api生成二维码图片
  437. * $content:二维码内容参数
  438. * $size:生成二维码的尺寸,宽度和高度的值
  439. * $lev:可选参数,纠错等级
  440. * $margin:生成的二维码离边框的距离
  441. */
  442. function create_erweima($content, $size = '200', $lev = 'L', $margin= '0') {
  443. $content = urlencode($content);
  444. $image = '<img src="http://chart.apis.google.com/chart?chs='.$size.'x'.$size.'&amp;cht=qr&chld='.$lev.'|'.$margin.'&amp;chl='.$content.'" widht="'.$size.'" height="'.$size.'" />';
  445. return $image;
  446. }
  447. }