Notify.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <?php
  2. namespace app\api\controller;
  3. use think\Controller;
  4. use think\Db;
  5. /**
  6. * 订单支付回调
  7. */
  8. class Notify extends Controller
  9. {
  10. protected $noNeedLogin = ['*'];
  11. protected $noNeedRight = ['*'];
  12. public function checkNotify($args = []){
  13. $secret = config('hitpay.salt');
  14. $input_hmac = $args['hmac'];
  15. unset($args['hmac']);
  16. //hitpay/client/generateSignatureArray
  17. $hmacSource = [];
  18. foreach ($args as $key => $val) {
  19. $hmacSource[$key] = "{$key}{$val}";
  20. }
  21. ksort($hmacSource);
  22. $sig = implode("", array_values($hmacSource));
  23. $new_hmac = hash_hmac('sha256', $sig, $secret);
  24. //判断相等
  25. if($new_hmac == $input_hmac){
  26. return true;
  27. }else{
  28. return false;
  29. }
  30. }
  31. //主动获取一次
  32. private function getPaymentStatus($payment_request_id){
  33. $apiKey = config('hitpay.apikey');
  34. $hitPayClient = new \HitPay\Client($apiKey, true);
  35. $data = $hitPayClient->getPaymentStatus($payment_request_id);
  36. return $data->status;
  37. }
  38. //充值金币 异步回调对外方法
  39. public function recharge_notify_base(){
  40. //日志
  41. $paytype = 'hitpay';
  42. $notify_file = $this->notify_log_start($paytype);
  43. //接参
  44. $field = ['payment_id','payment_request_id','phone','amount','currency','status','reference_number','hmac'];
  45. $notify_data = request_post_hub($field);
  46. //验签
  47. $checkNotify = $this->checkNotify($notify_data);
  48. if ($checkNotify !== true) {
  49. echo '签名错误';
  50. exit;
  51. }
  52. //检查支付完成 completed / failed
  53. if($notify_data['status'] != 'completed'){
  54. $now_status = $this->getPaymentStatus($notify_data['payment_request_id']);
  55. if($now_status != 'completed'){
  56. echo '没有支付完成';
  57. exit;
  58. }
  59. }
  60. //验证,拿订单号等信息
  61. $out_trade_no = $notify_data['reference_number'];
  62. $payment_request_id = $notify_data['payment_request_id'];
  63. //订单查询
  64. $map = [
  65. 'out_trade_no' => $out_trade_no,
  66. 'payment_request_id' => $payment_request_id,
  67. ];
  68. $info = Db::name('pay_order')->where($map)->find();
  69. if(empty($info)){
  70. echo 'success';
  71. exit;
  72. }
  73. if($info['order_status'] != 0)
  74. {
  75. echo 'success';
  76. exit;
  77. }
  78. //你可以在此编写订单逻辑
  79. $rs = $this->recharge_notify_do($out_trade_no);
  80. if($rs === false){
  81. //不论结果都应返回success
  82. echo 'success';
  83. exit;
  84. }else{
  85. //不论结果都应返回success
  86. echo 'success';
  87. exit;
  88. }
  89. //默认
  90. echo 'success';
  91. exit;
  92. }
  93. //充值金币 逻辑
  94. private function recharge_notify_do($out_trade_no){
  95. $time = time();
  96. Db::startTrans();
  97. $orderInfo = Db::name('pay_order')->where(['out_trade_no' => $out_trade_no])->lock(true)->find();
  98. if (empty($orderInfo)) {
  99. Db::rollback();
  100. return false;
  101. }
  102. if($orderInfo['order_status'] != 0){
  103. Db::rollback();
  104. return false;
  105. }
  106. //逻辑开始
  107. //试课预约
  108. if($orderInfo['table_name'] == 'trylesson_order'){
  109. $update = [
  110. 'order_status' => 10,
  111. 'paytime' => $time,
  112. 'updatetime' => $time,
  113. ];
  114. $rs = Db::name('trylesson_order')->where('id',$orderInfo['table_id'])->update($update);
  115. if($rs === false){
  116. Db::rollback();
  117. return false;
  118. }
  119. }
  120. //售课预约
  121. if($orderInfo['table_name'] == 'lesson_order'){
  122. $update = [
  123. 'order_status' => 10,
  124. 'paytime' => $time,
  125. 'updatetime' => $time,
  126. ];
  127. $rs = Db::name('lesson_order')->where('id',$orderInfo['table_id'])->update($update);
  128. if($rs === false){
  129. Db::rollback();
  130. return false;
  131. }
  132. }
  133. //售课预约买套餐
  134. if($orderInfo['table_name'] == 'package_order'){
  135. //修改套餐单
  136. $update = [
  137. 'order_status' => 1,
  138. 'paytime' => $time,
  139. 'updatetime' => $time,
  140. ];
  141. $rs = Db::name('package_order')->where('order_no',$orderInfo['out_trade_no'])->update($update); //这里不用id,是因为另有赠品单,两个一起更新
  142. if($rs === false){
  143. Db::rollback();
  144. return false;
  145. }
  146. //修改预约单。这一块最好搬到计划任务里
  147. $args = json_decode($orderInfo['args'],true);
  148. if(isset($args['lesson_order_id']) && !empty($args['lesson_order_id'])){
  149. $package_order = Db::name('package_order')->where('order_no',$orderInfo['out_trade_no'])->where('is_gift',0)->find();
  150. $lesson_order = Db::name('lesson_order')->where('id',$args['lesson_order_id'])->find();
  151. //课时能够支撑报名人数
  152. if($package_order['remain'] >= $lesson_order['number']){
  153. //扣除一节
  154. $update = [
  155. 'remain' => $package_order['remain'] - $lesson_order['number'],
  156. 'updatetime' => time(),
  157. ];
  158. $rs1 = Db::name('package_order')->where('id',$package_order['id'])->update($update);
  159. if($rs1 === false){
  160. Db::rollback();
  161. return false;
  162. }
  163. //修改预约单状态
  164. $update = [
  165. 'order_status' => 10,
  166. 'paytime' => $time,
  167. 'updatetime' => $time,
  168. 'package_order_id' => $package_order['id'],
  169. 'paytype' => 1, //从购买套餐中3,改为 课程套餐1
  170. ];
  171. if($lesson_order['number'] > 1){
  172. $update['package_remark'] = ($package_order['sessions'] - $package_order['remain'] + 1) . '-' . ($package_order['sessions'] - $package_order['remain'] + $lesson_order['number']) .'/'. $package_order['sessions'];
  173. }else{
  174. $update['package_remark'] = ($package_order['sessions'] - $package_order['remain'] + 1) .'/'. $package_order['sessions'];
  175. }
  176. $rs = Db::name('lesson_order')->where('id',$args['lesson_order_id'])->update($update);
  177. if($rs === false){
  178. Db::rollback();
  179. return false;
  180. }
  181. }else{
  182. //新买的课时不足以支撑这次的报名人数,不处理
  183. }
  184. }
  185. }
  186. //逻辑结束
  187. //状态
  188. $ros = Db::name('pay_order')->where(['out_trade_no' => $out_trade_no])->update(['order_status'=>1,'notifytime'=>$time]);
  189. if($ros === false) {
  190. Db::rollback();
  191. return false;
  192. }
  193. //默认提交
  194. Db::commit();
  195. return true;
  196. }
  197. //异步日志
  198. private function notify_log_start($paytype = 'wechat'){
  199. //记录支付回调数据
  200. ignore_user_abort(); // run script in background
  201. set_time_limit(30);
  202. // 日志文件 start
  203. $log_base_dir = '../paylog/'.$paytype.'/';
  204. if (!is_dir($log_base_dir))
  205. {
  206. mkdir($log_base_dir, 0770, true);
  207. @chmod($log_base_dir, 0770);
  208. }
  209. $notify_file = $log_base_dir.'notify.txt';
  210. if(!file_exists($notify_file)) {
  211. @touch($notify_file);
  212. @chmod($notify_file, 0770);
  213. }
  214. if(filesize($notify_file)>5242880)//大于5M自动切换
  215. {
  216. rename($notify_file, $log_base_dir.'notify_'.date('Y_m_d_H_i_s').'.txt');
  217. }
  218. if(!file_exists($notify_file)) {
  219. @touch($notify_file);
  220. @chmod($notify_file, 0770);
  221. }
  222. // 日志文件 end
  223. //开始写入
  224. $xml = file_get_contents("php://input");
  225. file_put_contents($notify_file, "\r\n\r\n".date('Y-m-d H:i:s')." [notify][入口接收php://input流原始数据] \n".$xml, FILE_APPEND);
  226. ini_set('display_errors','On');
  227. return $notify_file;
  228. }
  229. }