Notify.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\controller\Api;
  4. use app\common\model\PayOrderModel;
  5. use app\common\model\Wallet;
  6. use app\utils\LogUtil;
  7. use think\Db;
  8. use addons\epay\library\Service;
  9. use think\Request;
  10. /**
  11. * 订单支付回调
  12. */
  13. class Notify extends Api
  14. {
  15. // 日志模块名称
  16. const LOG_MODULE = 'Notify';
  17. protected $noNeedLogin = ['*'];
  18. protected $noNeedRight = ['*'];
  19. public function __construct(Request $request = null)
  20. {
  21. parent::__construct($request);
  22. //日志统一写入
  23. register_shutdown_function([new LogUtil, 'close']);
  24. LogUtil::getInstance('Api/'); //设置日志存入通道
  25. }
  26. // 余额充值 支付回调
  27. public function recharge()
  28. {
  29. //验签
  30. $pay_type = input('pay_type', 'wechat');
  31. LogUtil::info("用户充值 {$pay_type}支付回调", self::LOG_MODULE, __FUNCTION__, $this->request->param());
  32. if (!$pay = Service::checkNotify($pay_type)) {
  33. LogUtil::info('签名错误', self::LOG_MODULE, __FUNCTION__);
  34. return $this->error('签名错误 err01');
  35. }
  36. //验证,拿订单号等信息
  37. $data = $pay->verify();
  38. $out_trade_no = $data['out_trade_no'];
  39. [$res, $msg] = PayOrderModel::recharge($out_trade_no);
  40. if (!$res) {
  41. LogUtil::info($msg, self::LOG_MODULE, __FUNCTION__);
  42. return $this->error('签名错误 err02');
  43. }
  44. LogUtil::info('处理成功', self::LOG_MODULE, __FUNCTION__);
  45. return $pay->success();
  46. }
  47. //充值VIP 异步回调对外方法
  48. public function vip_notify_base()
  49. {
  50. //验签
  51. $paytype = input('paytype', 'wechat');
  52. $notify_file = $this->notify_log_start($paytype);
  53. $pay = Service::checkNotify($paytype);
  54. if (!$pay) {
  55. echo '签名错误';
  56. exit;
  57. }
  58. //验证,拿订单号等信息
  59. $data = $pay->verify();
  60. $out_trade_no = $data['out_trade_no'];
  61. //订单查询
  62. $info = Db::name('pay_order')->where('out_trade_no', $out_trade_no)->find();
  63. if (empty($info)) {
  64. echo $pay->success();
  65. exit;
  66. }
  67. if ($info['order_status'] != 0) {
  68. echo $pay->success();
  69. exit;
  70. }
  71. //你可以在此编写订单逻辑
  72. $rs = $this->vip_notify_do($out_trade_no);
  73. if ($rs === false) {
  74. //不论结果都应返回success
  75. echo $pay->success();
  76. exit;
  77. } else {
  78. //不论结果都应返回success
  79. echo $pay->success();
  80. exit;
  81. }
  82. //默认
  83. echo $pay->success();
  84. exit;
  85. }
  86. //充值金币 逻辑
  87. private function vip_notify_do($out_trade_no)
  88. {
  89. Db::startTrans();
  90. $orderInfo = Db::name('pay_order')->where(['out_trade_no' => $out_trade_no])->lock(true)->find();
  91. if (empty($orderInfo)) {
  92. Db::rollback();
  93. return false;
  94. }
  95. if ($orderInfo['order_status'] != 0) {
  96. Db::rollback();
  97. return false;
  98. }
  99. //逻辑开始
  100. //先充值
  101. $args = json_decode($orderInfo['args'], true);
  102. $user_info = Db::name('user_wallet')->where('user_id', $orderInfo['user_id'])->lock(true)->find();
  103. if ($user_info['vip_endtime'] < time()) {
  104. //过期了
  105. $vip_endtime = time() + (intval($args['days']) * 86400);
  106. $vip_type = 1;
  107. } else {
  108. //追加vip
  109. $vip_endtime = $user_info['vip_endtime'] + (intval($args['days']) * 86400);
  110. $vip_type = 2;
  111. }
  112. $update_data = [
  113. 'vip_endtime' => $vip_endtime,
  114. ];
  115. $result = Db::name('user_wallet')->where('user_id', $orderInfo['user_id'])->update($update_data);
  116. //记录日志
  117. $log_data = [
  118. 'user_id' => $orderInfo['user_id'],
  119. 'before' => $user_info['vip_endtime'],
  120. 'change_value' => intval($args['days']) * 86400,
  121. 'remain' => $vip_endtime,
  122. 'remark' => '购买vip',
  123. 'createtime' => time(),
  124. 'vip_type' => $vip_type,
  125. ];
  126. Db::name('user_vip_log')->insertGetId($log_data);
  127. if ($result === false) {
  128. Db::rollback();
  129. return false;
  130. }
  131. //逻辑结束
  132. //状态
  133. $ros = Db::name('pay_order')->where(['out_trade_no' => $out_trade_no])->update(['order_status' => 1, 'notifytime' => time()]);
  134. if ($ros === false) {
  135. Db::rollback();
  136. return false;
  137. }
  138. //默认提交
  139. Db::commit();
  140. return true;
  141. }
  142. //异步日志
  143. private function notify_log_start($paytype = 'wechat')
  144. {
  145. //记录支付回调数据
  146. ignore_user_abort(); // run script in background
  147. set_time_limit(30);
  148. // 日志文件 start
  149. $log_base_dir = '../paylog/' . $paytype . '/';
  150. if (!is_dir($log_base_dir)) {
  151. mkdir($log_base_dir, 0770, true);
  152. @chmod($log_base_dir, 0770);
  153. }
  154. $notify_file = $log_base_dir . 'notify.txt';
  155. if (!file_exists($notify_file)) {
  156. @touch($notify_file);
  157. @chmod($notify_file, 0770);
  158. }
  159. if (filesize($notify_file) > 5242880)//大于5M自动切换
  160. {
  161. rename($notify_file, $log_base_dir . 'notify_' . date('Y_m_d_H_i_s') . '.txt');
  162. }
  163. if (!file_exists($notify_file)) {
  164. @touch($notify_file);
  165. @chmod($notify_file, 0770);
  166. }
  167. // 日志文件 end
  168. //开始写入
  169. $_REQUEST = isset($_REQUEST) ? $_REQUEST : array();
  170. if ($_REQUEST && $paytype == 'alipay') {
  171. file_put_contents($notify_file, "\r\n\r\n" . date('Y-m-d H:i:s') . " [notify][入口接收request]" . json_encode($_REQUEST), FILE_APPEND);
  172. } else {
  173. $xml = file_get_contents("php://input");
  174. file_put_contents($notify_file, "\r\n\r\n" . date('Y-m-d H:i:s') . " [notify][入口接收php://input流原始数据] \n" . $xml, FILE_APPEND);
  175. $xmlObj = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
  176. file_put_contents($notify_file, "\r\n\r\n" . date('Y-m-d H:i:s') . " [notify][入口接收php://input流] " . json_encode($xmlObj), FILE_APPEND);
  177. }
  178. ini_set('display_errors', 'On');
  179. return $notify_file;
  180. }
  181. }