$hook_name, 'is_backend' => true, 'params' => &$params, 'where' => &$where, 'field' => &$field, 'order_by' => &$order_by, 'm' => &$m, 'n' => &$n, ]); // 获取用户列表 $data = Db::name('User')->where($where)->order($order_by)->field($field)->limit($m, $n)->select()->toArray(); return DataReturn(MyLang('handle_success'), 0, self::UserListHandle($data, $params)); } /** * 列表数据处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2022-08-01 * @desc description * @param [array] $data [数据列表] * @param [array] $params [输入参数] */ public static function UserListHandle($data, $params = []) { if(!empty($data)) { // 用户列表钩子-前面 $hook_name = 'plugins_service_user_list_handle_begin'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'data' => &$data, ]); // 字段列表 $keys = ArrayKeys($data); // 邀请用户列表 $referrer_data = []; if(in_array('referrer', $keys)) { $referrer_data = self::GetUserViewInfo(array_column($data, 'referrer')); } // 用户平台信息 $platform_data = []; if(in_array('id', $keys)) { $platform = Db::name('UserPlatform')->where(['user_id'=>array_column($data, 'id')])->select()->toArray(); if(!empty($platform)) { $common_platform_type = MyConst('common_platform_type'); foreach($platform as $v) { if(!array_key_exists($v['user_id'], $platform_data)) { $platform_data[$v['user_id']] = ['data'=>[], 'system'=>[], 'platform'=>[]]; } $v['platform_name'] = isset($common_platform_type[$v['platform']]) ? $common_platform_type[$v['platform']]['name'] : $v['platform']; $platform_data[$v['user_id']]['data'][] = $v; if(!in_array($v['system_type'], $platform_data[$v['user_id']]['system'])) { $platform_data[$v['user_id']]['system'][] = $v['system_type']; } if(!in_array($v['platform_name'], $platform_data[$v['user_id']]['platform'])) { $platform_data[$v['user_id']]['platform'][] = $v['platform_name']; } } } } // 开始处理数据 $common_gender_list = MyConst('common_gender_list'); $common_user_status_list = MyConst('common_user_status_list'); foreach($data as &$v) { // 生日 if(array_key_exists('birthday', $v)) { $v['birthday'] = empty($v['birthday']) ? '' : date('Y-m-d', $v['birthday']); } // 头像 if(array_key_exists('avatar', $v)) { if(!empty($v['avatar'])) { $v['avatar'] = ResourcesService::AttachmentPathViewHandle($v['avatar']); } else { $v['avatar'] = UserDefaultAvatar(); } } // 邀请用户信息 if(array_key_exists('referrer', $v)) { $v['referrer_info'] = (!empty($referrer_data) && is_array($referrer_data) && array_key_exists($v['referrer'], $referrer_data)) ? $referrer_data[$v['referrer']] : []; } // 用户平台信息 if(array_key_exists('id', $v)) { $temp = (empty($platform_data) || empty($platform_data[$v['id']])) ? [] : $platform_data[$v['id']]; $v['user_platform_data'] = empty($temp['data']) ? [] : $temp['data']; $v['system_type_list'] = empty($temp['system']) ? [] : $temp['system']; $v['platform_list'] = empty($temp['platform']) ? [] : $temp['platform']; $v['system_type_text'] = empty($v['system_type_list']) ? '' : implode(',', $v['system_type_list']); $v['platform_text'] = empty($v['platform_list']) ? '' : implode(',', $v['platform_list']); } // 时间 if(array_key_exists('add_time', $v)) { $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']); } if(array_key_exists('upd_time', $v)) { $v['upd_time'] = empty($v['upd_time']) ? '' : date('Y-m-d H:i:s', $v['upd_time']); } // 性别 if(array_key_exists('gender', $v)) { $v['gender_text'] = isset($common_gender_list[$v['gender']]) ? $common_gender_list[$v['gender']]['name'] : ''; } // 状态 if(array_key_exists('status', $v)) { $v['status_text'] = $common_user_status_list[$v['status']]['name']; } } // 用户列表钩子-后面 $hook_name = 'plugins_service_user_list_handle_end'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'data' => &$data, ]); } return $data; } /** * 用户总数 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2016-12-10T22:16:29+0800 * @param [array] $where [条件] */ public static function UserTotal($where) { // 用户总数读取前钩子 $hook_name = 'plugins_service_user_total_begin'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'where' => &$where, ]); // 获取总数 return (int) Db::name('User')->where($where)->count(); } /** * 获取用户登录信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2021-12-06 * @desc description * @param [boolean] $is_cache [是否缓存读取] */ public static function LoginUserInfo($is_cache = true) { // 静态数据避免重复读取 static $user_login_info = null; if($user_login_info === null && $is_cache) { $user_login_info = self::CacheLoginUserInfo(); } // 缓存为空则重新读取 if(empty($user_login_info)) { if(APPLICATION == 'web') { // web用户session $user_login_info = MySession(self::$user_login_key); } if(empty($user_login_info)) { $params = input(); if(!empty($params['token'])) { $user_login_info = self::UserTokenData($params['token']); } } } return $user_login_info; } /** * 获取用户token用户数据 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @datetime 2019-08-18T19:01:59+0800 * @desc description * @param [string] $token [用户token] */ public static function UserTokenData($token) { // token缓存数据 $user = self::CacheUserTokenData($token); if(!empty($user) && isset($user['id'])) { return $user; } // 数据库校验 return self::AppUserInfoHandle(['where_field'=>'token', 'where_value'=>$token, 'is_refresh_token'=>0]); } /** * 用户登录缓存数据 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2023-03-28 * @desc description */ public static function CacheLoginUserInfo() { // 静态数据避免重复读取 static $user_cache_login_info = null; if($user_cache_login_info === null) { // 参数 $params = input(); // 用户数据处理 if(APPLICATION == 'web') { // web用户session $user_cache_login_info = MySession(self::$user_login_key); // 用户信息为空,指定了token则设置登录信息 if(empty($user_cache_login_info)) { $token = empty($params['token']) ? MyCookie(self::$user_token_key) : $params['token']; if(!empty($token)) { $user_cache_login_info = self::CacheUserTokenData($token); // 存在token用户信息则记录session if(!empty($user_cache_login_info)) { self::UserLoginRecord(0, $user_cache_login_info); } } } } else { if(!empty($params['token'])) { $user_cache_login_info = self::CacheUserTokenData($params['token']); } } } return $user_cache_login_info; } /** * 获取用户token缓存用户数据 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @datetime 2019-08-18T19:01:59+0800 * @desc description * @param [string] $token [用户token] */ public static function CacheUserTokenData($token) { return MyCache(SystemService::CacheKey('shopxo.cache_user_info').$token); } /** * 用户状态校验 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-02-27 * @desc description * @param [int] $user_id [用户id] * @param [array] $valid_status [有效状态] */ public static function UserStatusCheck($user_id, $valid_status = [0]) { // 查询用户状态是否正常 $user = self::UserBaseInfo('id', $user_id); if(empty($user)) { return DataReturn(MyLang('common_service.user.user_no_exist_tips'), -110); } if(!is_array($valid_status)) { $valid_status = explode(',', $valid_status); } if(!in_array($user['status'], $valid_status)) { $common_user_status_list = MyConst('common_user_status_list'); if(isset($common_user_status_list[$user['status']])) { return DataReturn($common_user_status_list[$user['status']]['tips'], -110); } else { return DataReturn(MyLang('common_service.user.user_status_error_tips'), -110); } } return DataReturn(MyLang('check_success'), 0); } /** * 根据字段获取用户基础信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-01-25 * @desc description * @param [string] $where_field [字段名称] * @param [string] $where_value [字段值] * @param [string] $field [指定字段] */ public static function UserBaseInfo($where_field, $where_value, $field = '*') { $where = [ [$where_field, '=', $where_value], ['is_delete_time', '=', 0], ['is_logout_time', '=', 0], ]; return Db::name('User')->where($where)->field($field)->find(); } /** * 根据字段获取用户平台信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-01-25 * @desc description * @param [string] $where_field [字段名称] * @param [string] $where_value [字段值] * @param [string] $field [指定字段] * @param [array] $params [输入参数] */ public static function UserPlatformInfo($where_field, $where_value, $field = '*', $params = []) { $system_type = empty($params['system_type_name']) ? SYSTEM_TYPE : $params['system_type_name']; $platform = empty($params['platform']) ? APPLICATION_CLIENT_TYPE : $params['platform']; $where = [ [$where_field, '=', $where_value], ['system_type', '=', $system_type], ['platform', '=', $platform], ]; return Db::name('UserPlatform')->where($where)->field($field)->find(); } /** * 根据字段获取用户信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-01-25 * @desc description * @param [string] $where_field [字段名称] * @param [string] $where_value [字段值] * @param [string] $field [指定字段] * @param [array] $params [输入参数] */ public static function UserInfo($where_field, $where_value, $field = '*', $params = []) { // 用户平台表结构 $platform_structure = ResourcesService::TableStructureData('UserPlatform'); unset($platform_structure['id'], $platform_structure['user_id'], $platform_structure['add_time'], $platform_structure['upd_time']); $platform_structure = array_keys($platform_structure); // 用户基础和平台条件 $where_field_arr = explode('|', $where_field); foreach($where_field_arr as $k=>$v) { $where_field_arr[$k] = (in_array($v, $platform_structure) ? 'up.' : 'u.').$v; } $where_field = implode('|', $where_field_arr); // 查询字段处理 if($field == '*') { $field = 'u.*, up.'.implode(', up.', $platform_structure); } else { $field_arr = explode(',', $field); $u_arr = array_diff($field_arr, $platform_structure); $up_arr = array_intersect($field_arr, $platform_structure); $field = 'u.'.implode(', u.', $u_arr).(empty($up_arr) ? '' : ', up.'.implode(', up.', $up_arr)); } // 查询用户信息 $system_type = empty($params['system_type_name']) ? SYSTEM_TYPE : $params['system_type_name']; $platform = empty($params['platform']) ? APPLICATION_CLIENT_TYPE : $params['platform']; $where = [ [$where_field, '=', $where_value], ['up.system_type', '=', $system_type], ['up.platform', '=', $platform], ['u.is_delete_time', '=', 0], ['u.is_logout_time', '=', 0], ]; $user = Db::name('User')->alias('u')->join('user_platform up', 'u.id=up.user_id')->where($where)->field($field)->find(); // 如果当前系统类型和平台 用户和平台表没有对应数据,则先读取用户基础信息在匹配平台数据 if(empty($user)) { // 是否存在条件字段.指定前缀,则去除 if(stripos($where_field, '.') !== false) { $temp = explode('.', $where_field); $where_field = $temp[1]; } // 如果当前条件字段是平台表字段则先从平台表读取数据 if(in_array($where_field, $platform_structure)) { $user_platform = self::MatchingUserPlatformData($where_field, $where_value, $params); if(!empty($user_platform)) { $user = self::UserBaseInfo('id', $user_platform['user_id'], '*', $params); if(!empty($user)) { $user = array_merge($user, $user_platform); } } } else { $user = self::UserBaseInfo($where_field, $where_value, '*', $params); if(!empty($user)) { $user_platform = self::MatchingUserPlatformData('user_id', $user['id'], $params); if(!empty($user_platform)) { $user = array_merge($user, $user_platform); } } } } return $user; } /** * 匹配用户平台数据 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2023-12-29 * @desc description * @param [string] $where_field [字段名称] * @param [string] $where_value [字段值] * @param [array] $params [输入参数] */ public static function MatchingUserPlatformData($where_field, $where_value, $params = []) { $temp_platform = []; $user_platform = Db::name('UserPlatform')->where([$where_field=>$where_value])->select()->toArray(); if(!empty($user_platform)) { $platform = empty($params['platform']) ? APPLICATION_CLIENT_TYPE : $params['platform']; foreach($user_platform as $pv) { // 优先取当前平台类型的数据 if($pv['platform'] == $platform) { $temp_platform = $pv; break; } } if(empty($temp_platform)) { $temp_platform = $user_platform[0]; } unset($temp_platform['id'], $temp_platform['add_time'], $temp_platform['upd_time']); } return $temp_platform; } /** * 根据字段获取用户系统信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-01-25 * @desc description * @param [string] $where_field [字段名称] * @param [string] $where_value [字段值] * @param [string] $field [指定字段] * @param [array] $params [输入参数] */ public static function UserSystemInfo($where_field, $where_value, $field = 'u.*', $params = []) { $system_type = empty($params['system_type_name']) ? SYSTEM_TYPE : $params['system_type_name']; $where = [ [$where_field, '=', $where_value], ['up.system_type', '=', $system_type], ['u.is_delete_time', '=', 0], ['u.is_logout_time', '=', 0], ]; return Db::name('User')->alias('u')->join('user_platform up', 'u.id=up.user_id')->where($where)->field($field)->find(); } /** * 用户平台信息添加 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2023-03-15 * @desc description * @param [array] $data [用户平台信息] * @param [array] $params [输入参数] */ public static function UserPlatformInsert($data, $params = []) { // 系统标识 if(empty($data['system_type'])) { $data['system_type'] = empty($params['system_type_name']) ? SYSTEM_TYPE : $params['system_type_name']; } // 平台 if(empty($data['platform'])) { $data['platform'] = APPLICATION_CLIENT_TYPE; } $data['add_time'] = time(); return Db::name('UserPlatform')->insertGetId($data) > 0; } /** * 用户平台信息更新 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2023-03-15 * @desc description * @param [string] $where_field [条件字段] * @param [string] $where_value [条件值] * @param [array] $data [更新数据] * @param [array] $params [输入参数] */ public static function UserPlatformUpdate($where_field, $where_value, $data, $params = []) { $where = [ [$where_field, '=', $where_value], ]; // 非自增id则增加更多条件 if($where_field != 'id') { $system_type = empty($params['system_type_name']) ? SYSTEM_TYPE : $params['system_type_name']; $platform = empty($params['platform']) ? APPLICATION_CLIENT_TYPE : $params['platform']; $where[] = ['system_type', '=', $system_type]; $where[] = ['platform', '=', $platform]; } $data['upd_time'] = time(); return Db::name('UserPlatform')->where($where)->update($data); } /** * 用户信息保存 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2016-12-10T22:16:29+0800 * @param [array] $params [输入参数] */ public static function UserSave($params = []) { // 请求参数 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'admin', 'error_msg' => MyLang('common_service.user.save_admin_info_error_tips'), ], [ 'checked_type' => 'length', 'key_name' => 'username', 'checked_data' => '30', 'is_checked' => 1, 'error_msg' => MyLang('common_service.user.form_item_username_message'), ], [ 'checked_type' => 'unique', 'key_name' => 'username', 'checked_data' => 'User', 'checked_key' => 'id', 'is_checked' => 1, 'error_msg' => MyLang('common_service.user.save_user_already_exist_tips'), ], [ 'checked_type' => 'length', 'key_name' => 'nickname', 'checked_data' => '30', 'is_checked' => 1, 'error_msg' => MyLang('common_service.user.form_item_nickname_message'), ], [ 'checked_type' => 'fun', 'key_name' => 'mobile', 'checked_data' => 'CheckMobile', 'is_checked' => 1, 'error_msg' => MyLang('common_service.user.form_item_mobile_message'), ], [ 'checked_type' => 'fun', 'key_name' => 'email', 'checked_data' => 'CheckEmail', 'is_checked' => 1, 'error_msg' => MyLang('common_service.user.form_item_email_message'), ], [ 'checked_type' => 'in', 'key_name' => 'gender', 'checked_data' => array_column(MyConst('common_gender_list'), 'id'), 'error_msg' => MyLang('common_service.user.save_gender_range_error_tips'), ], [ 'checked_type' => 'in', 'key_name' => 'status', 'checked_data' => array_column(MyConst('common_user_status_list'), 'id'), 'error_msg' => MyLang('common_service.user.save_status_range_error_tips'), ], [ 'checked_type' => 'length', 'key_name' => 'address', 'checked_data' => '80', 'is_checked' => 1, 'error_msg' => MyLang('common_service.user.form_item_address_message'), ], [ 'checked_type' => 'fun', 'key_name' => 'pwd', 'checked_data' => 'CheckLoginPwd', 'is_checked' => 1, 'error_msg' => MyLang('common_service.user.form_item_pwd_message'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 附件 $attachment = ResourcesService::AttachmentParams($params, ['avatar']); if($attachment['code'] != 0) { return $attachment; } // 更新数据 $data = [ 'avatar' => $attachment['data']['avatar'], 'username' => isset($params['username']) ? $params['username'] : '', 'nickname' => isset($params['nickname']) ? $params['nickname'] : '', 'mobile' => isset($params['mobile']) ? $params['mobile'] : '', 'email' => isset($params['email']) ? $params['email'] : '', 'province' => empty($params['province']) ? '' : $params['province'], 'city' => empty($params['city']) ? '' : $params['city'], 'county' => empty($params['county']) ? '' : $params['county'], 'address' => empty($params['address']) ? '' : $params['address'], 'gender' => intval($params['gender']), 'integral' => intval($params['integral']), 'locking_integral' => intval($params['locking_integral']), 'status' => intval($params['status']), 'birthday' => empty($params['birthday']) ? 0 : strtotime($params['birthday']), 'referrer' => empty($params['referrer']) ? 0 : intval($params['referrer']), ]; // 邀请人处理 if(!empty($data['referrer']) && !empty($params['id'])) { // 邀请人不能为当前用户id、相同则去掉 if($data['referrer'] == $params['id']) { $data['referrer'] = 0; } // 对方的邀请是否是当前用户 if(!empty($data['referrer'])) { $referrer = Db::name('User')->where(['id'=>$data['referrer']])->value('referrer'); if(!empty($referrer) && $referrer == $params['id']) { $data['referrer'] = 0; } } } // 用户保存处理钩子 $hook_name = 'plugins_service_user_save_handle'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'data' => &$data, 'user_id' => isset($params['id']) ? intval($params['id']) : 0, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 密码 if(!empty($params['pwd'])) { $data['salt'] = GetNumberCode(6); $data['pwd'] = LoginPwdEncryption(trim($params['pwd']), $data['salt']); } // 更新/添加 if(!empty($params['id'])) { // 获取用户信息 $user = Db::name('User')->where(['id'=>intval($params['id'])])->field('id,integral')->find(); if(empty($user)) { return DataReturn(MyLang('common_service.user.save_user_info_no_exist_tips'), -10); } $ret = self::UserUpdateHandle($data, $params['id'], $params); if($ret['code'] == 0) { $user_id = $params['id']; } } else { $ret = self::UserInsert($data); if($ret['code'] != 0) { return $ret; } $user_id = $ret['data']['user_id']; } // 添加用户后处理钩子 $hook_name = 'plugins_service_user_save_success_handle'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'data' => &$data, 'user_id' => &$user_id, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 状态 if(isset($user_id)) { if(($data['integral'] > 0 && empty($user)) || (isset($user['integral']) && $user['integral'] != $data['integral'])) { $integral_type = 1; $old_integral = 0; $opt_integral = $data['integral']; if(!empty($params['id'])) { $old_integral = $user['integral']; $integral_type = ($user['integral'] > $data['integral']) ? 0 : 1; $opt_integral = ($integral_type == 1) ? $data['integral']-$user['integral'] : $user['integral']-$data['integral']; } IntegralService::UserIntegralLogAdd($user_id, $old_integral, $opt_integral, MyLang('common_service.user.admin_operate_name'), $integral_type, $params['admin']['id']); } return DataReturn(MyLang('operate_success'), 0); } return DataReturn(MyLang('operate_fail'), -100); } /** * 用户信息更新 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2022-02-13 * @desc description * @param [array] $data [用户更新信息] * @param [int] $user_id [用户id] * @param [array] $params [输入参数] */ public static function UserUpdateHandle($data, $user_id, $params = []) { // 注册数据分离处理 // 用户平台表结构 $structure = ResourcesService::TableStructureData('UserPlatform'); unset($structure['id'], $structure['user_id'], $structure['add_time'], $structure['upd_time']); $user_base = []; $user_platform = []; foreach($data as $k=>$v) { if(array_key_exists($k, $structure)) { $user_platform[$k] = $v; } else { $user_base[$k] = $v; } } // 用户信息更新 $user_base['upd_time'] = time(); if(Db::name('User')->where(['id'=>$user_id])->update($user_base) === false) { return DataReturn(MyLang('update_fail'), -100); } // 用户平台信息更新 $user_platform['user_id'] = $user_id; if(self::UserPlatformUpdate('user_id', $user_id, $user_platform, $params) === false) { return DataReturn(MyLang('update_fail'), -100); } // 更新成功后钩子 $hook_name = 'plugins_service_user_update_success'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, 'data' => $data, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } return DataReturn(MyLang('update_success'), 0); } /** * 用户删除 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2016-12-10T22:16:29+0800 * @param [array] $params [输入参数] */ public static function UserDelete($params = []) { // 参数是否有误 if(empty($params['ids'])) { return DataReturn(MyLang('data_id_error_tips'), -1); } // 是否数组 if(!is_array($params['ids'])) { $params['ids'] = explode(',', $params['ids']); } // 用户表 if(!Db::name('User')->where(['id'=>$params['ids']])->delete()) { return DataReturn(MyLang('delete_fail'), -100); } // 用户平台信息表 if(Db::name('UserPlatform')->where(['user_id'=>$params['ids']])->delete() === false) { return DataReturn(MyLang('delete_fail'), -100); } return DataReturn(MyLang('delete_success'), 0); } /** * 用户登录记录 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-09T11:37:43+0800 * @param [int] $user_id [用户id] * @param [array] $user [用户信息] * @param [array] $params [输入参数] * @return [boolean] [记录成功true, 失败false] */ public static function UserLoginRecord($user_id = 0, $user = [], $params = []) { if(!empty($user_id) && empty($user)) { $user = self::UserHandle(self::UserInfo('id', $user_id, '*', $params)); } if(!empty($user)) { // 用户id处理 if(empty($user_id)) { $user_id = $user['id']; } // 用户登录成功信息纪录钩子 $hook_name = 'plugins_service_user_login_success_record'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user' => &$user, 'user_id' => $user_id ]); // 通过token存储用户缓存信息 if(!empty($user['token'])) { MyCache(SystemService::CacheKey('shopxo.cache_user_info').$user['token'], $user); } // web端设置session if(APPLICATION == 'web') { // 存储session MySession(self::$user_login_key, $user); // 设置cookie数据 MyCookie('user_info', json_encode($user, JSON_UNESCAPED_UNICODE), false); } return true; } return false; } /** * 用户数据处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2020-01-23 * @desc description * @param [ array] $user [用户数据] */ public static function UserHandle($user) { if(!empty($user)) { // 基础数据处理 if(isset($user['add_time'])) { $user['add_time_text'] = date('Y-m-d H:i:s', $user['add_time']); } if(isset($user['upd_time'])) { $user['upd_time_text'] = date('Y-m-d H:i:s', $user['upd_time']); } if(isset($user['gender'])) { $user['gender_text'] = MyConst('common_gender_list')[$user['gender']]['name']; } if(isset($user['birthday'])) { $user['birthday'] = empty($user['birthday']) ? '' : date('Y-m-d', $user['birthday']); } // 邮箱/手机 if(isset($user['mobile'])) { $user['mobile_security'] = empty($user['mobile']) ? '' : mb_substr($user['mobile'], 0, 3, 'utf-8').'***'.mb_substr($user['mobile'], -3, null, 'utf-8'); } if(isset($user['email'])) { $user['email_security'] = empty($user['email']) ? '' : mb_substr($user['email'], 0, 3, 'utf-8').'***'.mb_substr($user['email'], -3, null, 'utf-8'); } // 地址信息 if(isset($user['province']) && isset($user['city']) && isset($user['county']) && isset($user['address'])) { $user['address_info'] = $user['province'].$user['city'].$user['county'].$user['address']; } // 显示名称,根据规则优先展示 $user['user_name_view'] = isset($user['nickname']) ? $user['nickname'] : ''; if(empty($user['user_name_view']) && isset($user['username'])) { $user['user_name_view'] = $user['username']; } if(empty($user['user_name_view']) && isset($user['mobile_security'])) { $user['user_name_view'] = $user['mobile_security']; } if(empty($user['user_name_view']) && isset($user['email_security'])) { $user['user_name_view'] = $user['email_security']; } // 头像 if(isset($user['avatar'])) { if(!empty($user['avatar'])) { $user['avatar'] = ResourcesService::AttachmentPathViewHandle($user['avatar']); } else { $user['avatar'] = UserDefaultAvatar(); } } // 是否设置了密码 $user['is_setup_pwd'] = empty($user['pwd']) ? 0 : 1; // 移除特殊数据 unset($user['pwd'], $user['salt']); } return $user; } /** * 用户头像更新 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-10-16 * @desc description * @param [array] $params [输入参数] */ public static function UserAvatarUpload($params = []) { // 用户id $user_id = (empty($params['user']) || empty($params['user']['id'])) ? 0 : $params['user']['id']; // 唯一标识 $unique = md5(empty($user_id) ? ResourcesService::UserUniqueId() : $user_id); // 缓存key、是否操作频繁 $cache_key = 'cache_user_avatar_upload_frequency_'.$unique; $cache_value = MyCache($cache_key); if(!empty($cache_value) && $cache_value['time']+3600 > time() && $cache_value['count'] >= 5) { return DataReturn(MyLang('operate_frequent_tips'), -1); } // 开始处理图片存储 // 定义图片目录 $root_path = ROOT.'public'.DS; $img_path = 'static'.DS.'upload'.DS.'images'.DS.'user_avatar'.DS; $date = DS.date('Y').DS.date('m').DS.date('d').DS; // 图像类库 $images_obj = \base\Images::Instance(['is_new_name'=>false]); // 文件上传校验、仅表单$_FILES的方式验证 $is_file_url = !empty($params[$params['img_field']]) && substr($params[$params['img_field']], 0, 4) == 'http'; if(!$is_file_url) { $error = FileUploadError($params['img_field']); if($error !== true) { return DataReturn($error, -2); } } // 头像处理前钩子 $hook_name = 'plugins_service_user_avatar_upload_begin'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, 'unique' => $unique, 'params' => $params, 'files' => $_FILES, 'root_path' => $root_path, 'img_path' => $img_path, 'date' => $date, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 是否指定裁剪信息 $original_dir = $root_path.$img_path.'original'.$date; // 是否url链接地址 if($is_file_url) { $original = $images_obj->DownloadImageSave($params[$params['img_field']], $original_dir); } else { if(!empty($params['img_width']) && !empty($params['img_height']) && isset($params['img_x']) && isset($params['img_y'])) { $original = $images_obj->GetCompressCut($_FILES[$params['img_field']], $original_dir, 800, 800, $params['img_x'], $params['img_y'], $params['img_width'], $params['img_height']); } else { $original = $images_obj->GetOriginal($_FILES[$params['img_field']], $original_dir); } } if(!empty($original)) { $compr = $images_obj->GetBinaryCompress($root_path.$img_path.'original'.$date.$original, $root_path.$img_path.'compr'.$date, 200, 200); $small = $images_obj->GetBinaryCompress($root_path.$img_path.'original'.$date.$original, $root_path.$img_path.'small'.$date, 50, 50); } if(empty($compr) || empty($small)) { return DataReturn(MyLang('images_format_error_tips'), -3); } $avatar = DS.$img_path.'compr'.$date.$compr; // 缓存记录 if(empty($cache_value)) { $cache_value = ['count'=>1, 'time'=>time()]; } else { $cache_value['count']++; } MyCache($cache_key, $cache_value, 3600); // 头像处理后钩子 $hook_name = 'plugins_service_user_avatar_upload_end'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, 'unique' => $unique, 'params' => $params, 'files' => $_FILES, 'root_path' => $root_path, 'img_path' => $img_path, 'date' => $date, 'avatar' => $avatar, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // app则直接返回图片地址 if(APPLICATION == 'app') { return DataReturn(MyLang('upload_success'), 0, ResourcesService::AttachmentPathViewHandle($avatar)); } // 更新用户头像 $data = [ 'avatar' => $avatar, 'upd_time' => time(), ]; if(Db::name('User')->where(['id'=>$user_id])->update($data)) { // 头像处理成功钩子 $hook_name = 'plugins_service_user_avatar_upload_success'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, 'unique' => $unique, 'params' => $params, 'files' => $_FILES, 'root_path' => $root_path, 'img_path' => $img_path, 'date' => $date, 'avatar' => $avatar, ]); // web端用户登录纪录处理 if(self::UserLoginRecord($params['user']['id'])) { return DataReturn(MyLang('upload_success'), 0); } } return DataReturn(MyLang('upload_fail'), -100); } /** * 用户登录 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-03 * @desc description * @param [array] $params [输入参数] */ public static function Login($params = []) { // 用户登录前校验钩子 $hook_name = 'plugins_service_user_login_begin_check'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 请求参数 $p = [ [ 'checked_type' => 'in', 'key_name' => 'type', 'checked_data' => array_column(MyConst('common_login_type_list'), 'value'), 'error_msg' => MyLang('login_type_error_tips'), ], [ 'checked_type' => 'empty', 'key_name' => 'accounts', 'error_msg' => MyLang('accounts_empty_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 是否开启用户登录 if(!in_array($params['type'], MyC('home_user_login_type', [], true))) { return DataReturn(MyLang('login_close_tips'), -1); } // 账户校验 $ac = self::UserLoginAccountsCheck($params); if($ac['code'] != 0) { return $ac; } // 验证参数 $verify_params = [ 'key_prefix' => 'user_login_'.md5($params['accounts']), 'expire_time' => MyC('common_verify_expire_time'), ]; // 帐号密码登录需要校验密码 if($params['type'] == 'username') { // 请求参数 $p = [ [ 'checked_type' => 'fun', 'key_name' => 'pwd', 'checked_data' => 'CheckLoginPwd', 'error_msg' => MyLang('common_service.user.form_item_pwd_message'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 帐号密码登录是否开启图片验证码 $verify_params['key_prefix'] = 'user_login'; $verify = self::IsImaVerify($params, $verify_params, MyC('home_user_login_img_verify_state')); if($verify['code'] != 0) { return $verify; } } else { // 账户类型 $obj = null; switch($params['type']) { // 短信 case 'sms' : $obj = new \base\Sms($verify_params); break; // 邮箱 case 'email' : $obj = new \base\Email($verify_params); break; // 未知的字段 default : return DataReturn(MyLang('verify_type_error_tips'), -1); } // 验证码校验 // sms, email if(isset($obj) && is_object($obj)) { // 是否已过期 if(!$obj->CheckExpire()) { return DataReturn(MyLang('verify_code_expire_tips'), -10); } // 是否正确 if(!$obj->CheckCorrect($params['verify'])) { return DataReturn(MyLang('verify_code_error_tips'), -11); } } } // 获取用户账户信息 $method = self::UserUniqueMethod(); $user = self::$method($ac['data'], $params['accounts']); if(empty($user)) { return DataReturn(MyLang('accounts_error_tips'), -3); } // 密码校验 // 帐号密码登录需要校验密码 if($params['type'] == 'username') { if(empty($user['pwd']) || empty($user['salt'])) { return DataReturn(MyLang('password_no_setup_tips'), -4); } $pwd = LoginPwdEncryption($params['pwd'], $user['salt']); if($pwd != $user['pwd']) { return DataReturn(MyLang('password_error_tips'), -4); } } // 用户平台信息、不存在则添加 $user_platform = self::UserPlatformInfo('user_id', $user['id']); if(empty($user_platform)) { if(!self::UserPlatformInsert(['user_id' => $user['id']], $params)) { return DataReturn(MyLang('insert_fail'), -1); } } // 用户状态 if(in_array($user['status'], [2,3])) { return DataReturn(MyConst('common_user_status_list')[$user['status']]['tips'], -10); } // 用户登录前钩子 $hook_name = 'plugins_service_user_login_begin'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'user_id' => $user['id'] ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 返回数据,更新数据库 $upd_data = []; if($params['type'] == 'username') { $salt = GetNumberCode(6); $upd_data['salt'] = $salt; $upd_data['pwd'] = LoginPwdEncryption($params['pwd'], $salt); } // 用户openid if(empty($user_platform[APPLICATION_CLIENT_TYPE.'_openid'])) { $openid = self::UserOpenidHandle($params); if(!empty($openid['field']) && !empty($openid['value'])) { // openid放入用户data中 $upd_data[$openid['field']] = $openid['value']; } } // 用户unionid if(empty($user_platform[APPLICATION_CLIENT_TYPE.'_unionid'])) { $unionid = self::UserUnionidHandle($params); if(!empty($unionid['field']) && !empty($unionid['value'])) { // unionid放入用户data中 $upd_data[$unionid['field']] = $unionid['value']; } } // 昵称和头像 if(empty($user['nickname']) && !empty($params['nickname'])) { $upd_data['nickname'] = $params['nickname']; } if((empty($user['avatar']) || stripos($user['avatar'], 'default-user-avatar') !== false) && !empty($params['avatar'])) { $upd_data['avatar'] = $params['avatar']; } // 更新用户信息 if(!empty($upd_data)) { $ret = self::UserUpdateHandle($upd_data, $user['id'], $params); if($ret['code'] != 0) { return DataReturn(MyLang('login_failure_tips'), -100); } } // 清除图片验证码 if(isset($verify) && isset($verify['data']) && is_object($verify['data'])) { $verify['data']->Remove(); } return self::UserLoginHandle($user['id'], $params); } /** * 登录处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-05-24 * @desc description * @param [int] $user_id [用户id] * @param [array] $params [输入参数] */ public static function UserLoginHandle($user_id, $params = []) { // 返回前端html代码 $body_html = []; // 用户登录后钩子 $user = self::UserHandle(self::UserInfo('id', $user_id, '*', $params)); // 会员码生成处理 if(empty($user['number_code'])) { $user['number_code'] = self::UserNumberCodeCreatedHandle($user_id); } // token $user['token'] = self::UserTokenUpdate($user_id, $user); // 登录钩子 $hook_name = 'plugins_service_user_login_end'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'user_id' => $user_id, 'user' => $user, 'body_html' => &$body_html, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 登录记录 if(self::UserLoginRecord(0, $user)) { // 成功返回 if(APPLICATION == 'app') { $result = self::AppUserInfoHandle(['user'=>$user, 'is_refresh_token'=>0]); } else { $result = [ 'body_html' => is_array($body_html) ? implode(' ', $body_html) : $body_html, 'user_id' => $user_id, ]; } return DataReturn(MyLang('login_success'), 0, $result); } return DataReturn(MyLang('login_failure_tips'), -100); } /** * 用户注册 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-03 * @desc description * @param [array] $params [输入参数] */ public static function Reg($params = []) { // 数据验证 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'accounts', 'error_msg' => MyLang('accounts_empty_tips'), ], [ 'checked_type' => 'empty', 'key_name' => 'pwd', 'error_msg' => MyLang('password_empty_tips'), ], [ 'checked_type' => 'in', 'key_name' => 'type', 'checked_data' => array_column(MyConst('common_user_reg_type_list'), 'value'), 'error_msg' => MyLang('register_type_error_tips'), ], [ 'checked_type' => 'empty', 'key_name' => 'verify', 'is_checked' => 2, 'error_msg' => MyLang('verify_code_empty_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 用户注册前校验钩子 $hook_name = 'plugins_service_user_register_begin_check'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 是否开启用户注册 if(!in_array($params['type'], MyC('home_user_reg_type', [], true))) { return DataReturn(MyLang('register_close_tips'), -1); } // 账户校验 $ret = self::UserRegAccountsCheck($params); if($ret['code'] != 0) { return $ret; } // 是否需要审核 $common_register_is_enable_audit = MyC('common_register_is_enable_audit', 0); // 用户数据 $salt = GetNumberCode(6); $data = [ 'upd_time' => time(), 'salt' => $salt, 'pwd' => LoginPwdEncryption($params['pwd'], $salt), 'status' => ($common_register_is_enable_audit == 1) ? 3 : 0, ]; // 验证码校验 $verify_params = [ 'key_prefix' => 'user_reg_'.md5($params['accounts']), 'expire_time' => MyC('common_verify_expire_time'), ]; // 账户类型 $obj = null; switch($params['type']) { // 短信 case 'sms' : $data['mobile'] = $params['accounts']; $obj = new \base\Sms($verify_params); break; // 邮箱 case 'email' : $data['email'] = $params['accounts']; $obj = new \base\Email($verify_params); break; // 默认 账号 default : $data['username'] = $params['accounts']; // 是否开启图片验证码 // user_reg 由前端图片验证码传递的 type 一致 $verify_params['key_prefix'] = 'user_reg'; $verify = self::IsImaVerify($params, $verify_params, MyC('home_user_register_img_verify_state')); if($verify['code'] != 0) { return $verify; } } // 验证码校验 // sms, email if(isset($obj) && is_object($obj)) { // 是否已过期 if(!$obj->CheckExpire()) { return DataReturn(MyLang('verify_code_expire_tips'), -10); } // 是否正确 if(!$obj->CheckCorrect($params['verify'])) { return DataReturn(MyLang('verify_code_error_tips'), -11); } } // 数据添加 $user_ret = self::UserInsert($data, $params); if($user_ret['code'] == 0) { // 清除验证码 if(isset($obj) && is_object($obj)) { $obj->Remove(); } // 是否需要审核 if($common_register_is_enable_audit == 1) { return DataReturn(MyLang('common_service.user.user_not_audit_tips'), -110); } // 用户登录session纪录 if(self::UserLoginRecord($user_ret['data']['user_id'])) { // 成功返回 if(APPLICATION == 'app') { $result = self::AppUserInfoHandle(['where_field'=>'id', 'where_value'=>$user_ret['data']['user_id'], 'is_refresh_token'=>0]); } else { $result = $user_ret['data']; } return DataReturn(MyLang('register_success'), 0, $result); } return DataReturn(MyLang('common_service.user.user_register_success_no_login_tips')); } return $user_ret; } /** * 用户注册账户校验 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-10T10:06:29+0800 * @param [array] $params [输入参数] */ public static function UserRegAccountsCheck($params = []) { switch($params['type']) { // 手机 case 'sms' : // 手机号码格式 if(!CheckMobile($params['accounts'])) { return DataReturn(MyLang('mobile_format_error_tips'), -2); } // 手机号码是否已存在 if(self::IsExistAccounts($params['accounts'], 'mobile')) { return DataReturn(MyLang('common_service.user.mobile_already_exist_tips'), -3); } break; // 邮箱 case 'email' : // 电子邮箱格式 if(!CheckEmail($params['accounts'])) { return DataReturn(MyLang('email_format_error_tips'), -2); } // 电子邮箱是否已存在 if(self::IsExistAccounts($params['accounts'], 'email')) { return DataReturn(MyLang('common_service.user.email_already_exist_tips'), -3); } break; // 用户名 case 'username' : // 用户名格式 if(!CheckUserName($params['accounts'])) { return DataReturn(MyLang('common_service.user.username_format_error_tips'), -2); } // 用户名是否已存在 if(self::IsExistAccounts($params['accounts'], 'username')) { return DataReturn(str_replace('{$var}', $params['accounts'], MyLang('common_service.user.save_user_already_exist_tips')), -3); } break; } return DataReturn(MyLang('operate_success'), 0); } /** * 账户是否存在 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-08T10:27:14+0800 * @param [string] $accounts [账户名称] * @param [string] $field [字段名称] * @return [boolean] [存在true, 不存在false] */ public static function IsExistAccounts($accounts, $field = 'mobile') { $method = self::UserUniqueMethod(); $temp = self::$method($field, $accounts); return !empty($temp); } /** * 用户校验唯一方法 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2023-03-22 * @desc description */ public static function UserUniqueMethod() { return (MyC('common_user_unique_system_type_model') == 1) ? 'UserSystemInfo' : 'UserBaseInfo'; } /** * 是否开启图片验证码校验 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-22T15:48:31+0800 * @param [array] $params [输入参数] * @param [array] $verify_params [配置参数] * @param [int] $status [状态 0未开启, 1已开启] * @return [object] [图片验证码类对象] */ public static function IsImaVerify($params, $verify_params, $status = 0) { if($status == 1) { if(empty($params['verify'])) { return DataReturn(MyLang('verify_images_empty_tips'), -10); } $verify = new \base\Verify($verify_params); if(!$verify->CheckExpire()) { return DataReturn(MyLang('verify_code_expire_tips'), -11); } if(!$verify->CheckCorrect($params['verify'])) { return DataReturn(MyLang('verify_code_error_tips'), -12); } return DataReturn(MyLang('operate_success'), 0, $verify); } return DataReturn(MyLang('operate_success'), 0); } /** * 用户登录账户校验 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-10T10:06:29+0800 * @param [array] $params [输入参数] */ public static function UserLoginAccountsCheck($params = []) { $field = ''; switch($params['type']) { // 手机 case 'sms' : // 手机号码格式 if(!CheckMobile($params['accounts'])) { return DataReturn(MyLang('mobile_format_error_tips'), -2); } // 手机号码是否不存在 if(!self::IsExistAccounts($params['accounts'], 'mobile')) { return DataReturn(MyLang('mobile_no_exist_error_tips'), -3); } $field = 'mobile'; break; // 邮箱 case 'email' : // 电子邮箱格式 if(!CheckEmail($params['accounts'])) { return DataReturn(MyLang('email_format_error_tips'), -2); } // 电子邮箱是否不存在 if(!self::IsExistAccounts($params['accounts'], 'email')) { return DataReturn(MyLang('email_no_exist_error_tips'), -3); } $field = 'email'; break; // 用户名 case 'username' : // 帐号是否不存在 if(!self::IsExistAccounts($params['accounts'], 'username|mobile|email')) { return DataReturn(MyLang('accounts_error_tips'), -3); } $field = 'username|mobile|email'; break; } return DataReturn(MyLang('operate_success'), 0, $field); } /** * 用户登录-验证码发送 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-10T10:06:29+0800 * @param [array] $params [输入参数] */ public static function LoginVerifySend($params = []) { // 数据验证 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'accounts', 'error_msg' => MyLang('accounts_empty_tips'), ], [ 'checked_type' => 'in', 'key_name' => 'type', 'checked_data' => array_column(MyConst('common_login_type_list'), 'value'), 'error_msg' => MyLang('login_type_error_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 是否开启用户登录 if(!in_array($params['type'], MyC('home_user_login_type', [], true))) { return DataReturn(MyLang('login_close_tips'), -1); } // 验证码基础参数 $verify_params = [ 'key_prefix' => 'user_login', 'expire_time' => MyC('common_verify_expire_time'), 'interval_time' => MyC('common_verify_interval_time'), ]; // 是否开启图片验证码 $verify = self::IsImaVerify($params, $verify_params, MyC('common_img_verify_state')); if($verify['code'] != 0) { return $verify; } // 账户校验 $ac = self::UserLoginAccountsCheck($params); if($ac['code'] != 0) { return $ac; } // 验证码基础参数 key $verify_params['key_prefix'] = 'user_login_'.md5($params['accounts']); // 发送验证码 $code = GetNumberCode(4); switch($params['type']) { // 短信 case 'sms' : $obj = new \base\Sms($verify_params); $status = $obj->SendCode($params['accounts'], $code, ConfigService::SmsTemplateValue('home_sms_login_template')); break; // 邮箱 case 'email' : $obj = new \base\Email($verify_params); $email_params = [ 'email' => $params['accounts'], 'content' => MyC('home_email_login_template'), 'title' => MyC('home_site_name').' - '.MyLang('common_service.user.login_email_send_title'), 'code' => $code, ]; $status = $obj->SendHtml($email_params); break; // 默认 default : return DataReturn(MyLang('verify_code_not_support_send_error_tips'), -2); } if($status) { // 清除验证码 if(isset($verify['data']) && is_object($verify['data'])) { $verify['data']->Remove(); } return DataReturn(MyLang('send_success'), 0); } return DataReturn(MyLang('send_fail').'['.$obj->error.']', -100); } /** * 用户注册-验证码发送 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-10T10:06:29+0800 * @param [array] $params [输入参数] */ public static function RegVerifySend($params = []) { // 数据验证 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'accounts', 'error_msg' => MyLang('accounts_empty_tips'), ], [ 'checked_type' => 'in', 'key_name' => 'type', 'checked_data' => array_column(MyConst('common_user_reg_type_list'), 'value'), 'error_msg' => MyLang('register_type_error_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 是否开启用户注册 if(!in_array($params['type'], MyC('home_user_reg_type', [], true))) { return DataReturn(MyLang('register_close_tips'), -1); } // 验证码基础参数 $verify_params = [ 'key_prefix' => 'user_reg', 'expire_time' => MyC('common_verify_expire_time'), 'interval_time' => MyC('common_verify_interval_time'), ]; // 是否开启图片验证码 $verify = self::IsImaVerify($params, $verify_params, MyC('common_img_verify_state')); if($verify['code'] != 0) { return $verify; } // 账户校验 $ret = self::UserRegAccountsCheck($params); if($ret['code'] != 0) { return $ret; } // 验证码基础参数 key $verify_params['key_prefix'] = 'user_reg_'.md5($params['accounts']); // 发送验证码 $code = GetNumberCode(4); switch($params['type']) { // 短信 case 'sms' : $obj = new \base\Sms($verify_params); $status = $obj->SendCode($params['accounts'], $code, ConfigService::SmsTemplateValue('home_sms_user_reg_template')); break; // 邮箱 case 'email' : $obj = new \base\Email($verify_params); $email_params = [ 'email' => $params['accounts'], 'content' => MyC('home_email_user_reg_template'), 'title' => MyC('home_site_name').' - '.MyLang('common_service.user.register_email_send_title'), 'code' => $code, ]; $status = $obj->SendHtml($email_params); break; // 默认 default : return DataReturn(MyLang('verify_code_not_support_send_error_tips'), -2); } if($status) { // 清除验证码 if(isset($verify['data']) && is_object($verify['data'])) { $verify['data']->Remove(); } return DataReturn(MyLang('send_success'), 0); } return DataReturn(MyLang('send_fail').'['.$obj->error.']', -100); } /** * 密码找回验证码发送 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-10T17:35:03+0800 * @param [array] $params [输入参数] */ public static function ForgetPwdVerifySend($params = []) { // 参数 if(empty($params['accounts'])) { return DataReturn(MyLang('params_error_tips'), -10); } // 验证码基础参数 $verify_params = [ 'key_prefix' => 'user_forget', 'expire_time' => MyC('common_verify_expire_time'), 'interval_time' => MyC('common_verify_interval_time'), ]; // 是否开启图片验证码 $verify = self::IsImaVerify($params, $verify_params, MyC('common_img_verify_state')); if($verify['code'] != 0) { return $verify; } // 账户是否存在,并返回账户格式类型 $ret = self::UserForgetAccountsCheck($params['accounts']); if($ret['code'] != 0) { return $ret; } // 验证码基础参数 key $verify_params['key_prefix'] = 'user_forget_'.md5($params['accounts']); // 验证码 $code = GetNumberCode(4); // 账户字段类型 switch($ret['data']) { // 手机 case 'mobile' : $obj = new \base\Sms($verify_params); $status = $obj->SendCode($params['accounts'], $code, ConfigService::SmsTemplateValue('home_sms_user_forget_pwd_template')); break; // 邮箱 case 'email' : $obj = new \base\Email($verify_params); $email_params = [ 'email' => $params['accounts'], 'content' => MyC('home_email_user_forget_pwd_template'), 'title' => MyC('home_site_name').' - '.MyLang('common_service.user.forget_pwd_email_send_title'), 'code' => $code, ]; $status = $obj->SendHtml($email_params); break; // 默认 default : return DataReturn(MyLang('common_service.user.mobile_or_email_format_error_tips'), -1); } if($status) { // 清除图片验证码 if(isset($verify) && isset($verify['data']) && is_object($verify['data'])) { $verify['data']->Remove(); } return DataReturn(MyLang('send_success'), 0); } return DataReturn(MyLang('send_fail').'['.$obj->error.']', -100); } /** * 帐号校验 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-10T17:59:53+0800 * @param [string] $accounts [账户名称] * @return [string] [账户字段 mobile, email] */ public static function UserForgetAccountsCheck($accounts) { if(CheckMobile($accounts)) { if(!self::IsExistAccounts($accounts, 'mobile')) { return DataReturn(MyLang('mobile_no_exist_error_tips'), -3); } return DataReturn(MyLang('operate_success'), 0, 'mobile'); } else if(CheckEmail($accounts)) { if(!self::IsExistAccounts($accounts, 'email')) { return DataReturn(MyLang('email_no_exist_error_tips'), -3); } return DataReturn(MyLang('operate_success'), 0, 'email'); } return DataReturn(MyLang('common_service.user.mobile_or_email_format_error_tips'), -4); } /** * 密码找回 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2017-03-10T17:35:03+0800 * @param [array] $params [输入参数] */ public static function ForgetPwd($params = []) { // 数据验证 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'accounts', 'error_msg' => MyLang('accounts_empty_tips'), ], [ 'checked_type' => 'empty', 'key_name' => 'pwd', 'error_msg' => MyLang('password_empty_tips'), ], [ 'checked_type' => 'empty', 'key_name' => 'verify', 'error_msg' => MyLang('verify_code_empty_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 账户是否存在 $ret = self::UserForgetAccountsCheck($params['accounts']); if($ret['code'] != 0) { return $ret; } // 验证码校验 $verify_params = [ 'key_prefix' => 'user_forget_'.md5($params['accounts']), 'expire_time' => MyC('common_verify_expire_time'), 'interval_time' => MyC('common_verify_interval_time'), ]; switch($ret['data']) { // 手机 case 'mobile' : $obj = new \base\Sms($verify_params); break; // 邮箱 case 'email' : $obj = new \base\Email($verify_params); break; // 默认 default : return DataReturn(MyLang('common_service.user.mobile_or_email_format_error_tips'), -1); } // 是否已过期 if(!$obj->CheckExpire()) { return DataReturn(MyLang('verify_code_expire_tips'), -10); } // 是否正确 if(!$obj->CheckCorrect($params['verify'])) { return DataReturn(MyLang('verify_code_error_tips'), -11); } // 获取用户信息 $user = self::UserInfo($ret['data'], $params['accounts']); if(empty($user)) { return DataReturn(MyLang('common_service.user.save_user_info_no_exist_tips'), -12); } // 密码修改 $ret = SafetyService::UserLoginPwdUpdate($params['accounts'], $user['id'], $params['pwd']); if($ret['code'] == 0) { // 清除验证码 if(isset($obj) && is_object($obj)) { $obj->Remove(); } return DataReturn(MyLang('operate_success'), 0); } return $ret; } /** * 用户资料保存 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-04 * @desc description * @param [array] $params [输入参数] */ public static function PersonalSave($params = []) { // 数据验证 $p = [ [ 'checked_type' => 'length', 'checked_data' => '1,60', 'key_name' => 'nickname', 'is_checked' => 2, 'error_msg' => MyLang('common_service.user.save_nickname_format_error_tips'), ], [ 'checked_type' => 'in', 'checked_data' => [0,1,2], 'key_name' => 'gender', 'is_checked' => 2, 'error_msg' => MyLang('common_service.user.save_gender_range_error_tips'), ], [ 'checked_type' => 'empty', 'key_name' => 'user', 'error_msg' => MyLang('user_info_incorrect_tips'), ], [ 'checked_type' => 'length', 'key_name' => 'address', 'checked_data' => '80', 'is_checked' => 2, 'error_msg' => MyLang('common_service.user.form_item_address_message'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 更新的字段 $fields = [ 'avatar', 'birthday', 'nickname', 'gender', 'province', 'city', 'county', 'address', 'mobile', ]; $data = []; foreach($fields as $k) { if(array_key_exists($k, $params)) { switch($k) { // 头像 case 'avatar' : $data[$k] = empty($params['avatar']) ? '' : ResourcesService::AttachmentPathHandle($params['avatar']); break; // 生日 case 'birthday' : $data[$k] = empty($params['birthday']) ? '' : strtotime($params['birthday']); break; // 手机、用户基础信息填写一键授权手机号码 case 'mobile' : if(!empty($params['mobile'])) { // 手机号码不存在则绑定到当前账号下 $method = self::UserUniqueMethod(); $temp = self::$method('mobile', $params['mobile']); if(empty($temp)) { $data[$k] = $params['mobile']; } } break; default : $data[$k] = empty($params[$k]) ? '' : $params[$k]; } } } if(empty($data)) { return DataReturn(MyLang('content_params_empty_tips'), -1); } // 更新用户信息 if(self::UserUpdateHandle($data, $params['user']['id'], $params)) { // 重新获取用户信息 $user = self::UserHandle(self::UserInfo('id', $params['user']['id'])); // 重新更新用户缓存 self::UserLoginRecord(0, $user); // 去除 if(!empty($user['token'])) { MyCache(SystemService::CacheKey('shopxo.cache_user_info').$user['token'], $user); } return DataReturn(MyLang('change_success'), 0, $user); } return DataReturn(MyLang('change_fail'), -100); } /** * 用户授权数据 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-11-06 * @desc description * @param [array] $params [用户数据] * @param [string] $field [平台字段名称] */ public static function AuthUserProgram($params, $field) { // 用户信息 $data = [ $field => $params['openid'], 'nickname' => empty($params['nickname']) ? '' : $params['nickname'], 'avatar' => empty($params['avatar']) ? '' : $params['avatar'], 'gender' => empty($params['gender']) ? 0 : intval($params['gender']), 'province' => empty($params['province']) ? '' : $params['province'], 'city' => empty($params['city']) ? '' : $params['city'], 'county' => empty($params['county']) ? '' : $params['county'], 'mobile' => empty($params['mobile']) ? '' : $params['mobile'], 'referrer' => isset($params['referrer']) ? $params['referrer'] : 0, ]; // 用户唯一方法 $method = self::UserUniqueMethod(); // 是否需要添加用户 $is_insert_user = false; // 用户信息处理 $user_platform = self::UserPlatformInfo($field, $params['openid']); if(!empty($user_platform)) { // 用户信息 $user = self::UserBaseInfo('id', $user_platform['user_id']); if(empty($user)) { $is_insert_user = true; } else { // 用户状态 if($user['status'] != 0) { return DataReturn(MyLang('common_service.user.user_not_audit_tips'), -301); } // 如果有手机号码、如当前用户不存在手机号码则绑定 if(empty($user['mobile']) && !empty($data['mobile'])) { // 手机号码不存在则绑定到当前账号下 $temp = self::$method('mobile', $data['mobile']); if(empty($temp)) { // 是否被禁止 $ret = self::UserRegForbidCheck($data['mobile'], 'mobile'); if($ret['code'] != 0) { return $ret; } // 绑定手机 $upd_data = [ 'mobile' => $data['mobile'], 'upd_time' => time(), ]; if(Db::name('User')->where(['id'=>$user['id']])->update($upd_data)) { return DataReturn(MyLang('bind_success'), 0, self::AppUserInfoHandle(['where_field'=>'id', 'where_value'=>$user['id']])); } } else { if($user['id'] != $temp['id']) { return DataReturn(MyLang('common_service.user.mobile_already_bind_account_tips'), -1); } } } return DataReturn(MyLang('auth_success'), 0, $user); } } else { // 用户unionid $unionid = self::UserUnionidHandle($params); if(!empty($unionid['field']) && !empty($unionid['value'])) { // unionid字段是否存在用户 $unionid_user_platform = self::UserPlatformInfo($unionid['field'], $unionid['value']); if(!empty($unionid_user_platform)) { // 用户信息 $unionid_user_base = self::UserBaseInfo('id', $unionid_user_platform['user_id']); if(empty($user)) { $is_insert_user = true; } else { // 用户状态 if($unionid_user_base['status'] != 0) { return DataReturn(MyLang('common_service.user.user_not_audit_tips'), -301); } // openid绑定 if(!self::UserPlatformUpdate('id', $unionid_user_platform['id'], [$field => $params['openid']], $params)) { return DataReturn(MyLang('bind_fail'), -1); } // 如果有手机号码、如当前用户不存在手机号码则绑定 if(empty($unionid_user_base['mobile']) && !empty($data['mobile'])) { // 手机号码不存在则绑定到当前账号下 $temp = self::$method('mobile', $data['mobile']); if(empty($temp)) { // 是否被禁止 $ret = self::UserRegForbidCheck($data['mobile'], 'mobile'); if($ret['code'] != 0) { return $ret; } // 绑定手机 $upd_data = [ 'mobile' => $data['mobile'], 'upd_time' => time(), ]; if(!Db::name('User')->where(['id'=>$unionid_user_base['id']])->update($upd_data)) { return DataReturn(MyLang('bind_fail'), -1); } } else { if($unionid_user_base['id'] != $temp['id']) { return DataReturn(MyLang('common_service.user.mobile_already_bind_account_tips'), -1); } } } return DataReturn(MyLang('bind_success'), 0, self::AppUserInfoHandle(['where_field'=>'id', 'where_value'=>$unionid_user_base['id']])); } } // 如果用户不存在数据库中,则unionid放入用户data中 $data[$unionid['field']] = $unionid['value']; } // 不强制绑定手机则写入用户信息 if(intval(MyC('common_user_is_mandatory_bind_mobile')) != 1) { $is_insert_user = true; } else { // 绑定手机号码 if(!empty($data['mobile'])) { // 如果手机号码存在则直接绑定openid // 不存在添加,存在更新openid $user = self::$method('mobile', $data['mobile']); if(!empty($user)) { // 上面openid和unionid都没存在信息,但是存在手机号码信息则增加用户平台数据 $user_platform_insert = [ 'user_id' => $user['id'], $field => $params['openid'], ]; if(!empty($unionid['field']) && !empty($unionid['value'])) { $user_platform_insert[$unionid['field']] = $unionid['value']; } if(self::UserPlatformInsert($user_platform_insert, $params)) { return DataReturn(MyLang('bind_success'), 0, self::AppUserInfoHandle(['where_field'=>'id', 'where_value'=>$user['id']])); } } else { $is_insert_user = true; } } } } // 添加用户 if($is_insert_user) { // 是否需要审核 $common_register_is_enable_audit = MyC('common_register_is_enable_audit', 0); $data['status'] = ($common_register_is_enable_audit == 1) ? 3 : 0; // 添加用户 $ret = self::UserInsert($data, $params); if($ret['code'] == 0) { // 是否需要审核 if($common_register_is_enable_audit == 1) { return DataReturn(MyLang('common_service.user.user_not_audit_tips'), -110); } return DataReturn(MyLang('auth_success'), 0, self::AppUserInfoHandle(['where_field'=>'id', 'where_value'=>$ret['data']['user_id'], 'is_refresh_token'=>0])); } return $ret; } return DataReturn(MyLang('auth_success'), 0, self::AppUserInfoHandle(['user'=>$data])); } /** * 用户openid绑定 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2021-06-21 * @desc description * @param [int] $user_id [用户id] * @param [string] $openid [openid] * @param [string] $field [openid 字段] */ public static function UserOpenidBind($user_id, $openid, $field) { return self::UserPlatformUpdate('user_id', $user_id, [$field => $openid]); } /** * 用户openid处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2020-02-11 * @desc description * @param [array] $params [输入参数] */ public static function UserOpenidHandle($params = []) { $field = null; $value = null; $fields_arr = array_column(MyConst('common_appmini_type'), 'value'); foreach($fields_arr as $type) { $openid = $type.'_openid'; if(!empty($params[$openid])) { $field = $openid; $value = $params[$openid]; break; } } return ['field'=>$field, 'value'=>$value]; } /** * 用户unionid处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2020-02-11 * @desc description * @param [array] $params [输入参数] */ public static function UserUnionidHandle($params = []) { // 用户unionid列表 // 微信用户unionid // QQ用户unionid // 头条用户unionid $field = null; $value = null; $fields_arr = ['weixin_unionid', 'qq_unionid', 'toutiao_unionid']; foreach($fields_arr as $unionid) { if(!empty($params[$unionid])) { $field = $unionid; $value = $params[$unionid]; break; } } return ['field'=>$field, 'value'=>$value]; } /** * app用户信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-11-06 * @desc description * @param [array] $params [输入参数] */ public static function AppUserInfoHandle($params = []) { // 获取用户信息 if(!empty($params['user_id'])) { $params['user'] = self::UserHandle(self::UserInfo('id', $params['user_id'])); } elseif(!empty($params['where_field']) && !empty($params['where_value']) && empty($params['user'])) { $params['user'] = self::UserHandle(self::UserInfo($params['where_field'], $params['where_value'])); } if(!empty($params['user'])) { // 是否强制绑定手机号码 $params['user']['is_mandatory_bind_mobile'] = intval(MyC('common_user_is_mandatory_bind_mobile')); // 基础处理 if(!empty($params['user']['id'])) { // 会员码生成处理 if(empty($params['user']['number_code'])) { $params['user']['number_code'] = self::UserNumberCodeCreatedHandle($params['user']['id']); } // 重新生成token更新到数据库并缓存 if(!isset($params['is_refresh_token']) || $params['is_refresh_token'] == 1) { $params['user']['token'] = self::UserTokenUpdate($params['user']['id'], $params['user']); } } // token读取没有缓存则记录缓存 if(!empty($params['where_field']) && !empty($params['where_value']) && $params['where_field'] == 'token') { $user_cache_login_info = self::CacheUserTokenData($params['where_value']); if(empty($user_cache_login_info)) { MyCache(SystemService::CacheKey('shopxo.cache_user_info').$params['where_value'], $params['user']); } } // 用户信息钩子 $hook_name = 'plugins_service_user_app_info_handle'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => (empty($params['user']) || empty($params['user']['id'])) ? 0 : $params['user']['id'], 'user' => &$params['user'], 'params' => $params, ]); } return $params['user']; } /** * 用户 token更新 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2021-07-01 * @desc description * @param [int] $user_id [用户id] * @param [array] $user [指定用户信息] */ public static function UserTokenUpdate($user_id, $user = []) { // 未指定用户则读取用户信息、并处理数据 if(empty($user) && !empty($user_id)) { $user = self::UserHandle(self::UserInfo('id', $user_id)); } if(!empty($user)) { // token生成并存储缓存 $user['token'] = ApiService::CreatedUserToken($user['id']); if(self::UserPlatformUpdate('user_id', $user['id'], ['token'=>$user['token'], 'upd_time'=>time()]) !== false) { MyCache(SystemService::CacheKey('shopxo.cache_user_info').$user['token'], $user); } } return (empty($user) || empty($user['token'])) ? '' : $user['token']; } /** * 用户添加 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-04-03 * @desc description * @param [array] $data [用户添加数据] * @param [array] $params [输入参数] */ public static function UserInsert($data, $params = []) { // 用户唯一方法 $method = self::UserUniqueMethod(); // 用户名、手机、邮箱不允许重复注册 if(!empty($data['username'])) { // 是否被禁止 $ret = self::UserRegForbidCheck($data['username'], 'username'); if($ret['code'] != 0) { return $ret; } // 唯一验证 $temp = self::$method('username', $data['username']); if(!empty($temp)) { return DataReturn(str_replace('{$var}', $data['username'], MyLang('common_service.user.save_user_already_exist_tips')), -10); } } else if(!empty($data['mobile'])) { // 是否被禁止 $ret = self::UserRegForbidCheck($data['mobile'], 'mobile'); if($ret['code'] != 0) { return $ret; } // 唯一验证 $temp = self::$method('mobile', $data['mobile']); if(!empty($temp)) { return DataReturn(MyLang('common_service.user.mobile_already_exist_tips'), -10); } } else if(!empty($data['email'])) { // 是否被禁止 $ret = self::UserRegForbidCheck($data['email'], 'email'); if($ret['code'] != 0) { return $ret; } // 唯一验证 $temp = self::$method('email', $data['email']); if(!empty($temp)) { return DataReturn(MyLang('common_service.user.email_already_exist_tips'), -10); } } // 用户基础信息处理 $data = self::UserBaseHandle($data, $params); // 用户openid $openid = self::UserOpenidHandle($params); if(!empty($openid['field']) && !empty($openid['value'])) { // openid放入用户data中 $data[$openid['field']] = $openid['value']; } // 用户unionid $unionid = self::UserUnionidHandle($params); if(!empty($unionid['field']) && !empty($unionid['value'])) { // unionid放入用户data中 $data[$unionid['field']] = $unionid['value']; } // 推荐人id $data['referrer'] = self::UserReferrerDecrypt($params); // 注册数据分离处理 // 用户平台表结构 $structure = ResourcesService::TableStructureData('UserPlatform'); unset($structure['id'], $structure['user_id'], $structure['add_time'], $structure['upd_time']); $user_base = []; $user_platform = []; foreach($data as $k=>$v) { if(array_key_exists($k, $structure)) { $user_platform[$k] = $v; } else { $user_base[$k] = $v; } } // 注册添加之前钩子 $hook_name = 'plugins_service_user_register_begin'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'user_base' => &$user_base, 'user_platform' => &$user_platform, ]); // 用户信息以手机或邮箱、不存在则添加 $user_base['add_time'] = time(); $user_id = Db::name('User')->insertGetId($user_base); if($user_id <= 0) { return DataReturn(MyLang('insert_fail'), -100); } // 用户平台信息添加 $user_platform['user_id'] = $user_id; if(!self::UserPlatformInsert($user_platform, $params)) { return DataReturn(MyLang('insert_fail'), -100); } // 会员码生成处理 self::UserNumberCodeCreatedHandle($user_id); // token self::UserTokenUpdate($user_id); // 清除推荐id if(!empty($user_base['referrer'])) { MySession('share_referrer_id', null); MyCookie('share_referrer_id', null); } // 返回前端html代码 $body_html = []; // 注册成功后钩子 $user = self::UserHandle(self::UserInfo('id', $user_id, 'id,number_code,system_type,token,status,username,nickname,mobile,email,gender,avatar,province,city,county,birthday,add_time')); $hook_name = 'plugins_service_user_register_end'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, 'user_id' => $user_id, 'user' => $user, 'body_html' => &$body_html, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 登录返回 $result = [ 'body_html' => is_array($body_html) ? implode(' ', $body_html) : $body_html, 'user_id' => $user_id, ]; return DataReturn(MyLang('insert_success'), 0, $result); } /** * 会员码生成处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2022-11-09 * @desc description * @param [int] $user_id [用户id] */ public static function UserNumberCodeCreatedHandle($user_id) { // 会员码 $max = 10; $len = strlen($user_id); $number_code = '8888'.(($len < $max) ? GetNumberCode($max-$len).$user_id : $user_id); // 更新数据库 Db::name('User')->where(['id'=>$user_id])->update(['number_code'=>$number_code]); return $number_code; } /** * 用户基础信息处理、注册绑定的时候处理外部传入的基础信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2021-11-13 * @desc description * @param [array] $data [用户信息] * @param [array] $params [输入参数] */ public static function UserBaseHandle($data, $params = []) { // 系统类型 if(empty($data['system_type'])) { $data['system_type'] = empty($params['system_type_name']) ? SYSTEM_TYPE : $params['system_type_name']; } // 基础参数处理 if(!empty($params) && is_array($params)) { // 是否存在基信息 // 参数key => dbkey $base_fields = [ 'nickname' => [ 'key' => 'nickname', 'type' => 'string' ], 'avatar' => [ 'key' => 'avatar', 'type' => 'url' ], 'province' => [ 'key' => 'province', 'type' => 'string' ], 'city' => [ 'key' => 'city', 'type' => 'string' ], 'county' => [ 'key' => 'county', 'type' => 'string' ], 'gender' => [ 'key' => 'gender', 'type' => 'int', 'isset' => 1 ], ]; foreach($base_fields as $k=>$v) { if(!empty($params[$k]) || (isset($v['isset']) && isset($params[$k]))) { switch($v['type']) { // url处理 case 'url' : $params[$k] = str_replace(['&'], ['&'], $params[$k]); // 头像如果是默认则置空 if($k == 'avatar' && !empty($params[$k]) && stripos($params[$k], 'default-user-avatar') !== false) { $params[$k] = ''; } break; // 整数 case 'int' : $params[$k] = intval($params[$k]); break; } $data[$v['key']] = $params[$k]; } } } return $data; } /** * app用户手机绑定 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-27 * @desc description * @param [array] $params [输入参数] */ public static function AppMobileBind($params = []) { return self::AppAccountsBindhHandle('mobile', $params); } /** * app用户邮箱绑定 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-27 * @desc description * @param [array] $params [输入参数] */ public static function AppEmailBind($params = []) { return self::AppAccountsBindhHandle('email', $params); } /** * app用户手机或邮箱绑定 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2024-03-11 * @desc description * @param [string] $type [字段每次类型(mobile, email)] * @param [array] $params [输入参数] */ public static function AppAccountsBindhHandle($type, $params = []) { // 数据验证 $p = [ [ 'checked_type' => 'empty', 'key_name' => $type, 'error_msg' => MyLang('common_service.user.'.$type.'_empty_tips'), ], [ 'checked_type' => 'empty', 'key_name' => 'verify', 'error_msg' => MyLang('verify_code_empty_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 用户手机或邮箱绑定前校验钩子 $hook_name = 'plugins_service_user_app_'.$type.'_bind_begin_check'; $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, ])); if(isset($ret['code']) && $ret['code'] != 0) { return $ret; } // 格式验证 $check_fun = 'Check'.ucfirst($type); if(!$check_fun($params[$type])) { return DataReturn(MyLang($type.'_format_error_tips'), -2); } // 验证码校验 $verify_params = [ 'key_prefix' => 'user_bind_'.md5($params[$type]), 'expire_time' => MyC('common_verify_expire_time') ]; $obj = new \base\Sms($verify_params); // 是否已过期 if(!$obj->CheckExpire()) { return DataReturn(MyLang('verify_code_expire_tips'), -10); } // 是否正确 if(!$obj->CheckCorrect($params['verify'])) { return DataReturn(MyLang('verify_code_error_tips'), -11); } // 用户更新数据 $data = [ $type => $params[$type], ]; // 是否小程序请求 $is_appmini = array_key_exists(APPLICATION_CLIENT_TYPE, MyConst('common_appmini_type')); // 根据绑定账户类型【手机或邮箱】获取用户信息 $method = self::UserUniqueMethod(); $db_user = self::$method($type, $data[$type]); // 额外信息 if(empty($db_user)) { if(empty($db_user['nickname']) && !empty($params['nickname'])) { $data['nickname'] = $params['nickname']; } if(empty($db_user['avatar']) && !empty($params['avatar'])) { $data['avatar'] = $params['avatar']; } if(empty($db_user['province']) && !empty($params['province'])) { $data['province'] = $params['province']; } if(empty($db_user['city']) && !empty($params['city'])) { $data['city'] = $params['city']; } if(empty($db_user['county']) && !empty($params['county'])) { $data['county'] = $params['county']; } if(empty($db_user) && isset($params['gender'])) { $data['gender'] = intval($params['gender']); } } // 小程序请求处理 if($is_appmini) { // openid必须存在 $accounts_field = APPLICATION_CLIENT_TYPE.'_openid'; if(empty($params[$accounts_field])) { return DataReturn(MyLang('common_service.user.user_openid_empty_tips'), -20); } // openid数据 $data[$accounts_field] = $params[$accounts_field]; // 小程序请求获取用户信息 $user_platform = self::UserPlatformInfo($accounts_field, $params[$accounts_field]); $current_user = empty($user_platform) ? [] : self::UserBaseInfo('id', $user_platform['user_id']); } else { // 当前登录用户 $current_user = self::LoginUserInfo(); } // 用户是否存在已登录 if(!empty($current_user)) { // 手机帐号信息是否存在 if(!empty($db_user)) { // id不一致则提示错误 if($current_user['id'] != $db_user['id']) { return DataReturn(MyLang('common_service.user.'.$type.'_already_bind_account_tips'), -50); } // 是否与当前帐号的手机号码一致 if(!empty($current_user[$type]) && $current_user[$type] == $db_user[$type]) { return DataReturn(MyLang('common_service.user.'.$type.'_current_mobile_identical_tips'), -51); } } // 当前用户赋值手机帐号信息 $db_user = $current_user; } // 不存在添加/则更新 if(empty($db_user)) { // 如果用户不存在则新增用户状态字段 // 是否需要审核 $common_register_is_enable_audit = MyC('common_register_is_enable_audit', 0); $data['status'] = ($common_register_is_enable_audit == 1) ? 3 : 0; // 新增用户 $user_ret = self::UserInsert($data, $params); if($user_ret['code'] != 0) { return $user_ret; } $user_id = $user_ret['data']['user_id']; } else { // 小程序请求处理 if($is_appmini) { // 用户unionid $unionid = self::UserUnionidHandle($params); if(!empty($unionid['field']) && !empty($unionid['value'])) { if(empty($db_user[$unionid['field']])) { // unionid放入用户data中 $data[$unionid['field']] = $unionid['value']; } } } // 帐号信息更新 $ret = self::UserUpdateHandle($data, $db_user['id'], $params); if($ret['code'] != 0) { return $ret; } $user_id = $db_user['id']; } if(isset($user_id) && $user_id > 0) { // 用户平台信息、不存在则添加 $user_platform = self::UserPlatformInfo('user_id', $user_id); if(empty($user_platform)) { if(!self::UserPlatformInsert(['user_id' => $user_id], $params)) { return DataReturn(MyLang('insert_fail'), -1); } } // 清除验证码 $obj->Remove(); return DataReturn(MyLang('bind_success'), 0, self::AppUserInfoHandle(['where_field'=>'id', 'where_value'=>$user_id])); } return DataReturn(MyLang('bind_fail'), -100); } /** * app用户手机绑定验证码发送 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-27 * @desc description * @param [array] $params [输入参数] */ public static function AppMobileBindVerifySend($params = []) { return self::AppAccountsBindVerifySendHandle('mobile', $params); } /** * app用户邮箱绑定验证码发送 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2018-12-27 * @desc description * @param [array] $params [输入参数] */ public static function AppEmailBindVerifySend($params = []) { return self::AppAccountsBindVerifySendHandle('email', $params); } /** * app用户手机或邮箱绑定验证码发送处理 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2024-03-11 * @desc description * @param [string] $type [字段每次类型(mobile, email)] * @param [array] $params [输入参数] */ public static function AppAccountsBindVerifySendHandle($type, $params = []) { // 数据验证 $p = [ [ 'checked_type' => 'empty', 'key_name' => $type, 'error_msg' => MyLang('common_service.user.'.$type.'_empty_tips'), ], [ 'checked_type' => 'fun', 'key_name' => $type, 'checked_data' => 'Check'.ucfirst($type), 'error_msg' => MyLang($type.'_format_error_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 验证码公共基础参数 $verify_params = [ 'key_prefix' => 'user_bind_'.md5($params[$type]), 'expire_time' => MyC('common_verify_expire_time'), 'interval_time' => MyC('common_verify_interval_time'), ]; // 发送验证码 $code = GetNumberCode(4); switch($type) { // 短信 case 'mobile' : $obj = new \base\Sms($verify_params); $status = $obj->SendCode($params[$type], $code, ConfigService::SmsTemplateValue('home_sms_user_mobile_binding_template')); break; // 邮箱 case 'email' : $obj = new \base\Email($verify_params); $email_params = [ 'email' => $params[$type], 'content' => MyC('home_email_user_email_binding_template'), 'title' => MyC('home_site_name').' - '.MyLang('common_service.safety.send_verify_email_title'), 'code' => $code, ]; $status = $obj->SendHtml($email_params); break; // 默认 default : return DataReturn(MyLang('verify_code_not_support_send_error_tips'), -2); } if($status) { return DataReturn(MyLang('send_success'), 0); } return DataReturn(MyLang('send_fail').'['.$obj->error.']', -100); } /** * 根据token获取用户信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2021-12-06 * @desc description * @param [array] $params [输入参数] */ public static function TokenUserinfo($params = []) { // 数据验证 $p = [ [ 'checked_type' => 'empty', 'key_name' => 'token', 'error_msg' => MyLang('common_service.user.token_empty_tips'), ], ]; $ret = ParamsChecked($params, $p); if($ret !== true) { return DataReturn($ret, -1); } // 获取用户信息并处理 $user = self::UserHandle(self::UserInfo('token', $params['token'])); if(empty($user)) { return DataReturn(MyLang('common_service.user.save_user_info_no_exist_tips'), -1); } return DataReturn('success', 0, $user); } /** * 用户退出 * @author Devil * @blog http://gong.gg/ * @version 0.0.1 * @datetime 2016-12-05T14:31:23+0800 * @param [array] $params [输入参数] */ public static function Logout($params = []) { // 用户信息 $user = self::CacheLoginUserInfo(); // 清除session MySession(self::$user_login_key, null); // html代码 $body_html = []; // 用户退出钩子 $hook_name = 'plugins_service_user_logout_handle'; MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => [], 'user_id' => isset($user['id']) ? $user['id'] : 0, 'user' => $user, 'body_html' => &$body_html, ]); // 数据返回 $result = [ 'body_html' => is_array($body_html) ? implode(' ', $body_html) : $body_html, ]; return DataReturn(MyLang('quit_success'), 0, $result); } /** * 获取用户展示信息 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-05-05 * @desc description * @param [array|int] $user_ids [用户id] * @param [array] $user [指定用户信息] */ public static function GetUserViewInfo($user_ids, $user = []) { // 是否指定用户信息 if(empty($user) && !empty($user_ids)) { // 参数处理查询数据 if(is_array($user_ids)) { $user_ids = array_filter(array_unique($user_ids)); } // 静态数据容器,确保每一个用户只读取一次,避免重复读取浪费资源 static $user_view_info_static_data = []; if(!empty($user_ids)) { $temp_user_ids = []; $params_user_ids = is_array($user_ids) ? $user_ids : explode(',', $user_ids); foreach($params_user_ids as $uid) { if(empty($user_view_info_static_data) || !array_key_exists($uid, $user_view_info_static_data)) { $temp_user_ids[] = $uid; } } // 存在未读取的规格咋数据库读取 if(!empty($temp_user_ids)) { $data = Db::name('User')->where(['id'=>$temp_user_ids])->column('id,number_code,username,nickname,mobile,email,avatar,gender,birthday,province,city,county,address,integral,locking_integral,add_time', 'id'); if(!empty($data)) { foreach($data as $uid=>$uv) { $user_view_info_static_data[$uid] = self::UserHandle($uv); } } // 空数据记录、避免重复查询 foreach($temp_user_ids as $uid) { if(!array_key_exists($uid, $user_view_info_static_data)) { $user_view_info_static_data[$uid] = null; } } } } // 用户id是否数组 if(is_array($user_ids)) { $user = isset($user_view_info_static_data) ? $user_view_info_static_data : []; } else { $user = (!empty($user_view_info_static_data) && array_key_exists($user_ids, $user_view_info_static_data)) ? $user_view_info_static_data[$user_ids] : []; } } else { if(!empty($user)) { $user = self::UserHandle($user); } } return $user; } /** * 用户登录,密码找回左侧数据 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-05-17 * @desc description * @param [array] $params [输入参数] */ public static function UserEntranceLeftData($params = []) { // 从缓存获取 $data = empty($params['cache_key']) ? [] : MyCache($params['cache_key']); // 获取数据 if(empty($data)) { $data = []; if(!empty($params['left_key'])) { for($i=1; $i<=3; $i++) { $images_value = MyC('home_site_user_'.$params['left_key'].'_ad'.$i.'_images'); $url_value = MyC('home_site_user_'.$params['left_key'].'_ad'.$i.'_url'); $bg_color_value = MyC('home_site_user_'.$params['left_key'].'_ad'.$i.'_bg_color'); if(!empty($images_value)) { $data[] = [ 'images' => ResourcesService::AttachmentPathViewHandle($images_value), 'url' => empty($url_value) ? null : $url_value, 'bg_color' => empty($bg_color_value) ? null : $bg_color_value, ]; } } // 存储缓存 if(!empty($params['cache_key'])) { MyCache($params['cache_key'], $data); } } } return DataReturn(MyLang('operate_success'), 0, $data); } /** * 用户推荐id加密 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-06-21 * @desc description * @param [int] $user_id [用户id] */ public static function UserReferrerEncryption($user_id) { return StrToAscii(base64_encode($user_id)); } /** * 用户推荐id解密 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2019-06-21 * @desc description * @param [array] $params [输入参数, referrer 参数用户推荐id, 会员码, 手机, 邮箱] */ public static function UserReferrerDecrypt($params = []) { // 推荐人 if(empty($params['referrer'])) { $referrer = MySession('share_referrer_id'); if(empty($referrer)) { $referrer = MyCookie('share_referrer_id'); } } else { $referrer = $params['referrer']; } if(!empty($referrer)) { // 用户验证、默认用户id和会员码 $field = 'id|number_code'; // 是否手机号码 if(CheckMobile($referrer)) { $field = 'mobile'; // 是否电子邮箱 } else if(CheckEmail($referrer)) { $field = 'email'; } else { // 查看用户id是否已加密 if(preg_match('/[a-zA-Z]/', $referrer)) { $referrer = intval(base64_decode(AsciiToStr($referrer))); } } $referrer = Db::name('User')->where([$field=>$referrer, 'status'=>0])->value('id'); } return empty($referrer) ? 0 : intval($referrer); } /** * 用户登录注册后跳转页面地址 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2021-03-04 * @desc description */ public static function UserLoginOrRegBackRefererUrl() { // 上一个页面, 空则用户中心 $referer_url = empty($_SERVER['HTTP_REFERER']) ? MyUrl('index/user/index') : htmlentities($_SERVER['HTTP_REFERER']); if(!empty($_SERVER['HTTP_REFERER'])) { // 是否是指定页面,则赋值用户中心 $all = ['login', 'register', 'forget', 'logininfo', 'reginfo', 'smsreginfo', 'emailreginfo', 'forgetpwdinfo', 'logout']; $status = false; foreach($all as $v) { if(strpos($_SERVER['HTTP_REFERER'], $v) !== false) { $referer_url = MyUrl('index/user/index'); $status = true; break; } } // 未匹配到指定页面 if(!$status) { // 非商城域名,则赋值用户中心 if(GetUrlHost($referer_url) != GetUrlHost(__MY_URL__)) { $referer_url = MyUrl('index/user/index'); } } } return $referer_url; } /** * 用户名、手机、邮箱注册是否禁止 * @author Devil * @blog http://gong.gg/ * @version 1.0.0 * @date 2024-12-18 * @desc description * @param [string] $value [用户名、手机、邮箱] * @param [string] $type [类型 username用户名、mobile手机、email邮箱] */ public static function UserRegForbidCheck($value, $type) { $forbid = MyC('home_userregister_unique_forbid_value'); if(!empty($forbid)) { if(!is_array($forbid)) { $forbid = explode(',', $forbid); } if(in_array($value, $forbid)) { return DataReturn(MyLang('register_'.$type.'_forbid_error_tips').'('.$value.')', -1); } } return DataReturn('success', 0); } } ?>