| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <?php
- namespace app\controller;
- use app\BaseController;
- use think\facade\Db;
- //支付控制器
- class Pay extends BaseController
- {
- protected $noNeedLogin = ['payOrder','payCallback'];
- public $baseUrl = 'https://pay.v8jisu.cn';
- public $merchantId = '28399';
- public $key = '0QknLivpRQB50Bq76r06PiR464SrTrvQ';
- public $merchantPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy9M3hkPM/rAeow0Y6bjJzHFy4btLxIZ4gMB3ggqP1MBDTg+oLwrVfU8OUxYG7/yntiFqDFNOAopccygsNRTzdrWQjenbJ4g9xCwWiIiubMRAKfgYNX9AsUalxcXpWPvmCLKHc4YdHGh8+GrV0qZi/FAQ7uMLXeowe+Np9cUziXIDLYbgJXB0UBqEyI2GVBJMOuFqKaP5pay/DcTTQwLKcHyzPlOUTlMet4ClPrAhqfe/FQYIfa8nFtrSevAzPMwJuZfYrFr6DvyQADaP16RZQS0tLMPW47646ieQ7GmITixXd5yEzlBTlECh1sIKyzn9DjzLkmrVFsDim4NFgJp/eQIDAQAB';
- public $merchantPrivateKey = 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDkSKP7fp5hjHFgYufalba3+qeJMPKHhXCm1yk7jJKkOIHkgW8tpcQqw/c8krwIRdjW6W5YF5Jr/b3cXP1JmyIeyLfbglSck+GijdFGMWlwbNAPVO/TrJUy8/+beFrqVJdCBlsRYW6lml4aGMXFTIK3Rn69zRfvgUFDYcZOa0VGTfXjfR0hOME6vxw1DxCOvWxczh8uLSeFnbirIyKaES807XGC3eCTmyJi/UsPA3vQeUUTpXliitSZFH/+T6g2K4n0Oy2OER5cTFWL8p/Gpy/pxoxALrc9eSIv8diLIco7WPfFYPABeZFe0cF4FwBeVaCqh1/K9m9uE6SAXhJUKZbzAgMBAAECggEAahuRjQ5Xk8Px1vliB2nbWjy5rrz/nhpaOFJ+Kd23M3nIdmvrP25zdeVMf+08VSQSHCK4VV3vgx6YJ1tZp+LhwylMvE0iAv2BvUrp4RSKi+Un+FhkeSEY4GwlfSA+MflLrTbDEZsWEQdlgf/NvV1IzOOJebNg0sRjj2xc/opB0uD9Dp2CMmdR4cztUXlmnVx0i5UQxl59u0TQitcuriTmqre4qibYX3ddr1V91k7WCde25a7HEdoQSID566O3H3tE6+XSIEp6LXpYrZFSK+b9Zc+V7khr27AmEMsSPpy/nSPI8pKwjaoFbLaGrh9PToXin5ENGbVY79fARIVe+HfAoQKBgQD1K1yqSEs+F09Aml6xY5BjqJ14HJQ8DphktrGzlI0hYHi42OtEfaPOrThLHGes4TipJUnvWjG0YqNaW+t9j2733OShUNF5BqiwTyfZ1/F+UffU+m6Dq0aB/DZV7KGB6rfQ1XUn77rIMs0gcm7BMwhfZLXUWDhj6qen+kMCO9PY+QKBgQDuXlFaQh1/ByR/urOqU6x9EGr5B0iT2QXM1vKbGOpj2wZIRV+wJtfnSy5kTxRigGgm1gXHgqYwRrONGR/0O/yfNVEm/OuEy4IUNBXsU/vjmzpfSNt2ajY91bMuf6aAZ1M688o08ouL4mrCKWQHUXIN8jxnPN6Yp84TcotghZi2SwKBgQCO6TnY4M9LYFcIN3PfP0RZc15nN3GJGJDolD49iehCfnOgfIGXqQ0lWn+n+OTON3LJ1jyk0xSKK71A3LgGtudegFqdVfjk7WbDb0CxkVjp42ntshVdlydAef5KU+dJTcLcbrEeGHXuYP6FXW8GG3NT9+at4sbsJ0qXdiA9WxaAMQKBgHDV5u6x42KRT/7Cs2/KYhllny24++s4zV0U1w0CM1oHgSbO6Cfri0JqvVAwevbRz/uqTlwOBXtOzInbPdwQVVpME9k/2oEnELFdoo8XhmJMxcn7JCAe0QReV46IUJnxz11Vr/92XQZfrKeyji5EqJffdiZskvZyYMOl8kJDm3GXAoGBAOOd8/HCGGeaMA7Uv9bjW17BQ9d/mJ/KmBI/S0t0/Y5Ur7hdtcS/5fw9lHPIqXTP+CJhE5+sQOi5GiwWHy0CCUlWFfi3kwlNTrau3m56sx7chjvaY/1F3b4sG7eFJMbgi8BjXiZREHJ1dehczF9pguIT/rcCtkpDMaWy8DIrSRdp';
- // 生成RSA公钥
- private function makeRsaSign($data)
- {
- // 排序 & 拼接
- ksort($data);
- $str = '';
- foreach ($data as $k => $v) {
- if ($v !== "" && $k != 'sign' && $k != 'sign_type' && !is_array($v)) {
- $str .= "{$k}={$v}&";
- }
- }
- $str = rtrim($str, "&");
- // 拼接PEM格式
- $privateKey = "-----BEGIN PRIVATE KEY-----\n"
- . chunk_split($this->merchantPrivateKey, 64, "\n")
- . "-----END PRIVATE KEY-----\n";
- $res = openssl_get_privatekey($privateKey);
- if (!$res) {
- throw new \Exception('私钥格式错误或无法加载');
- }
- openssl_sign($str, $sign, $res, OPENSSL_ALGO_SHA256);
- return base64_encode($sign);
- }
- // 生成 MD5 签名
- private function makeMd5Sign($data)
- {
- $md5_key = $this->key; // 商户密钥
- ksort($data); // 按照 ASCII 码排序
- $str = '';
- foreach ($data as $k => $v) {
- if ($v !== "" && $k != 'sign' && $k != 'sign_type') {
- // 排除空值、sign 和 sign_type
- $str .= "{$k}={$v}&";
- }
- }
- $str = rtrim($str, "&"); // 去掉最后一个 &
- $str .= $md5_key; // 按文档要求,直接拼接 KEY
-
- return md5($str); // 小写
- }
-
- // 发起Http请求
- private function HttpRequest($url, $postData)
- {
- // 将数组编码为 x-www-form-urlencoded 格式的查询字符串
- $postData1 = http_build_query($postData);
- // 初始化 cURL 会话
- $ch = curl_init($url);
- // 设置 cURL 选项
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 将响应作为字符串返回
- curl_setopt($ch, CURLOPT_POST, true); // 使用 POST 方法
- curl_setopt($ch, CURLOPT_POSTFIELDS, $postData1); // 设置 POST 数据
- curl_setopt($ch, CURLOPT_HTTPHEADER, array(
- 'Content-Type: application/x-www-form-urlencoded' // 设置 Content-Type 头
- ));
- // 执行请求并获取响应
- $response = curl_exec($ch);
- // 关闭 cURL 会话
- curl_close($ch);
- // 检查请求是否成功
- if ($response === false) {
- return "cURL Error: " . curl_error($ch);
- } else {
- // 处理响应
- return $response;
- }
- }
- // JSON清理
- function fixEscapedJson($jsonString) {
- // 移除多余的反斜杠
- $fixed = stripslashes($jsonString);
- // 替换HTML实体
- $fixed = str_replace(
- ['"', '&', '<', '>'],
- ['"', '&', '<', '>'],
- $fixed
- );
- return $fixed;
- }
-
- //拉起订单
- public function order()
- {
- $goodsName = $this->request->post('goodsName'); // 商品名称
- $amount = $this->request->post('amount'); // 商品金额
- $type = $this->request->post('type'); // 支付方式
- $isVip = $this->request->post('isVip') ?? 0; // 是否为购买VIP
- $user = $this->getUser();
- if (!$goodsName || !$type || !is_numeric($amount)) {
- $this->fail(500, '参数校验错误');
- }
- if (!$user) {
- $this->fail(500, '用户未登录');
- }
- // 参数构建
- $data['pid'] = $this->merchantId;
- $data['method'] = 'jump'; // 接口类型
- $data['device'] = 'pc'; // 设备类型
- $data['type'] = $type; // 支付方式
- $data['out_trade_no'] = date('YmdHis') . strval(mt_rand(100000, 999999)); // 订单号
- $data['notify_url'] = 'https://api.danjiwanjia.com/pay/payCallback'; // 服务器异步通知地址
- $data['return_url'] = 'https://www.danjiwanjia.com/#/userCenter'; // 页面跳转通知地址
- $data['name'] = $goodsName; // 商品名称
- $data['money'] = $amount; // 商品金额
- $data['clientip'] = $this->request->ip(); // 用户ip地址
- $data['timestamp'] = time(); // 当前时间戳
- $data['param'] = json_encode(['isVip' => $isVip]); // 业务拓展参数 通过此参数判断用户是否通过VIP页面调起支付
- $data['sign_type'] = 'RSA'; // 当前时间戳
- $data['sign'] = $this->makeRsaSign($data); // 签名生成
- // 插入数据表
- Db::table('tb_user_order')
- ->insert([
- 'user_id' => $user->user_id,
- 'balance' => $amount,
- 'state' => 0,
- 'created_at' => time(),
- 'order_no' => $data['out_trade_no'],
- ]);
- // 发起请求
- $url = $this->baseUrl . '/api/pay/create';
- $result = $this->HttpRequest($url, $data);
- // header('Content-Type: application/json');
- // echo $result;
- // exit();
- $result = json_decode($result, true);
- if($result['code'] == 0) {
- $this->success('success', $result['pay_info']);
- } else {
- $this->fail(500, $result['msg']);
- }
- }
-
- //获取我的订单
- public function getMyOrder()
- {
- $page = $this->request->post('page'); //页码
- $pageNum = $this->request->post('pageNum'); //每页显示的数据条数
- if (!is_numeric($pageNum) || !is_numeric($page)) {
- $this->fail(500, 'page或pageNum参数校验错误');
- }
- $data = Db::table('tb_user_order')
- ->where(['user_id' => $this->getUser()->user_id])
- ->order('created_at DESC')
- ->paginate([
- 'page' => $page,
- 'list_rows' => $pageNum,
- ]);
- $this->success('success', $data);
- }
-
- /**
- * 支付回调
- */
- public function payCallback()
- {
- $data = $this->request->param();
- error_log('payCallback: '.json_encode($data));
- if(!$data) {
- exit('无法获取到传参');
- }
- $order_sn = $data['out_trade_no'];
- $amount = $data['money'];
- $isVip = json_decode($this->fixEscapedJson($data['param']), true)['isVip'];
- $order = Db::name('tb_user_order')->where('order_no', $order_sn)->find();
- if (!$order) {
- exit('订单不存在');
- }
- if ($order['state'] == 1) {
- // 订单已支付 不走后面的逻辑但是要返回success
- exit('success');
- }
- // 订单校验通过 更新订单状态
- Db::name('tb_user_order')
- ->where('order_no', $order_sn)
- ->update([
- 'state' => 1,
- 'pay_at' => time(),
- ]);
- // 业务判断
- if($isVip == 1) {
- // 增加用户VIP时长
- // 查找对应价格VIP等级
- $vipInfo = Db::name('tb_user_vip_price')
- ->where('user_id', $order['user_id'])
- ->where('price', $amount)
- ->find();
- // 首先判断当前用户是否已经为VIP
- $userVip = Db::name('tb_user_vip')->where('user_id', $order['user_id'])->find();
- if($userVip) {
- // 如果用户已经为VIP 且为同类型VIP则增加VIP时长
- if($userVip['type'] == $vipInfo['type']) {
- Db::name('tb_user_vip')
- ->where('user_id', $order['user_id'])
- ->setInc('expired_at', strtotime($vipInfo['duration'] . 'month'));
- } else {
- // 如果用户已经为VIP 且为不同类型VIP则删除原有VIP记录并新增VIP记录
- Db::name('tb_user_vip')
- ->where('user_id', $order['user_id'])
- ->delete();
- Db::name('tb_user_vip')->insert([
- 'user_id' => $order['user_id'],
- 'type' => $vipInfo['type'],
- 'expired_at' => strtotime($vipInfo['duration'] . 'month')
- ]);
- }
- } else {
- // 如果用户不是VIP 则新增VIP记录
- Db::name('tb_user_vip')->insert([
- 'user_id' => $order['user_id'],
- 'type' => $vipInfo['type'],
- 'expired_at' => strtotime($vipInfo['duration'] . 'month')
- ]);
- }
- } else {
- // 增加用户余额
- Db::name('tb_user')
- ->where('id', $order['user_id'])
- ->inc('balance', $amount * 2) // 限时活动 实际到账金额为金额的2倍
- ->update();
- }
- exit('success');
- }
- }
|