AliPayNotify.Class.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. /**
  3. * 支付宝支付通知类
  4. * Created by PhpStorm.
  5. * User: phperstar
  6. * Date: 2019/11/28
  7. * Time: 5:00 PM
  8. */
  9. namespace JinDouYun\Controller\Common;
  10. use Mall\Framework\Core\StatusCode;
  11. use JinDouYun\Controller\BaseController;
  12. use JinDouYun\Model\Order\MOrder;
  13. use JinDouYun\Model\Market\MVipCard;
  14. class AliPayNotify extends BaseController
  15. {
  16. //使用文件读取文件格式,请只传递该值(支付宝公钥文件方式)
  17. private $alipayPublicKey = null;
  18. //使用读取字符串格式,请只传递该值(支付宝公钥字符串方式)
  19. private $alipayrsaPublicKey;
  20. public function __construct($isCheckAcl = false, $isMustLogin = false, $checkToken = false)
  21. {
  22. parent::__construct($isCheckAcl, $isMustLogin, $checkToken);
  23. $this->alipayrsaPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnb7lP7zW4CR94yAgljj4yNc4j7NyWd7oGhCB5/0PBcg9QQ91bj4dAUMFyu/QNJK2ez2jqVUoDeB13ueOVxwBfINwLm4k6Kw5PnDkSJBuGyE9bUQDEPOpm3/UZmza86uvm5xce54gyn+9OqH0Z4iWt4CuVAG4IwwAaVVhNLwxJQAiKWHYtNzWHtvNQV81CFEJinnV8u1sh40ex0FZlnjcyvSwzOILVqEsLYUaXpp0XDnk9j1yC+sVSAjezIQUplptWuGBnMiA2Q5nZtryNm+BaaVV0wNCs5wTUr4hfvxcw4UitkNEwJTVKp2JUYMgNV8JuX+y/MEIASN8nMiL+rDzYwIDAQAB';
  24. }
  25. /**
  26. * 支付宝回调处理方法
  27. * 官网文档地址:https://docs.open.alipay.com/204/105301/
  28. * @throws \Exception
  29. */
  30. public function notify()
  31. {
  32. $flag = $this->rsaCheckV1($_POST, NULL, "RSA2");
  33. //验签
  34. if($flag){
  35. //处理业务,并从$_POST中提取需要的参数内容
  36. if($_POST['trade_status'] == 'TRADE_SUCCESS' || $_POST['trade_status'] == 'TRADE_FINISHED'){ // 处理交易完成或者支付成功的通知
  37. file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'回调数据'.var_export($_POST,true).PHP_EOL,FILE_APPEND);
  38. $passback_params = urldecode($_POST['passback_params']); // 回传参数
  39. $attach = explode('|',$passback_params);
  40. if(empty($attach)){
  41. exit('fail');
  42. }
  43. $enterpriseId = $attach[0];
  44. unset($attach[0]);
  45. $userCentId = $attach[1];
  46. unset($attach[1]);
  47. $allOrdersId = array_values($attach);
  48. if (strpos( $_POST['out_trade_no'],'tmp') === false || substr($_POST['out_trade_no'],0,3) == 'tmp') {
  49. $updateOrderData = [
  50. 'outerTradeNo' => $_POST['trade_no'], // 该交易在支付宝系统中的交易流水号
  51. 'payType' => StatusCode::$payType['aliPay'],
  52. 'payStatus' => StatusCode::$standard,
  53. 'orderStatus' => StatusCode::$orderStatus['waitDelivery'],
  54. 'payTime' => strtotime($_POST['gmt_payment']), // 支付完成时间
  55. 'total_fee'=> $_POST['total_amount'],//支付金额
  56. 'pay_way'=>StatusCode::$payType['aliPay']
  57. ];
  58. $objMOrder = new MOrder($userCentId, $enterpriseId);
  59. if(strpos( $_POST['out_trade_no'],'tmp') === false){
  60. $result = $objMOrder->updateOrderPayData($updateOrderData, ['id'=>$allOrdersId,'no'=>$_POST['out_trade_no']],true);
  61. }else{
  62. $result = $objMOrder->updateOrderPayData($updateOrderData, ['id'=>$allOrdersId,'outerTradeNo'=>$_POST['out_trade_no']],true);
  63. }
  64. if(!$result->isSuccess()){
  65. file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'修改订单状态失败'.var_export($result->getData(),true).PHP_EOL,FILE_APPEND);
  66. exit('fail');
  67. }else{
  68. exit('success');// 响应success表示业务处理成功,告知支付宝无需在异步通知
  69. }
  70. }
  71. //处理会员卡订单
  72. if (strpos( $_POST['out_trade_no'],'tmp') !== false && substr($_POST['out_trade_no'],0,3) == 'vip') {
  73. $vipOrderData = [
  74. 'outerTradeNo' => $_POST['trade_no'],
  75. 'payType' => StatusCode::$payType['aliPay'],
  76. 'payStatus' => StatusCode::$standard,
  77. 'payTime' => strtotime($_POST['gmt_payment']), // 支付完成时间
  78. ];
  79. $objMVipCard = new MVipCard($enterpriseId, $userCentId);
  80. $result = $objMVipCard->updateVipOrderPayData($vipOrderData, ['id'=>$allOrdersId,'outerTradeNo'=>$_POST['out_trade_no']],true);
  81. if(!$result->isSuccess()){
  82. file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'修改会员卡订单状态失败'.var_export($result->getData(),true).PHP_EOL,FILE_APPEND);
  83. exit('fail');
  84. }else{
  85. exit('success');// 响应success表示业务处理成功,告知支付宝无需在异步通知
  86. }
  87. }
  88. exit('fail');
  89. }else{
  90. file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'状态错误'.var_export($_POST,true).PHP_EOL,FILE_APPEND);
  91. }
  92. }else{
  93. file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'签名验证失败'.var_export($_POST,true).PHP_EOL,FILE_APPEND);
  94. }
  95. }
  96. /** rsaCheckV1 & rsaCheckV2
  97. * 验证签名
  98. * 在使用本方法前,必须初始化AopClient且传入公钥参数。
  99. * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。
  100. **/
  101. public function rsaCheckV1($params, $rsaPublicKeyFilePath,$signType='RSA') {
  102. $sign = $params['sign'];
  103. $params['sign_type'] = null;
  104. $params['sign'] = null;
  105. return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath,$signType);
  106. }
  107. public function getSignContent($params) {
  108. ksort($params);
  109. $stringToBeSigned = "";
  110. $i = 0;
  111. foreach ($params as $k => $v) {
  112. if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
  113. // 转换成目标字符集
  114. $v = $this->characet($v, "UTF-8");
  115. if ($i == 0) {
  116. $stringToBeSigned .= "$k" . "=" . "$v";
  117. } else {
  118. $stringToBeSigned .= "&" . "$k" . "=" . "$v";
  119. }
  120. $i++;
  121. }
  122. }
  123. unset ($k, $v);
  124. return $stringToBeSigned;
  125. }
  126. /**
  127. * 校验$value是否非空
  128. * if not set ,return true;
  129. * if is null , return true;
  130. **/
  131. protected function checkEmpty($value)
  132. {
  133. if (!isset($value))
  134. return true;
  135. if ($value === null)
  136. return true;
  137. if (trim($value) === "")
  138. return true;
  139. return false;
  140. }
  141. /**
  142. * 转换字符集编码
  143. * @param $data
  144. * @param $targetCharset
  145. * @return string
  146. */
  147. function characet($data, $targetCharset)
  148. {
  149. if (!empty($data)) {
  150. $fileType = "UTF-8";
  151. if (strcasecmp($fileType, $targetCharset) != 0) {
  152. $data = mb_convert_encoding($data, $targetCharset, $fileType);
  153. // $data = iconv($fileType, $targetCharset.'//IGNORE', $data);
  154. }
  155. }
  156. return $data;
  157. }
  158. function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA')
  159. {
  160. if($this->checkEmpty($this->alipayPublicKey)){
  161. $pubKey= $this->alipayrsaPublicKey;
  162. $res = "-----BEGIN PUBLIC KEY-----\n" .
  163. wordwrap($pubKey, 64, "\n", true) .
  164. "\n-----END PUBLIC KEY-----";
  165. }else {
  166. //读取公钥文件
  167. $pubKey = file_get_contents($rsaPublicKeyFilePath);
  168. //转换为openssl格式密钥
  169. $res = openssl_get_publickey($pubKey);
  170. }
  171. ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
  172. //调用openssl内置方法验签,返回bool值
  173. if ("RSA2" == $signType) {
  174. $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
  175. } else {
  176. $result = (bool)openssl_verify($data, base64_decode($sign), $res);
  177. }
  178. if(!$this->checkEmpty($this->alipayPublicKey)) {
  179. //释放资源
  180. openssl_free_key($res);
  181. }
  182. return $result;
  183. }
  184. }