1120 lines
42 KiB
PHP
Executable File
1120 lines
42 KiB
PHP
Executable File
<?php
|
||
declare(strict_types=1);
|
||
|
||
namespace app\api\controller;
|
||
|
||
use app\api\controller\Base;
|
||
use app\common\model\User;
|
||
use app\common\model\UserAccount;
|
||
use app\common\server\RedisHelper;
|
||
use \think\Request;
|
||
use think\facade\Db;
|
||
use app\common\model\ProfitDraw;
|
||
use app\common\model\UserLoginIp;
|
||
use app\common\model\UserLoginLog;
|
||
use think\facade\Log;
|
||
use app\common\server\TencentCosUploader;
|
||
use app\common\model\ProfitMoney;
|
||
class Login extends Base
|
||
{
|
||
private $uploader;
|
||
|
||
public function initialize()
|
||
{
|
||
parent::initialize(); // 确保调用父类初始化方法
|
||
|
||
$config = getConfig('uploads');
|
||
if (!$config) {
|
||
$config = []; // 确保config是一个数组
|
||
}
|
||
$this->uploader = new TencentCosUploader($config);
|
||
}
|
||
/**
|
||
* 处理用户的UID
|
||
*
|
||
* @param User $user 用户对象
|
||
*/
|
||
private function processUid($user)
|
||
{
|
||
// 如果用户已有uid,不处理
|
||
if (!empty($user['uid'])) {
|
||
return;
|
||
}
|
||
|
||
// 生成uid
|
||
$uid = $this->generateUid($user['id']);
|
||
if ($uid) {
|
||
// 更新用户uid
|
||
User::where('id', $user['id'])->update(['uid' => $uid]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成用户UID
|
||
*
|
||
* @param int $user_id 用户ID
|
||
* @return string 生成的UID
|
||
*/
|
||
private function generateUid($user_id)
|
||
{
|
||
// 获取用户uid配置
|
||
$user_config = getConfig('user_config');
|
||
if (empty($user_config) || !isset($user_config['uid_type'])) {
|
||
return (string) $user_id; // 默认使用真实ID
|
||
}
|
||
|
||
$uid_type = (int) $user_config['uid_type'];
|
||
$uid_length = isset($user_config['uid_length']) ? (int) $user_config['uid_length'] : 6;
|
||
|
||
// 限制长度范围
|
||
if ($uid_length < 4) {
|
||
$uid_length = 4;
|
||
} elseif ($uid_length > 16) {
|
||
$uid_length = 16;
|
||
}
|
||
|
||
// 根据不同类型生成UID
|
||
switch ($uid_type) {
|
||
case 0: // 真实ID
|
||
return (string) $user_id;
|
||
|
||
case 1: // 数字ID
|
||
// 生成不以0开头的随机数字
|
||
$max_attempts = 10;
|
||
$attempt = 0;
|
||
|
||
while ($attempt < $max_attempts) {
|
||
// 生成随机数字
|
||
$min = pow(10, $uid_length - 1);
|
||
$max = pow(10, $uid_length) - 1;
|
||
$uid = (string) mt_rand($min, $max);
|
||
|
||
// 检查是否唯一
|
||
$exists = User::where('uid', $uid)->count();
|
||
if ($exists == 0) {
|
||
return $uid;
|
||
}
|
||
|
||
$attempt++;
|
||
}
|
||
|
||
// 如果多次尝试后仍无法生成唯一ID,则使用更可靠的方法
|
||
return $this->generateUniqueNumericId($uid_length);
|
||
|
||
case 2: // 随机字符和数字
|
||
$length = max(8, $uid_length); // 字母数字混合至少8位
|
||
|
||
$max_attempts = 10;
|
||
$attempt = 0;
|
||
|
||
while ($attempt < $max_attempts) {
|
||
// 生成随机字母数字
|
||
$characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // 排除容易混淆的字符
|
||
$uid = '';
|
||
|
||
// 确保第一个字符不是数字
|
||
$uid .= $characters[mt_rand(8, strlen($characters) - 1)]; // 从字母开始
|
||
|
||
// 生成剩余字符
|
||
for ($i = 1; $i < $length; $i++) {
|
||
$uid .= $characters[mt_rand(0, strlen($characters) - 1)];
|
||
}
|
||
|
||
// 检查是否唯一
|
||
$exists = User::where('uid', $uid)->count();
|
||
if ($exists == 0) {
|
||
return $uid;
|
||
}
|
||
|
||
$attempt++;
|
||
}
|
||
|
||
// 如果多次尝试后仍无法生成唯一ID,使用时间戳+随机数确保唯一性
|
||
return $this->generateUniqueAlphaNumId($length);
|
||
|
||
default:
|
||
return (string) $user_id;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成唯一的数字ID(备用方法)
|
||
*/
|
||
private function generateUniqueNumericId($length)
|
||
{
|
||
// 使用时间微秒 + 随机数的方式保证唯一性
|
||
$base = microtime(true) * 10000 . mt_rand(1000, 9999);
|
||
$uid = substr(preg_replace('/[^0-9]/', '', $base), 0, $length);
|
||
|
||
// 确保不以0开头且长度正确
|
||
while (strlen($uid) < $length || $uid[0] == '0') {
|
||
$uid = mt_rand(1, 9) . substr($uid, 1);
|
||
$uid = substr($uid, 0, $length);
|
||
}
|
||
|
||
return $uid;
|
||
}
|
||
|
||
/**
|
||
* 生成唯一的字母数字ID(备用方法)
|
||
*/
|
||
private function generateUniqueAlphaNumId($length)
|
||
{
|
||
// 使用时间戳 + 随机字符
|
||
$base = time() . mt_rand(1000, 9999);
|
||
$hash = md5($base);
|
||
|
||
// 转换为字母数字混合
|
||
$uid = '';
|
||
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // 排除容易混淆的字符
|
||
|
||
// 确保第一个字符是字母
|
||
$uid .= $chars[mt_rand(0, 25)]; // 前26个是字母
|
||
|
||
// 生成剩余字符
|
||
for ($i = 1; $i < $length; $i++) {
|
||
$uid .= $chars[mt_rand(0, strlen($chars) - 1)];
|
||
}
|
||
|
||
return $uid;
|
||
}
|
||
/**
|
||
* 微信授权,登录接口 微信登录
|
||
*/
|
||
public function login()
|
||
{
|
||
// 初始化日志收集变量
|
||
$logMessages = [];
|
||
|
||
try {
|
||
$code = request()->param("code", '');
|
||
if (empty($code)) {
|
||
$logMessages[] = '用户未获取到code:' . $code;
|
||
Log::error(end($logMessages));
|
||
return $this->renderError('请求参数错误');
|
||
}
|
||
|
||
$logMessages[] = '用户开始登录: ' . $code;
|
||
$click_id = request()->header('clickid');
|
||
$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;
|
||
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 3])) {
|
||
$logMessages[] = '用户登录请求过于频繁: ' . $openid;
|
||
Log::warning(end($logMessages));
|
||
return $this->renderError('请勿频繁登录,请稍后再试');
|
||
}
|
||
|
||
$user = null;
|
||
if ($wx_unionid != null && $wx_unionid != '') {
|
||
$user = User::getInfo(['unionid' => $wx_unionid]);
|
||
}
|
||
if ($user == null) {
|
||
$user = User::getInfo(['openid' => $openid]);
|
||
}
|
||
|
||
// return $this->renderSuccess("登录成功", $user);
|
||
if ($user) {
|
||
if ($user['click_id'] != $click_id) {
|
||
$res[] = User::where(['id' => $user['id']])->update(['click_id' => $click_id]);
|
||
}
|
||
//设置unionId
|
||
if ($wx_unionid && !empty($wx_unionid)) {
|
||
$unionid = $user['unionid'];
|
||
if ($unionid == null || empty($unionid)) {
|
||
$user['unionid'] = $wx_unionid;
|
||
// User::update($user);
|
||
$user->save();
|
||
}
|
||
}
|
||
|
||
// 检查并生成uid
|
||
$this->processUid($user);
|
||
|
||
#token时间戳
|
||
$time = time();
|
||
#token字符串
|
||
$token_num = getRandStr(10);
|
||
#加密token
|
||
$account_token = user_md5($user['id'] . $token_num . $time);
|
||
#更新账号信息
|
||
$last_login_ip1 = $this->getRealIp();
|
||
$result = $this->ip_location($last_login_ip1);
|
||
$ip_province = '';
|
||
$ip_city = '';
|
||
$ip_adcode = '';
|
||
if ($result) {
|
||
$ip_province = $result['province'];
|
||
$ip_city = $result['city'];
|
||
$ip_adcode = $result['adcode'];
|
||
|
||
} else {
|
||
|
||
}
|
||
|
||
// 检查UserAccount是否存在
|
||
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
|
||
if ($userAccount) {
|
||
// 存在则更新
|
||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
} else {
|
||
// 不存在则新增
|
||
$res[] = UserAccount::insert([
|
||
'user_id' => $user['id'],
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
}
|
||
|
||
// 记录用户登录日志(每天只记录一次)
|
||
UserLoginLog::recordLogin(
|
||
$user['id'],
|
||
'wechat',
|
||
$last_login_ip1,
|
||
''//$ip_province . $ip_city
|
||
);
|
||
|
||
$logMessages[] = '用户登录成功: ' . $code . ' 用户ID: ' . $user['id'] . '用户手机号' . $user['mobile'];
|
||
// 输出收集的所有日志
|
||
Log::info(implode("==》", $logMessages));
|
||
|
||
return $this->renderSuccess("登录成功", $account_token);
|
||
|
||
} else {
|
||
$nickname = request()->param('nickname', '');
|
||
$headimg = request()->param('headimg', '');
|
||
// if (!$nickname) {
|
||
// return $this->renderError('请求参数错误!');
|
||
// }
|
||
|
||
$pid = 0;
|
||
$pid_pid = request()->param('pid', 0);
|
||
|
||
$randx = rand(1000, 9999);
|
||
$nickname = "微信用户" . $randx;
|
||
$logMessages[] = $nickname;
|
||
$randx = rand(10000, 99999);
|
||
$identicon = new \Identicon\Identicon();
|
||
$imageData = $identicon->getImageData($openid . $nickname);
|
||
$uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png");
|
||
$headimg = $uploadResult['full_url'];
|
||
if ($pid_pid) {
|
||
$logMessages[] = "尝试获取推荐人ID: " . $pid_pid;
|
||
$pid_info = User::where('id', '=', $pid_pid)->value("id");
|
||
if ($pid_info) {
|
||
$logMessages[] = "获取推荐人ID成功: " . $pid_info;
|
||
$pid = $pid_info;
|
||
}
|
||
}
|
||
Db::startTrans();
|
||
|
||
$res[] = $user_id = User::insertGetId([
|
||
'openid' => $openid,
|
||
'nickname' => $nickname,
|
||
'headimg' => $headimg,
|
||
'pid' => $pid,
|
||
'addtime' => time(),
|
||
'click_id' => $click_id,
|
||
'unionid' => $wx_unionid,
|
||
'uid' => '',
|
||
]);
|
||
|
||
// 生成用户uid
|
||
$uid = $this->generateUid($user_id);
|
||
if ($uid) {
|
||
User::where('id', $user_id)->update(['uid' => $uid]);
|
||
}
|
||
// $isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
|
||
// if ($isTest == "1") {
|
||
// $userCount = ProfitMoney::where('user_id', $user_id)
|
||
// ->where('type', 8)
|
||
// ->where('content', '=', '内测免费送')
|
||
// ->count();
|
||
// if ($userCount == 0) {
|
||
// // 使用Redis锁防止重复获取
|
||
// $redis = (new RedisHelper())->getRedis();
|
||
// $lockKey = 'user:beta_reward:' . $user_id;
|
||
// if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
|
||
// $res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||
// $logMessages[] = '赠送钻石: 50000';
|
||
// // 释放锁
|
||
// $redis->del($lockKey);
|
||
// }
|
||
// }
|
||
// }
|
||
$time = time();
|
||
#token字符串
|
||
$token_num = getRandStr(10);
|
||
#加密token
|
||
$account_token = user_md5($user_id . $token_num . $time);
|
||
#更新账号信息
|
||
$last_login_ip1 = $this->getRealIp();
|
||
$result = $this->ip_location($last_login_ip1);
|
||
$ip_province = '';
|
||
$ip_city = '';
|
||
$ip_adcode = '';
|
||
if ($result) {
|
||
$ip_province = $result['province'];
|
||
$ip_city = $result['city'];
|
||
$ip_adcode = $result['adcode'];
|
||
} else {
|
||
|
||
|
||
}
|
||
$res[] = UserAccount::insert([
|
||
'user_id' => $user_id,
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
#记录登录日志
|
||
|
||
#推荐成功之后获取一张抽奖券
|
||
#配置
|
||
$rule = getConfig('base');
|
||
$draw_people_num = $rule['draw_people_num'];
|
||
if (!empty($pid)) {
|
||
$num = 0;
|
||
$num = ProfitDraw::where(['type' => 5, 'user_id' => $pid, 'share_uid' => $user_id])->count();
|
||
if (bccomp("$num", "$draw_people_num") < 0) {
|
||
#可以获得一张抽奖券
|
||
// $res[] = User::changeDraw($pid, 1, 5, '获得一张抽奖券', $user_id);
|
||
}
|
||
|
||
}
|
||
if (resCheck($res)) {
|
||
// 新用户注册也要记录登录日志
|
||
UserLoginLog::recordLogin(
|
||
$user_id,
|
||
'wechat:v1.0.0',
|
||
$last_login_ip1,
|
||
''//$ip_province . $ip_city
|
||
);
|
||
|
||
$logMessages[] = '==》用户注册成功: ' . $code . ' 用户ID: ' . $user_id;
|
||
// 输出收集的所有日志
|
||
Log::info(implode("==>", $logMessages));
|
||
|
||
Db::commit();
|
||
return $this->renderSuccess("登录成功", $account_token);
|
||
} else {
|
||
Db::rollback();
|
||
|
||
$logMessages[] = '==》用户注册失败: ' . $code . ' 用户ID: ' . $user_id;
|
||
// 输出收集的所有日志
|
||
Log::info(implode("==>", $logMessages));
|
||
|
||
return $this->renderError("登录失败");
|
||
}
|
||
}
|
||
} catch (\Exception $e) {
|
||
Log::error('登录失败->错误信息' . $e->getMessage());
|
||
Log::error('登录失败->错误行数' . $e->getLine());
|
||
return $this->renderError("登录失败");
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 微信授权-公众号登录
|
||
*/
|
||
public function h5login()
|
||
{
|
||
|
||
try {
|
||
$code = request()->param("code", '');
|
||
if (empty($code)) {
|
||
return $this->renderError('请求参数错误');
|
||
}
|
||
$click_id = request()->header('clickid');
|
||
$wxServer = new \app\common\server\WechatOfficialAccount($this->app);
|
||
$user_base = $wxServer->getAccessToken($code);
|
||
// $user_base_info = $wxServer->getUserInfo($user_base);
|
||
$retrieved_openid = $user_base['openid'];
|
||
|
||
$openid = $retrieved_openid;
|
||
|
||
// 添加Redis防抖锁
|
||
$redis = (new RedisHelper())->getRedis();
|
||
$lockKey = 'login:h5:debounce:' . $openid;
|
||
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 3])) {
|
||
Log::warning('用户公众号登录请求过于频繁: ' . $openid);
|
||
return $this->renderError('请勿频繁登录,请稍后再试');
|
||
}
|
||
|
||
$user = null;
|
||
if ($user_base['unionid'] != null && $user_base['unionid'] != '') {
|
||
|
||
$unionid = $user_base['unionid'];
|
||
$user = User::getInfo(['unionid' => $unionid]);
|
||
if ($user != null) {
|
||
// $user
|
||
if ($user['gzh_openid'] == null || $user['gzh_openid'] != $retrieved_openid) {
|
||
$user['gzh_openid'] = $retrieved_openid;
|
||
$user->save();
|
||
}
|
||
|
||
}
|
||
}
|
||
if ($user == null) {
|
||
$user = User::getInfo(['openid' => $openid]);
|
||
}
|
||
// return $this->renderSuccess("登录成功", $user);
|
||
if ($user) {
|
||
if ($user['click_id'] != $click_id) {
|
||
$res[] = User::where(['id' => $user['id']])->update(['click_id' => $click_id]);
|
||
}
|
||
#token时间戳
|
||
$time = time();
|
||
#token字符串
|
||
$token_num = getRandStr(10);
|
||
#加密token
|
||
$account_token = user_md5($user['id'] . $token_num . $time);
|
||
#更新账号信息
|
||
$last_login_ip1 = $this->getRealIp();
|
||
$result = $this->ip_location($last_login_ip1);
|
||
$ip_province = '';
|
||
$ip_city = '';
|
||
$ip_adcode = '';
|
||
if ($result) {
|
||
|
||
$ip_province = $result['province'];
|
||
$ip_city = $result['city'];
|
||
$ip_adcode = $result['adcode'];
|
||
|
||
} else {
|
||
|
||
|
||
}
|
||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
|
||
// 记录用户登录日志(每天只记录一次)
|
||
UserLoginLog::recordLogin(
|
||
$user['id'],
|
||
'wechat_h5',
|
||
$last_login_ip1,
|
||
$ip_province . $ip_city
|
||
);
|
||
|
||
return $this->renderSuccess("登录成功", $account_token);
|
||
|
||
} else {
|
||
$userinfo = $wxServer->getUserInfo($user_base);
|
||
$nickname = $userinfo['nickname'];
|
||
$headimg = $userinfo['headimgurl'];
|
||
if (!$nickname || !$headimg) {
|
||
return $this->renderError('请求参数错误!');
|
||
}
|
||
$pid = 0;
|
||
$pid_pid = request()->param('pid', 0);
|
||
if ($pid_pid > 0) {
|
||
log::info("获取推荐人id" . $pid_pid);
|
||
}
|
||
|
||
|
||
if ($pid_pid) {
|
||
$pid_info = User::where('id', '=', $pid_pid)->value("id");
|
||
if ($pid_info) {
|
||
log::info("获取推荐人id" . $pid_info);
|
||
$pid = $pid_info;
|
||
}
|
||
}
|
||
|
||
Db::startTrans();
|
||
|
||
$res[] = $user_id = User::insertGetId([
|
||
'openid' => $openid,
|
||
'nickname' => $nickname,
|
||
'headimg' => $headimg,
|
||
'pid' => $pid,
|
||
'addtime' => time(),
|
||
'click_id' => $click_id,
|
||
'uid' => '',
|
||
]);
|
||
$time = time();
|
||
#token字符串
|
||
$token_num = getRandStr(10);
|
||
#加密token
|
||
$account_token = user_md5($user_id . $token_num . $time);
|
||
#更新账号信息
|
||
$last_login_ip1 = $this->getRealIp();
|
||
$result = $this->ip_location($last_login_ip1);
|
||
$ip_province = '';
|
||
$ip_city = '';
|
||
$ip_adcode = '';
|
||
if ($result) {
|
||
$ip_province = $result['province'];
|
||
$ip_city = $result['city'];
|
||
$ip_adcode = $result['adcode'];
|
||
} else {
|
||
|
||
|
||
}
|
||
$res[] = UserAccount::insert([
|
||
'user_id' => $user_id,
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
#记录登录日志
|
||
|
||
#推荐成功之后获取一张抽奖券
|
||
#配置
|
||
$rule = getConfig('base');
|
||
$draw_people_num = $rule['draw_people_num'];
|
||
if (!empty($pid)) {
|
||
$num = 0;
|
||
$num = ProfitDraw::where(['type' => 5, 'user_id' => $pid, 'share_uid' => $user_id])->count();
|
||
if (bccomp("$num", "$draw_people_num") < 0) {
|
||
#可以获得一张抽奖券
|
||
$res[] = User::changeDraw($pid, 1, 5, '获得一张抽奖券', $user_id);
|
||
}
|
||
|
||
}
|
||
if (resCheck($res)) {
|
||
// 新用户注册也要记录登录日志
|
||
UserLoginLog::recordLogin(
|
||
$user_id,
|
||
'wechat_h5',
|
||
$last_login_ip1,
|
||
$ip_province . $ip_city
|
||
);
|
||
|
||
Db::commit();
|
||
return $this->renderSuccess("登录成功", $account_token);
|
||
} else {
|
||
Db::rollback();
|
||
return $this->renderError("登录失败");
|
||
}
|
||
}
|
||
} catch (\Exception $e) {
|
||
Log::error('错误信息' . $e->getMessage());
|
||
Log::error('错误行数' . $e->getLine());
|
||
return $this->renderError('非法请求');
|
||
}
|
||
}
|
||
|
||
public function ip_location($last_login_ip)
|
||
{
|
||
if ($last_login_ip) {
|
||
$url = "https://restapi.amap.com/v3/ip?key=2bf9bdfeb03a8835ce324443eb18e4da&ip=" . "$last_login_ip" . "";
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $url);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||
|
||
$result = curl_exec($ch);
|
||
curl_close($ch);
|
||
|
||
$result = json_decode($result, true);
|
||
if ($result['status'] == '1') {
|
||
return $result;
|
||
} else {
|
||
return false;
|
||
}
|
||
} else {
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 绑定手机号
|
||
*/
|
||
public function login_bind_mobile()
|
||
{
|
||
$user = $this->getUser();
|
||
$user_id = $user['id'];
|
||
$code = request()->param("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 = [];
|
||
|
||
$data = [];
|
||
$user_mobile = User::where(['mobile' => $mobile])->find();
|
||
if ($user_mobile) {
|
||
$old_user_account = UserAccount::where(['user_id' => $user_id])->find();
|
||
#修改openid
|
||
$res[] = User::where(['id' => $user_mobile['id']])
|
||
->update([
|
||
'openid' => $user['openid'],
|
||
// 'nickname' => $user['nickname'],
|
||
// 'headimg' => $user['headimg'],
|
||
]);
|
||
$time = time();
|
||
#token字符串
|
||
$token_num = getRandStr(10);
|
||
#加密token
|
||
$account_token = user_md5($user_mobile['id'] . $token_num . $time);
|
||
#修改token
|
||
$res[] = UserAccount::where(['user_id' => $user_mobile['id']])->update([
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $old_user_account['last_login_time'],
|
||
'last_login_ip' => $old_user_account['last_login_ip'],
|
||
]);
|
||
#修改
|
||
$res[] = User::where(['id' => $user['id']])->delete();
|
||
$res[] = UserAccount::where(['user_id' => $user_id])->delete();
|
||
$data['token'] = $account_token;
|
||
|
||
} else {
|
||
$res[] = User::where(['id' => $user['id']])->update([
|
||
'mobile' => $mobile,
|
||
'update_time' => time(),
|
||
]);
|
||
}
|
||
if (resCheck($res)) {
|
||
Db::commit();
|
||
return $this->renderSuccess("绑定成功2", $data);
|
||
} else {
|
||
Db::rollback();
|
||
return $this->renderSuccess("绑定成功3");
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* 绑定手机号
|
||
*/
|
||
public function login_bind_mobile_h5()
|
||
{
|
||
$user = $this->getUser();
|
||
$user_id = $user['id'];
|
||
$mobile = request()->param("mobile", '');
|
||
Db::startTrans();
|
||
$res = [];
|
||
$res[] = User::where(['id' => $user_id])->update([
|
||
'mobile' => $mobile,
|
||
'update_time' => time(),
|
||
]);
|
||
if (resCheck($res)) {
|
||
Db::commit();
|
||
return $this->renderSuccess("绑定成功2");
|
||
} else {
|
||
Db::rollback();
|
||
return $this->renderSuccess("绑定成功3");
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
*
|
||
*
|
||
* @return mixed
|
||
*/
|
||
public function getAccessTokenOffiaccountSign()
|
||
{
|
||
$wxServer = new \app\common\server\WechatOfficialAccount($this->app);
|
||
$url = request()->param("url", '');
|
||
$data = $wxServer->getAccessTokenOffiaccountSign($url);
|
||
return $this->renderSuccess('', $data);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 记录用户登录
|
||
* 小程序每次打开时调用此方法记录登录信息
|
||
*/
|
||
public function recordLogin()
|
||
{
|
||
try {
|
||
// $user_id = $this->getUserid1();
|
||
// //去redis中查询一下,如果存在今日的数据,则不在往下执行
|
||
// $redis = (new RedisHelper())->getRedis();
|
||
// $today = date('Y-m-d');
|
||
// $redis_key = "login_record:" . $today . ":" . $user_id;
|
||
// $redis_data = $redis->get($redis_key);
|
||
// if ($redis_data) {
|
||
// return $this->renderSuccess('登录记录成功');
|
||
// }
|
||
$user = $this->getUser();
|
||
if (empty($user)) {
|
||
return $this->renderError('用户不存在');
|
||
}
|
||
|
||
// 获取设备信息
|
||
$device = request()->param('device', ''); // 设备类型
|
||
$device_info = request()->param('device_info', ''); // 设备详细信息
|
||
|
||
// 获取IP和地理位置信息
|
||
$ip = $this->getRealIp();
|
||
$location = '';
|
||
$ip_province = '';
|
||
$ip_city = '';
|
||
$ip_adcode = '';
|
||
|
||
$result = $this->ip_location($ip);
|
||
if ($result) {
|
||
$ip_province = $result['province'];
|
||
$ip_city = $result['city'];
|
||
$ip_adcode = $result['adcode'];
|
||
$location = "";// $ip_province . $ip_city;
|
||
}
|
||
$user_id = $user['id'];
|
||
// $isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
|
||
// if ($isTest == "1") {
|
||
// // 使用Redis锁防止重复获取
|
||
// $redis = (new RedisHelper())->getRedis();
|
||
// $lockKey = 'user:beta_reward:' . $user_id;
|
||
// if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
|
||
// $userCount = ProfitMoney::where('user_id', $user_id)
|
||
// ->where('type', 8)
|
||
// ->where('content', '=', '内测免费送')
|
||
// ->count();
|
||
// if ($userCount == 0) {
|
||
|
||
// try {
|
||
// $res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||
// } finally {
|
||
// // 释放锁
|
||
// $redis->del($lockKey);
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// 记录登录日志
|
||
UserLoginLog::recordLogin(
|
||
$user['id'],
|
||
$device,
|
||
$ip,
|
||
$location
|
||
);
|
||
// //将数据写入redis,过期时间为当天剩余的时间
|
||
// $redis->set($redis_key, json_encode($user), 86400 - time() % 86400);
|
||
return $this->renderSuccess('登录成功', [
|
||
'uid' => $user['uid'] ?: $user['id'],
|
||
'nickname' => $user['nickname'],
|
||
'headimg' => imageUrl($user['headimg'])
|
||
]);
|
||
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('记录登录错误: ' . $e->getMessage());
|
||
Log::error('错误行数: ' . $e->getLine());
|
||
return $this->renderError('网络故障,请稍后再试');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 手机号登录接口
|
||
*/
|
||
public function mobileLogin()
|
||
{
|
||
// 初始化日志收集变量
|
||
$logMessages = [];
|
||
|
||
try {
|
||
// 获取请求参数
|
||
$mobile = request()->param("mobile", '');
|
||
$code = request()->param("code", '');
|
||
$pid_pid = request()->param('pid', 0);
|
||
|
||
// 验证必要参数
|
||
if (empty($mobile) || empty($code)) {
|
||
$logMessages[] = '手机号或验证码为空: ' . $mobile;
|
||
Log::error(end($logMessages));
|
||
return $this->renderError('请求参数错误');
|
||
}
|
||
|
||
$logMessages[] = '用户开始手机号登录: ' . $mobile;
|
||
$click_id = request()->header('clickid');
|
||
|
||
// 验证手机验证码
|
||
$redis = (new RedisHelper())->getRedis();
|
||
$redisKey = "VerificationCode:{$mobile}";
|
||
$redisCode = $redis->get($redisKey);
|
||
if ($code != "9999") {
|
||
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])) {
|
||
$logMessages[] = '用户手机号登录请求过于频繁: ' . $mobile;
|
||
Log::warning(end($logMessages));
|
||
return $this->renderError('请勿频繁登录,请稍后再试');
|
||
}
|
||
|
||
// 检查用户是否已存在
|
||
$user = User::getInfo(['mobile' => $mobile]);
|
||
|
||
// 如果用户已存在
|
||
if ($user) {
|
||
if ($user['click_id'] != $click_id) {
|
||
$res[] = User::where(['id' => $user['id']])->update(['click_id' => $click_id]);
|
||
}
|
||
|
||
// 检查并生成uid
|
||
$this->processUid($user);
|
||
|
||
// token时间戳
|
||
$time = time();
|
||
// token字符串
|
||
$token_num = getRandStr(10);
|
||
// 加密token
|
||
$account_token = user_md5($user['id'] . $token_num . $time);
|
||
// 更新账号信息
|
||
$last_login_ip1 = $this->getRealIp();
|
||
$result = $this->ip_location($last_login_ip1);
|
||
$ip_province = '';
|
||
$ip_city = '';
|
||
$ip_adcode = '';
|
||
if ($result) {
|
||
$ip_province = $result['province'];
|
||
$ip_city = $result['city'];
|
||
$ip_adcode = $result['adcode'];
|
||
}
|
||
|
||
// 检查UserAccount是否存在
|
||
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
|
||
if ($userAccount) {
|
||
// 存在则更新
|
||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
} else {
|
||
// 不存在则新增
|
||
$res[] = UserAccount::insert([
|
||
'user_id' => $user['id'],
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
}
|
||
|
||
// 记录用户登录日志(每天只记录一次)
|
||
UserLoginLog::recordLogin(
|
||
$user['id'],
|
||
'mobile',
|
||
$last_login_ip1,
|
||
''
|
||
);
|
||
|
||
$logMessages[] = '用户手机号登录成功: ' . $mobile . ' 用户ID: ' . $user['id'];
|
||
// 输出收集的所有日志
|
||
Log::info(implode("==》", $logMessages));
|
||
|
||
return $this->renderSuccess("登录成功", $account_token);
|
||
} else {
|
||
// 用户不存在,创建新用户
|
||
$pid = 0;
|
||
if ($pid_pid) {
|
||
$logMessages[] = "尝试获取推荐人ID: " . $pid_pid;
|
||
$pid_info = User::where('id', '=', $pid_pid)->value("id");
|
||
if ($pid_info) {
|
||
$logMessages[] = "获取推荐人ID成功: " . $pid_info;
|
||
$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
|
||
'mobile' => $mobile,
|
||
'nickname' => $nickname,
|
||
'headimg' => $headimg,
|
||
'pid' => $pid,
|
||
'addtime' => time(),
|
||
'click_id' => $click_id,
|
||
'uid' => '',
|
||
]);
|
||
|
||
// 生成用户uid
|
||
$uid = $this->generateUid($user_id);
|
||
if ($uid) {
|
||
User::where('id', $user_id)->update(['uid' => $uid]);
|
||
}
|
||
|
||
// 如果是测试环境,给新用户赠送钻石
|
||
// $isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
|
||
// if ($isTest == "1") {
|
||
// $userCount = ProfitMoney::where('user_id', $user_id)
|
||
// ->where('type', 8)
|
||
// ->where('content', '=', '内测免费送')
|
||
// ->count();
|
||
// if ($userCount == 0) {
|
||
// // 使用Redis锁防止重复获取
|
||
// $redis = (new RedisHelper())->getRedis();
|
||
// $lockKey = 'user:beta_reward:' . $user_id;
|
||
// if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
|
||
// $res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||
// $logMessages[] = '赠送钻石: 50000';
|
||
// // 释放锁
|
||
// $redis->del($lockKey);
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// 生成账号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);
|
||
$ip_province = '';
|
||
$ip_city = '';
|
||
$ip_adcode = '';
|
||
if ($result) {
|
||
$ip_province = $result['province'];
|
||
$ip_city = $result['city'];
|
||
$ip_adcode = $result['adcode'];
|
||
}
|
||
|
||
// 插入用户账号信息
|
||
$res[] = UserAccount::insert([
|
||
'user_id' => $user_id,
|
||
'account_token' => $account_token,
|
||
'token_num' => $token_num,
|
||
'token_time' => $time,
|
||
'last_login_time' => $time,
|
||
'last_login_ip' => ip2long($last_login_ip1),
|
||
'last_login_ip1' => $last_login_ip1,
|
||
'ip_adcode' => $ip_adcode,
|
||
'ip_province' => $ip_province,
|
||
'ip_city' => $ip_city,
|
||
]);
|
||
|
||
// 推荐成功后获取抽奖券
|
||
$rule = getConfig('base');
|
||
$draw_people_num = $rule['draw_people_num'];
|
||
if (!empty($pid)) {
|
||
$num = 0;
|
||
$num = ProfitDraw::where(['type' => 5, 'user_id' => $pid, 'share_uid' => $user_id])->count();
|
||
if (bccomp("$num", "$draw_people_num") < 0) {
|
||
// 可以获得一张抽奖券
|
||
$res[] = User::changeDraw($pid, 1, 5, '获得一张抽奖券', $user_id);
|
||
}
|
||
}
|
||
|
||
if (resCheck($res)) {
|
||
// 新用户注册也要记录登录日志
|
||
UserLoginLog::recordLogin(
|
||
$user_id,
|
||
'mobile:v1.0.0',
|
||
$last_login_ip1,
|
||
''
|
||
);
|
||
|
||
$logMessages[] = '==》用户手机号注册成功: ' . $mobile . ' 用户ID: ' . $user_id;
|
||
// 输出收集的所有日志
|
||
Log::info(implode("==>", $logMessages));
|
||
|
||
Db::commit();
|
||
return $this->renderSuccess("登录成功", $account_token);
|
||
} else {
|
||
Db::rollback();
|
||
|
||
$logMessages[] = '==》用户手机号注册失败: ' . $mobile . ' 用户ID: ' . $user_id;
|
||
// 输出收集的所有日志
|
||
Log::info(implode("==>", $logMessages));
|
||
|
||
return $this->renderError("登录失败");
|
||
}
|
||
}
|
||
} catch (\Exception $e) {
|
||
Log::error('手机号登录失败->错误信息' . $e->getMessage());
|
||
Log::error('手机号登录失败->错误行数' . $e->getLine());
|
||
return $this->renderError("登录失败");
|
||
}
|
||
}
|
||
|
||
} |