diff --git a/app/admin/controller/Config.php b/app/admin/controller/Config.php index baea861..a850583 100755 --- a/app/admin/controller/Config.php +++ b/app/admin/controller/Config.php @@ -23,29 +23,20 @@ class Config extends Base public function weixinpay(Request $request) { $config = getConfig('weixinpay_setting'); - if (empty($config)) { - // 兼容旧数据,如果新配置为空,则尝试获取旧配置并转换格式 - $old_config = getConfig('weixinpay'); - if (!empty($old_config)) { - $config = [ - 'merchants' => [ - [ - 'name' => '默认商户', - 'mch_id' => $old_config['mch_id'] ?? '', - 'keys' => $old_config['keys'] ?? '', - 'order_prefix' => $old_config['order_prefix'] ?? 'MYH', - 'weight' => 1 - ] - ] - ]; - } - } - View::assign("key", "weixinpay_setting"); View::assign("data", $config); return View::fetch('Config/weixinpay'); } + //支付宝支付 + public function alipay(Request $request) + { + $config = getConfig('alipay_setting'); + View::assign("key", "alipay_setting"); + View::assign("data", $config); + return View::fetch('Config/alipay'); + } + //签到设置 public function sign(Request $request) { @@ -79,10 +70,6 @@ class Config extends Base { // 获取小程序配置 $config = getConfig('miniprogram_setting'); - - // 获取旧的微信小程序配置,用于兼容 - $wechat_setting = getConfig('wechat_setting'); - // 获取所有微信支付商户信息 $merchants = []; $weixinpay_setting = getConfig('weixinpay_setting'); @@ -95,13 +82,49 @@ class Config extends Base ]; } } - View::assign("data", $config); - View::assign("wechat_setting", $wechat_setting); View::assign("merchants", $merchants); return View::fetch('Config/miniprogram'); } + //H5页面 + public function h5(Request $request) + { + // 获取H5页面配置 + $config = getConfig('h5_setting'); + + // 获取所有微信支付商户信息 + $wxmerchants = []; + $weixinpay_setting = getConfig('weixinpay_setting'); + if (!empty($weixinpay_setting) && !empty($weixinpay_setting['merchants'])) { + foreach ($weixinpay_setting['merchants'] as $index => $merchant) { + $wxmerchants[$index] = [ + 'id' => $index, + 'name' => $merchant['name'], + 'mch_id' => $merchant['mch_id'] + ]; + } + } + + // 获取所有支付宝商户信息 + $alimerchants = []; + $alipay_setting = getConfig('alipay_setting'); + if (!empty($alipay_setting) && !empty($alipay_setting['merchants'])) { + foreach ($alipay_setting['merchants'] as $index => $merchant) { + $alimerchants[$index] = [ + 'id' => $index, + 'name' => $merchant['name'], + 'appId' => $merchant['appId'] + ]; + } + } + + View::assign("data", $config); + View::assign("wxmerchants", $wxmerchants); + View::assign("alimerchants", $alimerchants); + return View::fetch('Config/h5'); + } + //系统设置 public function systemconfig(Request $request) { @@ -184,6 +207,39 @@ class Config extends Base ($redis->getRedis())->del('config:miniprogram_setting'); } + // 处理H5页面配置 + if ($data['key'] == 'h5_setting' && isset($data['h5apps']) && is_array($data['h5apps'])) { + // 检查是否有默认H5 + $hasDefault = false; + $prefixes = []; + foreach ($data['h5apps'] as $index => $h5app) { + if (isset($h5app['is_default']) && $h5app['is_default'] == 1) { + $hasDefault = true; + } + + // 验证订单前缀 + if (!empty($h5app['order_prefix'])) { + if (strlen($h5app['order_prefix']) != 2) { + return $this->renderError('H5应用"' . $h5app['name'] . '"的订单前缀必须是2位字符'); + } + + if (in_array($h5app['order_prefix'], $prefixes)) { + return $this->renderError('订单前缀"' . $h5app['order_prefix'] . '"重复,每个H5应用的前缀必须唯一'); + } + + $prefixes[] = $h5app['order_prefix']; + } + } + + if (!$hasDefault) { + return $this->renderError('请至少设置一个默认H5应用'); + } + + // 清除旧的H5配置缓存 + $redis = new RedisHelper(); + ($redis->getRedis())->del('config:h5_setting'); + } + // 处理同步地址数据格式 if ($data['key'] == 'systemconfig') { $syncAddresses = []; @@ -234,6 +290,12 @@ class Config extends Base ($redis->getRedis())->del('config:tencent_sms_config'); } + if ($data['key'] == 'alipay_setting') { + //清除redis缓存:alipay_setting + $redis = new RedisHelper(); + ($redis->getRedis())->del('config:alipay_setting'); + } + $result = setConfig($data['key'], $data); if ($result) { return $this->renderSuccess('修改成功'); diff --git a/app/admin/route/app.php b/app/admin/route/app.php index 0ed0663..83c3cb2 100755 --- a/app/admin/route/app.php +++ b/app/admin/route/app.php @@ -272,14 +272,16 @@ Route::rule('admin_operationlog', 'Admins/admin_operationlog', 'GET|POST'); Route::rule('admin_goods_log', 'Admins/admin_goods_log', 'GET|POST'); #============================ -#Config.网站配置 +#Config.php配置 #============================ Route::get('base', 'Config/base'); -Route::get('sign', 'Config/sign');//签到设置 Route::get('weixinpay', 'Config/weixinpay'); +Route::get('alipay', 'Config/alipay'); +Route::get('sign', 'Config/sign'); Route::get('uploadsFile', 'Config/uploads'); //上传设置 Route::get('systemconfig', 'Config/systemconfig'); //系统设置 -Route::get('miniprogram', 'Config/miniprogram'); //微信小程序配置 +Route::get('miniprogram', 'Config/miniprogram'); //微信小程序 +Route::get('h5', 'Config/h5'); //H5页面配置 Route::post('update', 'Config/update'); Route::get('wechatofficialaccount', 'Config/wechatofficialaccount'); diff --git a/app/admin/view/Config/alipay.html b/app/admin/view/Config/alipay.html new file mode 100644 index 0000000..f0b6a5b --- /dev/null +++ b/app/admin/view/Config/alipay.html @@ -0,0 +1,231 @@ +{include file="Public:header2"/} + + +
+
+
+
+
+
+
+
+
+ 支付宝商户号配置。权重越高,支付几率越多。 +
+
+ + +
+ {if isset($data.merchants) && is_array($data.merchants)} + {foreach $data.merchants as $index => $merchant} +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ {/foreach} + {else} + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ {/if} +
+ +
+
+ + +
+
+
+
+
+
+
+
+
+{include file="Public:footer"/} + + + \ No newline at end of file diff --git a/app/admin/view/Config/h5.html b/app/admin/view/Config/h5.html new file mode 100644 index 0000000..fad77c3 --- /dev/null +++ b/app/admin/view/Config/h5.html @@ -0,0 +1,468 @@ +{include file="Public:header2"/} + + +
+
+
+
+
H5页面配置
+
+
+
+
+
+ 配置多个H5应用,系统将根据域名自动匹配使用哪个H5应用。若请求域名未匹配到对应H5应用,则使用默认H5应用配置。 +
+
+ + +
+ + {if isset($data.h5apps) && is_array($data.h5apps)} + {foreach $data.h5apps as $index => $h5app} +
+
+ +
+ +
+
+ +
+ +
+ +
设为默认后将用于未匹配域名的请求
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
多个域名使用英文逗号分隔,如:example.com,www.example.com
+
+ +
+ +
+ +
+
长度为2位字符,用于标识订单来源H5应用
+
+ +
+ +
+
+
支付宝支付
+
微信支付
+
+ + +
+
+ {if isset($alimerchants) && is_array($alimerchants) && count($alimerchants) > 0} + {foreach $alimerchants as $merchant_id => $merchant} +
+ +
+ {/foreach} + {else} +
暂无可用支付宝商户,请先在支付宝支付设置中添加商户
+ {/if} +
+
+ + + +
+
+ + +
+ {/foreach} + {else} + +
+
+ +
+ +
+
+ +
+ +
+ +
设为默认后将用于未匹配域名的请求
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
多个域名使用英文逗号分隔,如:example.com,www.example.com
+
+ +
+ +
+ +
+
长度为2位字符,用于标识订单来源H5应用
+
+ +
+ +
+
+
支付宝支付
+
微信支付
+
+ + +
+
+ {if isset($alimerchants) && is_array($alimerchants) && count($alimerchants) > 0} + {foreach $alimerchants as $merchant_id => $merchant} +
+ +
+ {/foreach} + {else} +
暂无可用支付宝商户,请先在支付宝支付设置中添加商户
+ {/if} +
+
+ + + +
+
+ + +
+ {/if} +
+ +
+
+ + +
+
+
+
+
+
+
+
+
+{include file="Public:footer"/} + + + \ No newline at end of file diff --git a/app/admin/view/Config/miniprogram.html b/app/admin/view/Config/miniprogram.html index 15a1805..d6f5279 100755 --- a/app/admin/view/Config/miniprogram.html +++ b/app/admin/view/Config/miniprogram.html @@ -32,7 +32,7 @@
- {if isset($data.miniprograms) && is_array($data.miniprograms)} + {foreach $data.miniprograms as $index => $miniprogram}
@@ -100,74 +100,7 @@
{/foreach} - {else} - -
-
- -
- -
-
- -
- -
- -
设为默认后将用于未匹配域名的请求
-
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
多个域名使用英文逗号分隔,如:example.com,www.example.com
-
- -
- -
- -
-
长度为2位字符,用于标识订单来源小程序
-
- -
- -
-
- {if isset($merchants) && is_array($merchants)} - {foreach $merchants as $merchant_id => $merchant} -
- -
- {/foreach} - {else} -
暂无可用商户,请先在微信支付设置中添加商户
- {/if} -
-
-
- - -
- {/if} +
diff --git a/app/admin/view/Config/weixinpay.html b/app/admin/view/Config/weixinpay.html index cc23fb8..a0e8de7 100755 --- a/app/admin/view/Config/weixinpay.html +++ b/app/admin/view/Config/weixinpay.html @@ -53,6 +53,18 @@
+
+ +
+ +
+
+
+ +
+ +
+
{/foreach} @@ -89,6 +101,18 @@ +
+ +
+ +
+
+
+ +
+ +
+
{/if} @@ -199,6 +223,18 @@ +
+ +
+ +
+
+
+ +
+ +
+
`; diff --git a/app/api/controller/Infinite.php b/app/api/controller/Infinite.php index dc932f6..de37cd0 100755 --- a/app/api/controller/Infinite.php +++ b/app/api/controller/Infinite.php @@ -507,7 +507,7 @@ class Infinite extends Base if (empty($user['mobile'])) { return $this->renderError('请先绑定手机号', [], -9); } - + $ad_id = request()->header('adid'); $goods_id = request()->param('goods_id/d', 0); #盒子ID $prize_num = request()->param('prize_num/d', 0); #抽几发 @@ -516,9 +516,10 @@ class Infinite extends Base $use_money2_is = request()->param('use_money2_is/d', 0); #0不抵扣 1抵扣 货币2抵扣 $coupon_id = request()->param('coupon_id'); //优惠券 $is_mibao = request()->param('is_mibao/d', 0); //连击赏下 是否是抽的秘宝池 1是 0否 + $pay_type = request()->param('pay_type/d', 1); //1.小程序微信支付,2.h5支付宝,3.app微信,4.app支付宝 #盒子信息 - $goods = Goodsmodel::field('id,title,imgurl_detail,type,price,status,is_shou_zhe,choujiang_xianzhi,quanju_xiangou,daily_xiangou')->where(['id' => $goods_id]) + $goods = Goodsmodel::field('*')->where(['id' => $goods_id]) ->find(); if (!$goods) { return $this->renderError("盒子不存在"); @@ -566,12 +567,6 @@ class Infinite extends Base return $this->renderError('请求错误'); } - // $is_goodslist = GoodsList::field('id') - // ->where($where) - // ->find(); - // if (!$is_goodslist) { - // return $this->renderError('暂无奖品信息'); - // } if ($goods['type'] == 9) { $prize_num = intval($prize_num); @@ -584,7 +579,7 @@ class Infinite extends Base return $this->renderError("秘宝池抽奖次数不足"); } } else { - if ($prize_num != 1 && $prize_num != 3 && $prize_num != 5 && $prize_num != 10 && $prize_num != 50) { + if ($prize_num != 1 && $prize_num != 3 && $prize_num != 5 && $prize_num != 10) { return $this->renderError("请求参数错误!!!"); } } @@ -621,23 +616,36 @@ class Infinite extends Base $num = 1; } + $res = []; + + if ($goods['quanju_xiangou'] > 0) { + // 查看有没有未支付的订单,未支付的订单要先作废 + Order::where('goods_id', '=', $goods_id) + ->where('user_id', '=', $user['id']) + ->where('status', '=', 0) + ->update(['status' => 2]); + } if ($goods['daily_xiangou'] > 0) { // 查看一天内有没有未支付的订单,未支付的订单要先作废 - $order_info = Order::where('goods_id', '=', $goods_id) + Order::where('goods_id', '=', $goods_id) ->where('user_id', '=', $user['id']) - ->where('num', '=', $num) ->where('status', '=', 0) ->where('addtime', '>=', time() - 86400) - ->find(); - if ($order_info) { - $order_info->status = 2; - $order_info->save(); - } + ->update(['status' => 2]); } - - $res = []; - $order_num = create_order_no('MH_', 'order', 'order_num'); - + $attach = 'order_wxs'; + if ($goods['type'] == 16) { + $attach = 'order_fbs'; + } + $title = '购买盒子' . $goods['title']; + $payRes = \app\common\server\platform\PlatformFactory::createPay($user, $paymentResult['price'], $title, $attach, "MH_"); + if ($payRes['status'] !== 1) { + Db::rollback(); + #删除redis + $redis->del($redis_key); + return $this->renderError("购买失败,请刷新重试"); + } + $order_num = $payRes['data']['order_no']; #创建订单 $res[] = $order_id = Order::insertGetId([ 'user_id' => $user['id'], @@ -657,7 +665,7 @@ class Infinite extends Base 'goods_imgurl' => $goods['imgurl_detail'], 'prize_num' => $prize_num, 'status' => 0, - 'pay_type' => 1,#1微信 2支付宝 + 'pay_type' => $pay_type,#1微信 2支付宝 'order_type' => $goods['type'], 'addtime' => time(), 'coupon_id' => $paymentResult['coupon_id'], @@ -667,49 +675,14 @@ class Infinite extends Base 'ad_id' => $ad_id, 'click_id' => $user['click_id'] ]); - if ($goods['quanju_xiangou'] > 0) { - - // 查看有没有未支付的订单,未支付的订单要先作废 - Order::where('goods_id', '=', $goods_id) - ->where('user_id', '=', $user['id']) - ->where('status', '=', 0) - ->where('order_num', '!=', $order_num) - ->update(['status' => 2]); - - } - if ($goods['daily_xiangou'] > 0) { - - // 查看一天内有没有未支付的订单,未支付的订单要先作废 - Order::where('goods_id', '=', $goods_id) - ->where('user_id', '=', $user['id']) - ->where('status', '=', 0) - ->where('addtime', '>=', time() - 86400) - ->where('order_num', '!=', $order_num) - ->update(['status' => 2]); - - } - #微信支付金额大于0 if ($paymentResult['price'] > 0) { - $body = '购买盒子' . $goods['title']; - $attach = 'order_wxs'; - if ($goods['type'] == 16) { - $attach = 'order_fbs'; - } - // $isTest = \app\common\helper\ConfigHelper::getSystemTestKey("disable_wechat_pay"); - // if ($isTest == "1") { - // Db::rollback(); - // #删除redis - // $redis->del($redis_key); - // return $this->renderError("支付未开放"); - // } - $payRes = (new Pay())->wxCreateOrder($order_num, $paymentResult['price'], $user['id'], $body, $attach); if ($payRes['status'] == 1) { #结果集 $new_data = [ 'status' => 1, 'order_num' => $order_num, - 'res' => $payRes['data'], + 'res' => $payRes['data']['res'], ]; } else { #删除redis diff --git a/app/api/controller/Login.php b/app/api/controller/Login.php index d379e19..8d590d6 100755 --- a/app/api/controller/Login.php +++ b/app/api/controller/Login.php @@ -196,10 +196,16 @@ class Login extends Base $logMessages[] = '用户开始登录: ' . $code; $click_id = request()->header('clickid'); - $wxServer = new \app\common\server\Wx($this->app); - $user_base = $wxServer->getOpenid($code); - $openid = $user_base['openid']; - + $wxPlatform = \app\common\server\platform\PlatformFactory::create(); + $openInfo = $wxPlatform->getOpenid($code); + if ($openInfo['status'] == 0) { + return $this->renderError($openInfo['msg']); + } + $openid = $openInfo['data']['openid']; + $wx_unionid = null; + if (isset($openInfo['data']['unionid'])) { + $wx_unionid = $openInfo['data']['unionid']; + } // 添加Redis防抖锁 $redis = (new RedisHelper())->getRedis(); $lockKey = 'login:debounce:' . $openid; @@ -208,11 +214,9 @@ class Login extends Base Log::warning(end($logMessages)); return $this->renderError('请勿频繁登录,请稍后再试'); } - + $user = null; - $wx_unionid = null; - if ($user_base['unionid'] != null && $user_base['unionid'] != '') { - $wx_unionid = $user_base['unionid']; + if ($wx_unionid != null && $wx_unionid != '') { $user = User::getInfo(['unionid' => $wx_unionid]); } if ($user == null) { @@ -257,7 +261,7 @@ class Login extends Base } else { } - + // 检查UserAccount是否存在 $userAccount = UserAccount::where(['user_id' => $user['id']])->find(); if ($userAccount) { @@ -462,7 +466,7 @@ class Login extends Base $retrieved_openid = $user_base['openid']; $openid = $retrieved_openid; - + // 添加Redis防抖锁 $redis = (new RedisHelper())->getRedis(); $lockKey = 'login:h5:debounce:' . $openid; @@ -470,7 +474,7 @@ class Login extends Base Log::warning('用户公众号登录请求过于频繁: ' . $openid); return $this->renderError('请勿频繁登录,请稍后再试'); } - + $user = null; if ($user_base['unionid'] != null && $user_base['unionid'] != '') { @@ -670,15 +674,18 @@ class Login extends Base $user = $this->getUser(); $user_id = $user['id']; $code = request()->param("code", ''); - $wxServer = new \app\common\server\Wx($this->app); - $mobile = $wxServer->getMobile($code); - // return $this->renderError($mobile,[$mobile,$code]); + $wxPlatform = \app\common\server\platform\PlatformFactory::create(); + $mobileRes = $wxPlatform->getMobile($code); + if ($mobileRes['status'] == 0 ) { + return $this->renderError($mobileRes['msg']); + } + if (!isset($mobileRes['data']['phoneNumber'])) { + return $this->renderError('获取手机号失败'); + } + $mobile = $mobileRes['data']['phoneNumber']; Db::startTrans(); $res = []; - // $res[] = User::where(['id' => $user['id']])->update([ - // 'mobile' => $mobile, - // 'update_time' => time(), - // ]); + $data = []; $user_mobile = User::where(['mobile' => $mobile])->find(); if ($user_mobile) { @@ -707,9 +714,7 @@ class Login extends Base $res[] = User::where(['id' => $user['id']])->delete(); $res[] = UserAccount::where(['user_id' => $user_id])->delete(); $data['token'] = $account_token; - // $res[] = UserAccount::where(['user_id' => $user['id']])->update([ - // 'token_time' => time(), - // ]); + } else { $res[] = User::where(['id' => $user['id']])->update([ 'mobile' => $mobile, @@ -864,7 +869,7 @@ class Login extends Base $mobile = request()->param("mobile", ''); $code = request()->param("code", ''); $pid_pid = request()->param('pid', 0); - + // 验证必要参数 if (empty($mobile) || empty($code)) { $logMessages[] = '手机号或验证码为空: ' . $mobile; @@ -874,21 +879,21 @@ class Login extends Base $logMessages[] = '用户开始手机号登录: ' . $mobile; $click_id = request()->header('clickid'); - + // 验证手机验证码 $redis = (new RedisHelper())->getRedis(); $redisKey = "VerificationCode:{$mobile}"; $redisCode = $redis->get($redisKey); - + if (empty($redisCode) || $redisCode != $code) { $logMessages[] = '验证码错误: ' . $code . ',正确验证码: ' . $redisCode; Log::error(end($logMessages)); return $this->renderError('验证码错误'); } - + // 验证通过后删除Redis中的验证码 $redis->del($redisKey); - + // 添加Redis防抖锁 $lockKey = 'login:mobile:debounce:' . $mobile; if (!$redis->set($lockKey, 1, ['nx', 'ex' => 3])) { @@ -896,7 +901,7 @@ class Login extends Base Log::warning(end($logMessages)); return $this->renderError('请勿频繁登录,请稍后再试'); } - + // 检查用户是否已存在 $user = User::getInfo(['mobile' => $mobile]); @@ -926,7 +931,7 @@ class Login extends Base $ip_city = $result['city']; $ip_adcode = $result['adcode']; } - + // 检查UserAccount是否存在 $userAccount = UserAccount::where(['user_id' => $user['id']])->find(); if ($userAccount) { @@ -982,22 +987,22 @@ class Login extends Base $pid = $pid_info; } } - + // 开始事务 Db::startTrans(); - + // 生成随机昵称和头像 $randx = rand(1000, 9999); $nickname = "手机用户" . $randx; $logMessages[] = $nickname; - + // 使用Identicon生成默认头像 $randx = rand(10000, 99999); $identicon = new \Identicon\Identicon(); $imageData = $identicon->getImageData($mobile . $nickname); $uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png"); $headimg = $uploadResult['full_url']; - + // 插入用户记录 $res[] = $user_id = User::insertGetId([ 'openid' => '', // 手机号注册无openid @@ -1015,7 +1020,7 @@ class Login extends Base if ($uid) { User::where('id', $user_id)->update(['uid' => $uid]); } - + // 如果是测试环境,给新用户赠送钻石 // $isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test"); // if ($isTest == "1") { @@ -1035,12 +1040,12 @@ class Login extends Base // } // } // } - + // 生成账号token $time = time(); $token_num = getRandStr(10); $account_token = user_md5($user_id . $token_num . $time); - + // 获取IP和地理位置信息 $last_login_ip1 = $this->getRealIp(); $result = $this->ip_location($last_login_ip1); @@ -1052,7 +1057,7 @@ class Login extends Base $ip_city = $result['city']; $ip_adcode = $result['adcode']; } - + // 插入用户账号信息 $res[] = UserAccount::insert([ 'user_id' => $user_id, @@ -1078,7 +1083,7 @@ class Login extends Base $res[] = User::changeDraw($pid, 1, 5, '获得一张抽奖券', $user_id); } } - + if (resCheck($res)) { // 新用户注册也要记录登录日志 UserLoginLog::recordLogin( diff --git a/app/common.php b/app/common.php index 978b6e9..3206639 100755 --- a/app/common.php +++ b/app/common.php @@ -316,6 +316,28 @@ if (!function_exists('create_order_no')) { return $order_no; } } + +if (!function_exists('create_order_no_new')) { + /** + * 生成订单号 + * @param string $pre 订单前缀 + * @param string $tale 表名 + * @param string $field 字段名 + * @return string + */ + function create_order_no_new($pre = "", $merchant_prefix = "", $project_prefix = "", $pay_type = "") + { + $pre = $pre . $merchant_prefix . $project_prefix . $pay_type; + $order_no = $pre . date('Ymd') . substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8) . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT); + $r = Db::name('order')->field('id')->where(['order_num' => $order_no])->find(); + if ($r) { + $order_no = create_order_no_new($pre, $merchant_prefix, $project_prefix, $pay_type); + } + return $order_no; + } +} + + if (!function_exists('getPrizeCode')) { /** @@ -724,20 +746,20 @@ if (!function_exists('order_callback')) { // 订单支付日志 function writelog($filename, $content) { - try { - $date = date('Y-m-d'); - $file = "./pay_log/" . $date; - if (!is_dir($file)) { - mkdir($file); + try { + $date = date('Y-m-d'); + $file = "./pay_log/" . $date; + if (!is_dir($file)) { + mkdir($file); + } + $file = $file . "/" . $filename . ".txt"; + $content = "【收到信息" . date("Y-m-d H:i:s", time()) . "】" . $content . "\r\n\r\n"; + $open = fopen($file, "a"); + fwrite($open, $content); + fclose($open); + } catch (\Throwable $th) { + } - $file = $file . "/" . $filename . ".txt"; - $content = "【收到信息" . date("Y-m-d H:i:s", time()) . "】" . $content . "\r\n\r\n"; - $open = fopen($file, "a"); - fwrite($open, $content); - fclose($open); - } catch (\Throwable $th) { - - } } @@ -900,10 +922,8 @@ function generatePayNotifySign($data) foreach ($data as $key => $value) { $stringA .= "{$key}={$value}&"; } - - // 获取密钥 - $wxpay_config = getConfig('wxpay'); - $key = $wxpay_config['key'] ?? 'l044imysi1vsmobyrkkfnaniu5bhiupd'; // 默认密钥 + //加密 + $key = 'l044imysi1vsmobyrkkfnaniu5bhiupd'; // 默认密钥 // 加上密钥 $stringA .= "key=" . $key; diff --git a/app/common/model/GoodsExtend.php b/app/common/model/GoodsExtend.php index d80bb21..9bb48b1 100644 --- a/app/common/model/GoodsExtend.php +++ b/app/common/model/GoodsExtend.php @@ -42,16 +42,7 @@ class GoodsExtend extends Base */ public static function getGoodsExtendByGoodsId($goodsId, $goods_type) { - // // 生成缓存键 - // $redis = (new \app\common\server\RedisHelper())->getRedis(); - // $cache_key = "goods_extend:{$goodsId}:{$goods_type}"; - - // // 尝试从缓存获取数据 - // $cached_data = $redis->get($cache_key); - // if ($cached_data) { - // return json_decode($cached_data, true); - // } - + $goods_extend = self::where('goods_id', $goodsId)->find(); if (!$goods_extend) { // 从goods_type表获取默认值 @@ -73,12 +64,7 @@ class GoodsExtend extends Base ]; } } - - // // 将数据存入缓存,设置5分钟过期时间 - // if ($goods_extend) { - // $redis->set($cache_key, json_encode($goods_extend), 300); - // } - + return $goods_extend; } } \ No newline at end of file diff --git a/app/common/server/platform/BasePlatform.php b/app/common/server/platform/BasePlatform.php new file mode 100644 index 0000000..bdac4b3 --- /dev/null +++ b/app/common/server/platform/BasePlatform.php @@ -0,0 +1,143 @@ +code = ''; + $this->env = ''; + } + + /** + * 抽象方法:支付(子类必须实现) + * @param object $data [$user,$price,order_type] + + */ + abstract public function pay(array $data): array; + /** + * 订单发货 + * @param mixed $user 用户 + * @param mixed $order_num 订单号 + * @return void + */ + abstract public function post_order($user, $order_num): int; + /** + * 获取urlLinks + * @param mixed $userId + * @return void + */ + abstract public function generateUrlLink($userId): array; + /** + * 获取用户openId + * @param mixed $code + * @return void + */ + abstract public function getOpenid($code): array; + /** + * + * 获取手机号 + * @param mixed $code + * @return void + */ + abstract public function getMobile($code = ''): array; + /** + * 普通方法(子类自动继承) + */ + public function getPlatformInfo(): array + { + return [ + 'code' => $this->code, + 'env' => $this->env, + 'time' => date('Y-m-d H:i:s') + ]; + } + + /** + * 产生一个指定长度的随机字符串,并返回给用户 + * @param type $len 产生字符串的长度 + * @return string 随机字符串 + */ + protected function genRandomString($len = 32) + { + $chars = array( + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9" + ); + $charsLen = count($chars) - 1; + // 将数组打乱 + shuffle($chars); + $output = ""; + for ($i = 0; $i < $len; $i++) { + $output .= $chars[mt_rand(0, $charsLen)]; + } + return $output; + } + +} \ No newline at end of file diff --git a/app/common/server/platform/H5Platform.php b/app/common/server/platform/H5Platform.php new file mode 100644 index 0000000..26bd09c --- /dev/null +++ b/app/common/server/platform/H5Platform.php @@ -0,0 +1,70 @@ +code = 'WEB_H5'; + $this->env = 'h5'; + } + + public function pay(array $data): array + { + // echo "H5支付:{$amount}分,订单号:{$orderId}\n"; + // 实际项目中这里调用支付SDK + return []; + } + /** + * 发货 + * @param mixed $openid + * @param mixed $access_token + * @param mixed $order_num + * @param mixed $title + * @return int + */ + public function post_order($user, $order_num): int + { + + return 1; + } + + + /** + * 生成URL链接 + * @param int $userId 用户ID + * @return array + */ + public function generateUrlLink($userId): array + { + + return ['status' => 1, 'data' => ""]; + } + + /** + * 获取手机号 + * @param string $code 手机号获取凭证 + * @return array + */ + public function getMobile($code = ''): array + { + + + return ['status' => 1, 'data' => ""]; + } + + /** + * 获取openid + * @param string $code 登录凭证 + * @return array + */ + public function getOpenid($code): array + { + + return ['status' => 1, 'data' => ""]; + } + +} \ No newline at end of file diff --git a/app/common/server/platform/MiniProgramPlatform.php b/app/common/server/platform/MiniProgramPlatform.php new file mode 100644 index 0000000..9ca8fbc --- /dev/null +++ b/app/common/server/platform/MiniProgramPlatform.php @@ -0,0 +1,732 @@ +code = 'MP-WEIXIN'; + $this->env = 'miniProgram'; + + $this->mp_miniprogram = \app\common\helper\MiniprogramHelper::getMiniprogramConfig(); + + if (!empty($this->mp_miniprogram['appid'])) { + $this->wx_appid = $this->mp_miniprogram['appid']; + $this->wx_secret = $this->mp_miniprogram['app_secret']; + } + } + /** + * Summary of pay [$user,$price,title,attach] + * @param mixed $data + * @return array{data: array, status: int|array{msg: string, status: int}} + */ + public function pay(array $data): array + { + $data += ['user' => null, 'price' => 0, 'title' => '', 'attach' => 'order_wxs', 'pre' => 'MH_']; + [ + 'user' => $user, + 'price' => $price, + 'title' => $title, + 'attach' => $attach, + 'pre' => $pre + ] = $data; + if ($user == null) { + //抛出异常 + throw new \Exception('用户信息为空'); + } + $project_prefix = $this->mp_miniprogram['order_prefix']; + if ($price <= 0) { + //生成订单号,订单号为:ML_DRAYDMP02025018.... ML_ 前缀(固定3位),DRA 商户号(固定3位),YD 项目,固定2位,MP0 表示微信小程序支付 + $order_no = create_order_no_new($pre, "MON", $project_prefix, "MP0"); + return [ + 'status' => 1, + 'data' => [ + 'order_no' => $order_no, + 'res' => [] + ] + ]; + } + $title = mb_substr($title, 0, 30); + + $prefix = $this->GetPrefix(); + //生成订单号,订单号为:ML_DRAYDMP02025018.... ML_ 前缀(固定3位),DRA 商户号(固定3位),YD 项目,固定2位,MP0 表示微信小程序支付 + $order_no = create_order_no_new($pre, $prefix, $project_prefix, "MP0"); + $openid = $user['openid']; + $payment_type = 'wxpay'; + $order_type = $attach; + $user_id = $user ? $user['id'] : 0; + // 支付使用的随机数 + $nonce_str = $this->genRandomString(); + // 回调使用的随机数(与支付随机数分离) + $callback_nonce_str = $this->genRandomString(); + // 生成新的支付通知URL + $notifyUrl = generatePayNotifyUrl($payment_type, $order_type, $user_id, $order_no, $callback_nonce_str); + $is_test = $user['istest']; + if ($is_test == 2) { + $price = 0.01; + } + $params['appid'] = $this->wx_appid; + $params['mch_id'] = $this->getMchId(); + $params['nonce_str'] = $nonce_str; + $params['body'] = $title; + $params['attach'] = $attach; + $params['out_trade_no'] = $order_no; + $params['notify_url'] = $notifyUrl; + $params['total_fee'] = round($price * 100, 2); + $params['spbill_create_ip'] = $this->get_client_ip(); + $params['trade_type'] = 'JSAPI'; + $params['openid'] = $openid; + $params['sign'] = $this->MakeSign($params); + $xml = $this->data_to_xml($params); + $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; + $response = $this->postXmlCurl($xml, $url); + $result = $this->xml_to_data($response); + if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') { + // 将通知URL和随机字符串保存到order_notify表中 + Db::name('order_notify')->insert([ + 'order_no' => $order_no, + 'notify_url' => $notifyUrl, + 'nonce_str' => $callback_nonce_str, + 'pay_time' => date('Y-m-d H:i:s'), + 'pay_amount' => $price, + 'status' => 0, + 'retry_count' => 0, + 'create_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s') + ]); + $time = time(); + $res['appId'] = $this->wx_appid; + $res["timeStamp"] = (string) $time; + $res["nonceStr"] = $nonce_str; + $res["package"] = "prepay_id=" . $result['prepay_id']; + $res["signType"] = 'MD5'; + $res["paySign"] = $this->MakeSign($res); + return [ + 'status' => 1, + 'data' => [ + 'order_no' => $order_no, + 'res' => $res + ] + ]; + } + + // 记录支付失败日志 + $error_message = ''; + if (isset($result['return_code']) && $result['return_code'] === 'FAIL') { + $error_message = $result['return_msg'] ?? '未知错误'; + } elseif (isset($result['result_code']) && $result['result_code'] === 'FAIL') { + $error_code = $result['err_code'] ?? ''; + $error_message = $result['err_code_des'] ?? $this->error_code($error_code) ?? '未知错误'; + } else { + $error_message = '微信支付接口返回异常'; + } + // $redis = (new \app\common\server\RedisHelper())->getRedis(); + // 记录到ThinkPHP的日志系统中 + Log::error('微信支付失败: ' . json_encode([ + 'order_no' => $order_no, + 'user_id' => $user_id, + 'openid' => $openid, + 'price' => $price, + 'error_message' => $error_message, + 'result' => $result, + 'time' => date('Y-m-d H:i:s') + ], JSON_UNESCAPED_UNICODE)); + + return ['status' => 0, 'msg' => '支付失败:' . $error_message]; + } + /** + * 发货 + * @param mixed $openid + * @param mixed $access_token + * @param mixed $order_num + * @param mixed $title + * @return int + */ + public function post_order($user, $order_num): int + { + $msg = "本单购买商品已发放至[小程序盒柜]"; + if (strpos($order_num, 'FH_') === 0) { + $msg = "本单购买的商品正在打包,请联系客服获取物流信息"; + } + $openid = $user['openid']; + // 根据订单号设置正确的商户配置 + $this->setMerchantByOrderNo($order_num); + $date = new \DateTime(); + // $this->appid + $access_token = $this->get_access_token(); + //订单发货时间 + $formattedDate = $date->format('Y-m-d\TH:i:s'); + $request_url = "https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token=" . $access_token; + $param = '{ + "order_key": { + "order_number_type": 1, + "mchid":"' . $this->getMchId() . '", + "out_trade_no":"' . $order_num . '" + }, + "logistics_type": 4, + "delivery_mode": 1, + "shipping_list": [ + { + "item_desc": "' . $msg . '" + } + ], + "upload_time": "' . $formattedDate . '+08:00", + "payer": { + "openid":"' . $openid . '" + } + }'; + // 记录请求参数日志 + writelog('post_order_log', json_encode([ + 'method' => 'post_order', + 'order_num' => $order_num, + 'openid' => $openid, + 'merchant' => $this->getMchId(), + 'request_url' => $request_url, + 'param' => $param, + 'time' => date('Y-m-d H:i:s') + ])); + + $res = curlPost($request_url, $param); + $res = json_decode($res, true); + + // 记录响应结果日志 + writelog('post_order_log', json_encode([ + 'method' => 'post_order_response', + 'order_num' => $order_num, + 'response' => $res, + 'time' => date('Y-m-d H:i:s') + ])); + + if ($res['errcode'] == 0 && $res['errmsg'] == 'ok') { + return 1; + } else { + // 发货失败,将订单信息存入Redis,等待定时任务重试 + $redis = (new \app\common\server\RedisHelper())->getRedis(); + $key = 'post_order:' . $order_num; + + // 存储发货失败的订单信息 + $orderData = [ + 'openid' => $openid, + 'appid' => $this->wx_appid, + // 不存储access_token,因为可能过期 + 'order_num' => $order_num, + 'title' => '订单发货', + 'merchant' => $this->getMchId(), + 'error_code' => $res['errcode'] ?? 'unknown', + 'error_msg' => $res['errmsg'] ?? 'unknown', + 'retry_count' => 0, + 'last_retry_time' => time(), + 'create_time' => time() + ]; + + // 存入Redis,设置过期时间为3天 + $redis->set($key, json_encode($orderData)); + $redis->expire($key, 3 * 24 * 3600); + + // 记录存入Redis的日志 + writelog('post_order_log', json_encode([ + 'method' => 'post_order_redis_save', + 'order_num' => $order_num, + 'redis_key' => $key, + 'data' => $orderData, + 'time' => date('Y-m-d H:i:s') + ])); + + return 2; + } + } + + + /** + * 生成URL链接 + * @param int $userId 用户ID + * @return array + */ + public function generateUrlLink($userId): array + { + // 获取access_token + $access_token = $this->get_access_token(); + + $url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=" . $access_token; + $param = [ + 'path' => 'pages/index/index', + 'query' => 'user_id=' . $userId, + // 'expire_type' => 0, + // 'expire_time' => time() + 7 * 86400, // 7天后过期 + // 'env_version' => 'release' + ]; + + $result = curlPost($url, json_encode($param)); + $result = json_decode($result, true); + if (isset($result['errcode']) && $result['errcode'] != 0) { + return ['status' => 0, 'msg' => $result['errmsg'] ?? '生成链接失败']; + } + + return ['status' => 1, 'data' => $result]; + } + + /** + * 获取手机号 + * @param string $code 手机号获取凭证 + * @return array + */ + public function getMobile($code = ''): array + { + if (empty($code)) { + return ['status' => 0, 'msg' => '缺少code参数']; + } + + // 获取access_token + $access_token = $this->get_access_token(); + + $url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" . $access_token; + $param = [ + 'code' => $code + ]; + + $result = $this->post_curl_data($url, $param); + // $result = json_decode($result, true); + if (isset($result['errcode']) && $result['errcode'] != 0) { + return ['status' => 0, 'msg' => $result['errmsg'] ?? '获取手机号失败']; + } + + return ['status' => 1, 'data' => $result['phone_info'] ?? []]; + } + + /** + * 获取openid + * @param string $code 登录凭证 + * @return array + */ + public function getOpenid($code): array + { + if (empty($code)) { + return ['status' => 0, 'msg' => '缺少code参数']; + } + + $url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $this->wx_appid . "&secret=" . $this->wx_secret . "&js_code=" . $code . "&grant_type=authorization_code"; + $result = $this->get_curl_data($url); + + if (isset($result['errcode']) && $result['errcode'] != 0) { + return ['status' => 0, 'msg' => $result['errmsg'] ?? '获取openid失败']; + } + + return ['status' => 1, 'data' => $result]; + } + + /** + * 根据订单号设置商户环境 + * + * @param string $orderNo 订单号 + * @return bool 设置成功返回 true,失败返回 false + */ + public function setMerchantByOrderNo(string $orderNo): bool + { + if (strlen($orderNo) < 6) { + return false; + } + + $merchantCode = substr($orderNo, 3, 3); // 截取商户号部分 + + // 获取配置中的商户列表 + $weixinpay_setting = getConfig('weixinpay_setting'); + + if (empty($weixinpay_setting['merchants']) || !is_array($weixinpay_setting['merchants'])) { + return false; + } + + // 查找对应的商户配置 + $merchant = null; + foreach ($weixinpay_setting['merchants'] as $item) { + if ($item['order_prefix'] == $merchantCode) { + $merchant = $item; + break; + } + } + + if (!$merchant) { + return false; + } + + // 设置商户环境 + $this->mp_merchant = $merchant; + $this->mch_id = $merchant['mch_id']; + $this->key = $merchant['keys']; + + return true; + } + + + /** + * 获取access_token + */ + public function get_access_token() + { + return $this->get_access_appid_token($this->wx_appid, $this->wx_secret); + + } + + /** + * 获取access_token + */ + public function get_access_appid_token($appid, $wx_secret) + { + $redis = (new \app\common\server\RedisHelper())->getRedis(); + $redis_key = 'wx_access_token:' . $appid; + + $access_token_info = $redis->get($redis_key); + if ($access_token_info) { + $access_token_info = json_decode($access_token_info, true); + if ($access_token_info['access_token_time'] > time()) { + return $access_token_info['access_token']; + } + } + + $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $appid . "&secret=" . $wx_secret; + $res_access_token = $this->get_curl_data($url); + if (isset($res_access_token['errcode'])) { + throw new \Exception('获取access_token异常'); + } + + $access_token = $res_access_token['access_token']; + $expires_in = $res_access_token['expires_in']; + $access_token_time = time() + $expires_in; + + $data = [ + 'access_token' => $access_token, + 'access_token_time' => $access_token_time, + ]; + + $redis->set($redis_key, json_encode($data), $expires_in - 1800); + + return $access_token; + } + + + /** + * @param $url 请求链接 + */ + public function get_curl_data($url) + { + $headerArray = array("Content-type:application/json;", "Accept:application/json"); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray); + $response = curl_exec($ch); + if ($response) { + curl_close($ch); + return json_decode($response, true); + } else { + $error = curl_errno($ch); + curl_close($ch); + return ['errcode' => 1]; + } + } + + /** + * @param $url 链接 + * @param $data 参数 + * @return mixed + */ + public function post_curl_data($url, $data) + { + $data = json_encode($data); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json; charset=utf-8', + 'Content-Length: ' . strlen($data) + )); + $return_content = curl_exec($ch); + if ($return_content) { + curl_close($ch); + $return_content = json_decode($return_content, true); + return $return_content; + } else { + $error = curl_errno($ch); + curl_close($ch); + return ['errcode' => 1]; + } + } + + // region 商户初始化相关代码 + /** + * 获取当前商户信息(延迟加载) + */ + public function getMerchant(): ?array + { + if ($this->mp_merchant === null) { + $this->initMerchant(); // 第一次访问时才加载 + } + return $this->mp_merchant; + } + + /** + * 获取 mch_id(延迟加载) + */ + public function getMchId(): ?string + { + if ($this->mch_id === null) { + $this->initMerchant(); + } + return $this->mch_id; + } + + /** + * 获取 key(延迟加载) + */ + public function getKey(): ?string + { + if ($this->key === null) { + $this->initMerchant(); + } + return $this->key; + } + + public function GetPrefix(): ?string + { + if ($this->mp_merchant === null) { + $this->initMerchant(); + } + return $this->mp_merchant['order_prefix']; + + } + + /** + * 实际加载商户信息 + */ + private function initMerchant(): void + { + if ( + empty($this->mp_miniprogram) || + empty($this->mp_miniprogram['merchants']) || + !is_array($this->mp_miniprogram['merchants']) + ) { + return; + } + + $weixinpay_setting = getConfig('weixinpay_setting'); + if (empty($weixinpay_setting['merchants']) || !is_array($weixinpay_setting['merchants'])) { + return; + } + + $associatedMerchants = array_values(array_filter($weixinpay_setting['merchants'], function ($merchant) { + return isset($merchant['is_enabled'], $merchant['mch_id']) && + $merchant['is_enabled'] === "1" && + in_array($merchant['mch_id'], $this->mp_miniprogram['merchants']); + })); + + if (!empty($associatedMerchants)) { + $merchant = WxPayHelper::getRandomMerchant($associatedMerchants); + $this->mp_merchant = $merchant; + $this->mch_id = $merchant['mch_id']; + $this->key = $merchant['keys']; + } + } + + // endregion + + + /** + * 生成签名 + * @return 签名 + */ + public function MakeSign($params) + { + //签名步骤一:按字典序排序数组参数 + ksort($params); + $string = $this->ToUrlParams($params); + //签名步骤二:在string后加入KEY + $string = $string . "&key=" . $this->getKey(); + //签名步骤三:MD5加密 + $string = md5($string); + //签名步骤四:所有字符转为大写 + $result = strtoupper($string); + return $result; + } + + /** + * 将参数拼接为url: key=value&key=value + * @param $params + * @return string + */ + public function ToUrlParams($params) + { + $string = ''; + if (!empty($params)) { + $array = array(); + foreach ($params as $key => $value) { + $array[] = $key . '=' . $value; + } + $string = implode("&", $array); + } + return $string; + } + + /** + * 输出xml字符 + * @param $params 参数名称 + * return string 返回组装的xml + **/ + public function data_to_xml($params) + { + if (!is_array($params) || count($params) <= 0) { + return false; + } + $xml = ""; + foreach ($params as $key => $val) { + if (is_numeric($val)) { + $xml .= "<" . $key . ">" . $val . ""; + } else { + $xml .= "<" . $key . ">"; + } + } + $xml .= ""; + return $xml; + } + + /** + * 将xml转为array + * @param string $xml + * return array + */ + public function xml_to_data($xml) + { + if (!$xml) { + return false; + } + //将XML转为array + //禁止引用外部xml实体 + libxml_disable_entity_loader(true); + $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); + return $data; + } + + + /** + * 以post方式提交xml到对应的接口url + * + * @param string $xml 需要post的xml数据 + * @param string $url url + * @param bool $useCert 是否需要证书,默认不需要 + * @param int $second url执行超时时间,默认30s + * @throws WxPayException + */ + private function postXmlCurl($xml, $url, $second = 30) + { + $ch = curl_init(); + //设置超时 + curl_setopt($ch, CURLOPT_TIMEOUT, $second); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + //设置header + curl_setopt($ch, CURLOPT_HEADER, FALSE); + //要求结果为字符串且输出到屏幕上 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + //post提交方式 + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); + //运行curl + $data = curl_exec($ch); + //返回结果 + if ($data) { + curl_close($ch); + return $data; + } else { + $error = curl_errno($ch); + curl_close($ch); + return false; + } + } + + /** + * 错误代码 + * @param $code 服务器输出的错误代码 + * return string + */ + public function error_code($code) + { + $errList = array( + 'NOAUTH' => '商户未开通此接口权限', + 'NOTENOUGH' => '用户帐号余额不足', + 'ORDERNOTEXIST' => '订单号不存在', + 'ORDERPAID' => '商户订单已支付,无需重复操作', + 'ORDERCLOSED' => '当前订单已关闭,无法支付', + 'SYSTEMERROR' => '系统错误!系统超时', + 'APPID_NOT_EXIST' => '参数中缺少APPID', + 'MCHID_NOT_EXIST' => '参数中缺少MCHID', + 'APPID_MCHID_NOT_MATCH' => 'appid和mch_id不匹配', + 'LACK_PARAMS' => '缺少必要的请求参数', + 'OUT_TRADE_NO_USED' => '同一笔交易不能多次提交', + 'SIGNERROR' => '参数签名结果不正确', + 'XML_FORMAT_ERROR' => 'XML格式错误', + 'REQUIRE_POST_METHOD' => '未使用post传递参数 ', + 'POST_DATA_EMPTY' => 'post数据不能为空', + 'NOT_UTF8' => '未使用指定编码格式', + ); + if (array_key_exists($code, $errList)) { + return $errList[$code]; + } + } + + function get_client_ip() + { + if (isset($_SERVER['REMOTE_ADDR'])) { + $cip = $_SERVER['REMOTE_ADDR']; + } elseif (getenv("REMOTE_ADDR")) { + $cip = getenv("REMOTE_ADDR"); + } elseif (getenv("HTTP_CLIENT_IP")) { + $cip = getenv("HTTP_CLIENT_IP"); + } else { + $cip = "127.0.0.1"; + } + return $cip; + } + +} \ No newline at end of file diff --git a/app/common/server/platform/PlatformFactory.php b/app/common/server/platform/PlatformFactory.php new file mode 100644 index 0000000..0adaa4c --- /dev/null +++ b/app/common/server/platform/PlatformFactory.php @@ -0,0 +1,46 @@ +header('client', 'MP-WEIXIN'); + } + if ($client == "WEB_H5") { + return new H5Platform(); + } + if ($client == "MP-WEIXIN") { + return new MiniProgramPlatform(); + } + return new MiniProgramPlatform(); + } + + /** + * 创建平台实例 + * @param string $client 客户端类型 + * @return + */ + public static function createPay($user, $price, $title, $attach, $pre = "MH_", $pay_type = 1, $client = null): array + { + $data = [ + 'user' => $user, + 'price' => $price, + 'title' => $title, + 'attach' => $attach, + 'pre' => $pre, + 'pay_type' => $pay_type + ]; + $platform = self::create($client); + return $platform->pay($data); + } +} \ No newline at end of file diff --git a/app/common/service/PayService.php b/app/common/service/PayService.php new file mode 100644 index 0000000..42f5f64 --- /dev/null +++ b/app/common/service/PayService.php @@ -0,0 +1,41 @@ +app = $app; + $this->request = $this->app->request; + //客户端 + $this->client = $this->request->header('client', 'MP-WEIXIN'); + //client + $m = new MiniProgramPlatform(); + } + +} \ No newline at end of file diff --git a/composer.json b/composer.json index a30d54e..07e835b 100755 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ "qcloud/cos-sdk-v5": "^2.6", "yzalis/identicon": "^2.0", "topthink/think-image": "^1.0", - "topthink/think-migration": "^3.1" + "topthink/think-migration": "^3.1", + "alipaysdk/easysdk": "^2.2" }, "require-dev": { "symfony/var-dumper": "^4.2", diff --git a/composer.lock b/composer.lock index e02aab0..06f0485 100755 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,225 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d87efcd19adbf32a7bf40402f4f4d2e9", + "content-hash": "0f1ac8c679e075e85ffcd1bd713e8421", "packages": [ + { + "name": "adbario/php-dot-notation", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/adbario/php-dot-notation.git", + "reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae", + "reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^5.5 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7|^6.6|^7.5|^8.5|^9.5", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "description": "PHP dot notation access to arrays", + "homepage": "https://github.com/adbario/php-dot-notation", + "keywords": [ + "ArrayAccess", + "dotnotation" + ], + "support": { + "issues": "https://github.com/adbario/php-dot-notation/issues", + "source": "https://github.com/adbario/php-dot-notation/tree/2.5.0" + }, + "time": "2022-10-14T20:31:46+00:00" + }, + { + "name": "alibabacloud/tea", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/aliyun/tea-php.git", + "reference": "1619cb96c158384f72b873e1f85de8b299c9c367" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/tea-php/zipball/1619cb96c158384f72b873e1f85de8b299c9c367", + "reference": "1619cb96c158384f72b873e1f85de8b299c9c367", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.4", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "*", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Client of Tea for PHP", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibabacloud", + "client", + "cloud", + "tea" + ], + "support": { + "issues": "https://github.com/aliyun/tea-php/issues", + "source": "https://github.com/aliyun/tea-php" + }, + "time": "2023-05-16T06:43:41+00:00" + }, + { + "name": "alibabacloud/tea-fileform", + "version": "0.3.4", + "source": { + "type": "git", + "url": "https://github.com/alibabacloud-sdk-php/tea-fileform.git", + "reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alibabacloud-sdk-php/tea-fileform/zipball/4bf0c75a045c8115aa8cb1a394bd08d8bb833181", + "reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181", + "shasum": "" + }, + "require": { + "alibabacloud/tea": "^3.0", + "php": ">5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Tea\\FileForm\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com" + } + ], + "description": "Alibaba Cloud Tea File Library for PHP", + "support": { + "issues": "https://github.com/alibabacloud-sdk-php/tea-fileform/issues", + "source": "https://github.com/alibabacloud-sdk-php/tea-fileform/tree/0.3.4" + }, + "time": "2020-12-01T07:24:35+00:00" + }, + { + "name": "alipaysdk/easysdk", + "version": "2.2.3", + "source": { + "type": "git", + "url": "https://github.com/alipay/alipay-easysdk.git", + "reference": "c6008839a22a5fca08e9f8536730f7abfed522d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alipay/alipay-easysdk/zipball/c6008839a22a5fca08e9f8536730f7abfed522d5", + "reference": "c6008839a22a5fca08e9f8536730f7abfed522d5", + "shasum": "" + }, + "require": { + "alibabacloud/tea": "^3.1", + "alibabacloud/tea-fileform": "^0.3.2", + "ext-ctype": "*", + "ext-curl": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": ">=6.3", + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Alipay\\EasySDK\\": "php/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "junying.wjy", + "email": "junying.wjy@antfin.com" + } + ], + "description": "支付宝官方 Alipay Easy SDK", + "support": { + "source": "https://github.com/alipay/alipay-easysdk/tree/v2.2.3" + }, + "time": "2022-11-28T14:04:57+00:00" + }, { "name": "bacon/bacon-qr-code", "version": "2.0.8", diff --git a/config/menu.php b/config/menu.php index fe15e88..c17ae9f 100755 --- a/config/menu.php +++ b/config/menu.php @@ -238,10 +238,18 @@ return [ 'url' => '/admin/weixinpay', 'name' => '微信商户设置', ], + [ + 'url' => '/admin/alipay', + 'name' => '支付宝商户设置', + ], [ 'url' => '/admin/miniprogram', 'name' => '小程序设置', ], + [ + 'url' => '/admin/h5', + 'name' => 'H5设置', + ], [ 'url' => '/admin/systemconfig', 'name' => '系统配置',