YiyunPayController.class.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. <?php
  2. namespace bibidd\Controller;
  3. use Bibidd\Controller\CommonBaseController;
  4. /**
  5. * 依云支付
  6. */
  7. class YiyunPayController extends CommonBaseController
  8. {
  9. /**
  10. * 领航支付
  11. * @return void
  12. */
  13. public function pay()
  14. {
  15. $this->addHeaders(); //添加头部请求
  16. $user_info = $this->checkUserIsExist($_POST['uid']); //检查用户
  17. $uid = $_POST['uid'];
  18. $time_unix=$this->getUnixTimestamp();
  19. //用户id
  20. //选择支付类型,通道支付宝1、支付宝2、微信1
  21. $channel = $_POST['channel'];
  22. $pay_amount = $_POST['payAmount']; //充值金额
  23. //1是没首充 0有奖励
  24. $yn_first_pay = $_POST['yn_first_pay'];
  25. //获取通道编码
  26. $channel_info = M("td_zf")->where("tongdao='$channel' and $pay_amount>=min_ and $pay_amount<=max_")->find();
  27. $pay_bankcode = $channel_info["td_id"];
  28. $beizhu = $channel_info["td_name"];
  29. $number=$uid.$time_unix.$this->random_num(5);
  30. //提交时间
  31. $ttime = time();
  32. $pay_applydate = date("Y-m-d H:i:s",$ttime);;
  33. //服务端通知
  34. $pay_notifyurl = C("appUrl").'/bibidd/YiyunPay/call_back_coins';
  35. //页面跳转通知
  36. $pay_callbackurl = C("appUrl").'/bibidd/YiyunPay/call_back_coins';
  37. //付款人 IP
  38. $pay_ip = $this->getIp();
  39. //商户号
  40. $pay_memberid = 10067;
  41. //密钥
  42. $member_key = 'M2R7R7JJRETCYOLCMCA3S5P4B0NVDDYZ2V6WETSPRJTZLAPQLARPBX3ZYVQTWGFFSUO26MOZRPYQDDOF08J2TOV9QVVZ4DFPF6SK5QQVE0PPJBOUNUMCGSVLIBZJMKZG';
  43. //订单号
  44. $pay_orderid = "$number" ;
  45. //商品名称
  46. $pay_productname = $uid.$beizhu.$pay_bankcode;
  47. $dingdan['order_id'] = $number;
  48. $dingdan['uid'] = $uid;
  49. $dingdan['order_str'] = $pay_productname;
  50. $dingdan['order_ip'] = $pay_ip;
  51. $dingdan['apply_date'] = $pay_applydate;
  52. $dingdan['apply_time'] = $ttime;
  53. $dingdan['order_type'] = '待支付';
  54. $dingdan['amount'] = $pay_amount;
  55. $tmpl_amount= $pay_amount*100; //通道是以分为单位
  56. $stringSignTemp="mchId=$pay_memberid&productId=$pay_bankcode&mchOrderNo=$pay_orderid&amount=$tmpl_amount&notifyUrl=$pay_notifyurl&returnUrl=$pay_callbackurl&param2=$yn_first_pay" ;
  57. $md5Value =$this-> generateSortedMd5($stringSignTemp,$member_key);
  58. M("pay_test")->add($dingdan);
  59. $post_data = array(
  60. 'mchId' => $pay_memberid,
  61. 'productId' =>$pay_bankcode,
  62. 'mchOrderNo' => $pay_orderid,
  63. 'amount' => $tmpl_amount,
  64. 'param2' => $yn_first_pay,
  65. 'notifyUrl' => $pay_notifyurl,
  66. 'returnUrl' => $pay_callbackurl,
  67. 'sign' => $md5Value,
  68. );
  69. $rs= $this->send_post('http://pay.yunmei.cfd/api/pay/create_order', $post_data);
  70. if (empty($rs) || $rs['retCode']=='FAIL') {
  71. $e_data['status'] = '0';
  72. $e_data['code'] = '204';//未携带参数,请求失败
  73. $e_data['pay_url'] = '';//未携带参数,请求失败
  74. $e_data['message'] = '请重试。';
  75. echo json_encode($e_data);
  76. }else{
  77. $rs['code'] = 200;
  78. echo json_encode($rs);
  79. }
  80. }
  81. /**
  82. * md5
  83. * @param $params
  84. * @return string
  85. */
  86. private function generateSortedMd5($params,$key)
  87. {
  88. // 解析参数字符串为关联数组
  89. parse_str($params, $paramArray);
  90. // 过滤空值参数(包括null和空字符串)
  91. $filteredParams = array_filter($paramArray, function($value) {
  92. return $value !== '' && $value !== null && $value !== 0;
  93. });
  94. // 按键名进行字典序排序
  95. ksort($filteredParams);
  96. // 构建查询字符串(不进行URL编码)
  97. $queryString = $this->buildRawQueryString($filteredParams,$key);
  98. // 计算MD5哈希
  99. $md5 = md5($queryString);
  100. return $md5;
  101. }
  102. /**
  103. * 构建原始查询字符串(不进行URL编码)
  104. */
  105. private function buildRawQueryString($params,$key1)
  106. {
  107. $base_string = '';
  108. foreach ($params as $key => $value) {
  109. $base_string .= $key . '=' . $value . '&';
  110. }
  111. $base_string.= 'key='.$key1;
  112. return $base_string;
  113. }
  114. function send_post($url, $post_data) {
  115. // 构建 multipart/form-data 格式数据
  116. $boundary = uniqid();
  117. $content = $this->buildFormDataBody($post_data, $boundary);
  118. $options = array(
  119. 'http' => array(
  120. 'method' => 'POST',
  121. 'header' => "Content-Type: multipart/form-data; boundary=$boundary\r\n",
  122. 'content' => $content,
  123. 'timeout' => 15 * 60 // 超时时间(单位:s)
  124. )
  125. );
  126. $context = stream_context_create($options);
  127. // 使用错误抑制符@防止警告直接输出,我们会捕获异常
  128. $result = @file_get_contents($url, false, $context);
  129. // 检查请求是否成功
  130. if ($result === false) {
  131. $error = error_get_last();
  132. throw new Exception('HTTP请求失败: ' . ($error['message'] ?? '未知错误'));
  133. }
  134. // 尝试解码JSON响应
  135. $decoded_result = json_decode($result, true);
  136. // 检查JSON解码是否成功
  137. if (json_last_error() !== JSON_ERROR_NONE) {
  138. // 如果不是JSON响应,返回原始结果
  139. return $result;
  140. }
  141. return $decoded_result;
  142. }
  143. private function buildFormDataBody($data, $boundary) {
  144. $eol = "\r\n";
  145. $body = '';
  146. foreach ($data as $key => $value) {
  147. $body .= "--$boundary$eol";
  148. $body .= "Content-Disposition: form-data; name=\"$key\"$eol$eol";
  149. $body .= $value . $eol;
  150. }
  151. $body .= "--$boundary--$eol";
  152. return $body;
  153. }
  154. /**
  155. * 领航回调地址
  156. * @return void
  157. */
  158. public function call_back_coins(){
  159. $this->addHeaders();
  160. //验签
  161. $params = $this->validate_sign();
  162. $post = $_POST;
  163. if ($post == null) {
  164. $post = file_get_contents("php://input");
  165. }
  166. //支付状态,0-订单生成,1-支付中,2-支付成功,3-业务处理完成
  167. $chenggong['name'] = $post['status'];
  168. //商户编号
  169. $memberid = $post['mchId'];
  170. //订单号
  171. $orderid = $post['mchOrderNo'];
  172. //订单金额
  173. $amount = $post['amount']/100;
  174. //交易流水号
  175. $transaction_id = $post['payOrderId'];
  176. //交易时间
  177. $datetime = $post['paySuccTime'];
  178. //交易状态
  179. $returncode = $post['status'];
  180. //扩展返回
  181. $attach = $post['param2'];
  182. //attach 如果是0
  183. //防止重复回调,2024-4-15
  184. $idempotent_check = M("huidiao_test")->where("memberid = '$memberid' AND orderid = '$orderid' AND transaction_id = '$transaction_id'")->find();
  185. if(!empty($idempotent_check))
  186. {
  187. exit('success');
  188. die();
  189. }
  190. //防止重复回调,2024-6-1
  191. $uid = M("pay_test")->where("order_id='$orderid'")->getField("uid");
  192. if(empty($uid))
  193. {
  194. exit('success');
  195. die();
  196. }
  197. $post['uid'] = $uid;
  198. $post['time'] = time();
  199. try {
  200. //添加回调表用户来源add_url
  201. $add_url1= M("user_info")->where("id='$uid'")->getField("add_url");
  202. //回调
  203. $callback_info['uid']=$uid;
  204. $callback_info['time']=time();
  205. $callback_info['name']=$post['productId'];
  206. $callback_info['code']=$post['productId'];
  207. $callback_info['memberid']=$post['mchId'];
  208. $callback_info['orderid']=$post['mchOrderNo'];
  209. $callback_info['amount']=$post['amount']/100;
  210. $callback_info['transaction_id']=$post['payOrderId'];
  211. $callback_info['datetime']=$post['paySuccTime'];
  212. $callback_info['returncode']=$post['status'];
  213. $callback_info['attach']=$post['param2'];
  214. $callback_info['add_url']=$add_url1;
  215. $callback_info['ip']=$this->getIp();
  216. M("huidiao_test")->add($callback_info);
  217. }catch (Exception $e)
  218. {
  219. exit('success');
  220. die();
  221. }
  222. //end,2024-6-1
  223. //支付成功
  224. if ($chenggong['name']==2) {
  225. //交易成功 将用户改成会员
  226. $now_time_chuo = time();
  227. $chenggong['order_type'] = '已支付';
  228. $chenggong['pay_time'] = $now_time_chuo;
  229. $chenggong['amount_due'] =$amount;
  230. $chenggong['mifeng_id'] =$transaction_id;
  231. if($attach=='-1')
  232. {
  233. //加金币
  234. switch ($amount) {
  235. case '40.0000':
  236. $ks = M("user_info")->where("id=$uid")->setInc('gold_coins_number',40);
  237. break;
  238. case '60.0000':
  239. $ks = M("user_info")->where("id=$uid")->setInc('gold_coins_number',60);
  240. break;
  241. case '100.0000':
  242. M("user_info")->where("id=$uid")->setInc('gold_coins_number',100);
  243. break;
  244. case '200.0000':
  245. M("user_info")->where("id=$uid")->setInc('gold_coins_number',200);
  246. break;
  247. case '500.0000':
  248. M("user_info")->where("id=$uid")->setInc('gold_coins_number',500);
  249. break;
  250. case '1000.0000':
  251. M("user_info")->where("id=$uid")->setInc('gold_coins_number',1000);
  252. break;
  253. default:
  254. M("user_info")->where("id=$uid")->setInc('gold_coins_number',$amount);
  255. }
  256. }elseif ($attach=='xx')
  257. {
  258. //直冲添加会员
  259. switch ($amount) {
  260. case '50.0000': //永久会员
  261. //永久会员
  262. $over_time_chuo_jj = '9999999999';
  263. $huiyuan['vip_over_time'] =$over_time_chuo_jj;
  264. $huiyuan['vip_yn'] = '1';
  265. $this->xiaofei_detail($uid,"开通会员","永久会员",$amount);
  266. //另外的统计表
  267. $vip_table_list['code'] = 1;
  268. $vip_table_list['time'] = time() ;
  269. $vip_table_list['uid'] = $uid;
  270. $vip_table_list['amount'] = $amount;
  271. M("vip_add_list")->add($vip_table_list);
  272. break;
  273. case '50.0000': //一个月会员
  274. //一个月会员
  275. $over_time_chuo_jj = $now_time_chuo + (3600*24*30);
  276. $huiyuan['vip_over_time'] =$over_time_chuo_jj;
  277. $huiyuan['vip_yn'] = '2';
  278. $this->xiaofei_detail($uid,"开通会员","月会员",$amount);
  279. //另外的统计表
  280. $vip_table_list['code'] = 2;
  281. $vip_table_list['time'] = time() ;
  282. $vip_table_list['uid'] = $uid;
  283. $vip_table_list['amount'] = $amount;
  284. M("vip_add_list")->add($vip_table_list);
  285. break;
  286. case '40.0000': //周会员
  287. //7天
  288. $over_time_chuo_yue = $now_time_chuo + (3600*24*7);
  289. $huiyuan['vip_over_time'] = $over_time_chuo_yue;
  290. $huiyuan['vip_yn'] = '3';
  291. $this->xiaofei_detail($uid,"开通会员","7天会员",$amount);
  292. //另外的统计表
  293. $vip_table_list['code'] = 3;
  294. $vip_table_list['time'] = time() ;
  295. $vip_table_list['uid'] = $uid;
  296. $vip_table_list['amount'] = $amount;
  297. M("vip_add_list")->add($vip_table_list);
  298. break;
  299. default:
  300. echo "type error";
  301. die();
  302. }
  303. //更新为会员
  304. M("user_info")->where("id=$uid")->save($huiyuan);
  305. }//end huiyuan
  306. //更新用户充值金额
  307. M("user_info")->where("id=$uid")->setInc('vip_money',$amount);
  308. //修改订单相关 并且添加支付表
  309. M("pay_test")->where("order_id='$orderid'")->save($chenggong);
  310. //统计用户充值总额 2024-11-15(上线时间为切割点)
  311. $this->count_chongzhi($uid,$amount);
  312. //代理返佣,统计
  313. $this->proxy_pay_count($uid,$amount);
  314. exit('success');
  315. }
  316. }
  317. private function validate_sign()
  318. {
  319. $params = [
  320. 'payOrderId' => $_POST['payOrderId'],
  321. 'mchId' => $_POST['mchId'],
  322. 'productId' => $_POST['productId'],
  323. 'mchOrderNo' => $_POST['mchOrderNo'],
  324. 'amount' => $_POST['amount'],
  325. 'status' => $_POST['status'],
  326. 'paySuccTime' => $_POST['paySuccTime'],
  327. 'sign' => $_POST['sign'],
  328. 'param2' => $_POST['param2'],
  329. ];
  330. ksort($params); //自然排序
  331. //拼接请求
  332. $base_string = '';
  333. foreach ($params as $key => $value) {
  334. if($key=='sign') continue;
  335. $base_string .= $key . '=' . $value . '&';
  336. }
  337. $base_string.= 'key=M2R7R7JJRETCYOLCMCA3S5P4B0NVDDYZ2V6WETSPRJTZLAPQLARPBX3ZYVQTWGFFSUO26MOZRPYQDDOF08J2TOV9QVVZ4DFPF6SK5QQVE0PPJBOUNUMCGSVLIBZJMKZG';
  338. $sign_check = md5($base_string);
  339. //校验签名
  340. $sign = $_POST['sign'];
  341. if(strcasecmp($sign_check , $sign)!=0)
  342. {
  343. // 验签失败
  344. $trans_id = $_POST['payOrderId'];
  345. $update_inf["mifeng_id"]='验签失败:'.$sign_check.'对方签名'.$sign;
  346. M("pay_test")->where("mifeng_id='$trans_id'")->save($update_inf);
  347. $data['code'] = '200';
  348. $data['message'] = '非法请求';
  349. //echo json_encode($data);
  350. exit('success');
  351. die();
  352. }
  353. return $params;
  354. }
  355. }