app_key = $app_key; $this->redis_login = "wxapp_{$app_key}_login_"; $this->redis_mcode = "wxapp_{$app_key}_mcode_"; $this->redis_hxcode = "wxapp_{$app_key}_hxcode_"; if (false !== strpos($_SERVER['HTTP_HOST'], 'dev')) { //dev 测试 $this->env = 'd'; } elseif (false !== strpos($_SERVER['HTTP_HOST'], 'test')) {//test 测试 $this->env = 't'; } else { // 正式 $this->env = 'p'; } //app配置 $config = $this->get_config($app_key); $this->wx_config = $config['wx']; $this->cf_title = $config['name']; $this->app_id = $config['app_id']; $this->model_app_user = $config['model']['user_model'];//应用用户model //根据app_id重载model $this->load->rebuild_model($this->app_id); //日志文件 $class_name = lcfirst(get_class($this));//调用类的名称,子类或者当前类名称 $this->log_file = "wxapp_{$app_key}_{$class_name}.log"; $this->log_dir = "wxapp_{$app_key}_{$class_name}"; //设置input $this->set_input($inputs); //加载library $this->load->library('entity/user_entity'); $this->load->library('hd_exception'); $this->u_entity = new User_entity($this->app_id); $this->app_redis = &load_cache('redis'); //加载model if ($this->model_app_user) { $this->load->model($this->model_app_user, 'app_user_model'); } //获取session $this->fetch_session(); } /** * 获取参数 * @param string $key * @return array|mixed */ function input_param($key = '') { if ($key) { return $this->inputs[$key]; } return $this->inputs; } /** * @param $name "请求方法" * @param $arguments (第一个参数默认版本号) * @return mixed * @throws Exception */ function __call($name, $arguments) { $version = $arguments[0]; $sversion = $arguments[1]; //一些接口的分支需要校验,如biz里的rec_list,是需要登录的 $pre_call = 'call__'; if (0 === strpos($name, $pre_call)) { $name = substr($name, strlen($pre_call)); } $method = $name; if ($version) {//版本号的方法存在用版本号的,否则继续用默认的方法 if (method_exists($this, $method . '__' . $version)) { $method .= '__' . $version; } } if ($sversion) {//小版本,设置某个方法的版本 $sversion = str_replace('.', '_', $sversion); if (method_exists($this, $method . '__' . $sversion)) { $method .= '__' . $sversion; } } if (!method_exists($this, $method)) { debug_log("[fail]" . __FUNCTION__ . ": request not allow; method:{$method}", $this->log_file); throw new Exception('非法请求', API_CODE_NONE); } //某个方法或者整个ct在白名单里无需校验 $session = $this->session; if (!in_array($name, $this->login_white) && 'all' != $this->login_white) { if (!$session) { throw new Exception('还未登录', API_CODE_LOGOUT); } $user = $this->u_entity->get(array('id' => $session['uid'])); if (!$user || -1 == $user['status']) { $this->logout($this->ukey); debug_log("[error]# user is delete, sql=" . $this->u_entity->last_query(), __FUNCTION__, $this->log_dir); throw new Exception('登录超时', API_CODE_LOGOUT); } // 校验用户状态 if (in_array($name, $this->check_status) || 'all' == $this->check_status) { if (self::STATUS_NOR != $session['status']) { throw new Exception('用户被禁用', API_CODE_FORB); } } //是否绑定手机号 if (in_array($name, $this->check_mobile) || 'all' == $this->check_mobile) { if (!$session['mobile'] || !mobile_valid($session['mobile'])) { throw new Exception('请绑定正确的手机号', API_CODE_FORB); } } // 校验用户头像 if (in_array($name, $this->check_headimg) || 'all' == $this->check_headimg) { if (!$session['headimg']) { throw new Exception('获取头像信息失败', API_CODE_FORB); } } } //超级管理员登录其他用户操作权限控制 /* not limit again edit by xxb 20200529 */ /*if($session['is_majia']){ if(!in_array($name, $this->majia_white) && 'all' != $this->majia_white){ throw new Exception('无权限', API_CODE_FORB); } }*/ return $this->$method(); } /** * 刷新登录有效时间 * @param $data * @return string */ protected function refresh_login($data) { $redis = $this->app_redis; $ukey = md5("{$data['uid']}_{$data['session_key']}"); $redis->save($this->redis_login . $ukey, json_encode($data, JSON_UNESCAPED_UNICODE), 30 * 24 * 3600); $this->ukey = $ukey; return $ukey; } /** * 删除登录记录 * @param $ukey */ protected function logout($ukey = '') { !$ukey && $ukey = $this->input_param('ukey'); if ($ukey) { $redis = $this->app_redis; $redis->delete($this->redis_login . $ukey); } } /** * 校验用户是否黑名单 * @return bool */ protected function is_black() { $mobile = $this->session['mobile']; if (!$mobile) { return false; } return $this->u_entity->is_black($mobile); } /** * * @return array|mixed */ private function fetch_session() { $ukey = $this->input_param('ukey'); $this->ukey = $ukey; if (!$ukey) { return array(); } $redis = $this->app_redis; //data:{"uid":"用户ID", "session_key":"微信session_key"} $data = json_decode($redis->get($this->redis_login . $ukey), true); if ($data) { $session = $data; $source_uid = $uid = $session['uid']; $user = $this->u_entity->get(array('id' => $uid)); if ($user) { //判断是否超级管理员批马甲 $json = $user['jsondata'] ? json_decode($user['jsondata'], true) : array(); if ($json['majia']) {//披上马甲 $muid = $json['majia']['uid']; $row = $this->u_entity->get(array('id' => $muid)); if ($row) { $uid = $muid; $session['is_majia'] = 1; $session['source_uid'] = $source_uid; $session['uid'] = $uid; $user = $row; } } // 角色切换处理 if ($session['group_id_type']) { $user['group_id'] = $user['group_id1']; $user['biz_id'] = $user['biz_id1']; $user['city_id'] = $user['city_id1']; } //设置默认城市,取biz_id对应城市 if (strlen($user['biz_id']) > strlen(str_replace(',', '', $user['biz_id']))) { $this->load->model("biz/biz_model"); $biz = $this->biz_model->get(['id' => intval($user['biz_id']), 'status' => 1], 'city_id'); $user['city_id'] = $biz && $biz['city_id'] ? $biz['city_id'] : 0; } } if ($user) { $session = array_merge($session, $user); $this->session = $session; //更新登录有效时间 $this->refresh_login($data); } else { $this->logout($ukey); } } $this->myuid = $this->session['uid']; return $this->session; } /** * 设置 * @param array $arr * @param int $type "-1删除 0重置 1新增" * @return mixed */ protected function set_session($arr = array(), $type = 0) { $redis = $this->app_redis; $ukey = $this->ukey; $data = json_decode($redis->get($this->redis_login . $ukey), true); if (-1 == $type) {//删除 foreach ($arr as $k) { unset($data[$k]); } } elseif (0 == $type) {//重置 $data = $arr; } elseif (1 == $type) {//新增 foreach ($arr as $k => $v) { $data[$k] = $v; } } $redis->save($this->redis_login . $ukey, json_encode($data, JSON_UNESCAPED_UNICODE), 30 * 24 * 3600); $this->ukey = $ukey; return $ukey; } /** * 小程序开关 * @param string $key (name, logo, biz_cate) * @return mixed */ protected function app_config($key = '') { $this->load->model('app/app_model'); $this->load->model("app/appusual/app_config_model"); if ($this->app) { $app = $this->app; } else { $where = array('id' => $this->app_id); $app = $this->app_model->get($where); $json = $app['jsondata'] ? json_decode($app['jsondata'], true) : array(); $where = array('app_id' => $this->app_id); $select = "k,v"; $map_config = $this->app_config_model->map('k', 'v', $where, '', 0, 0, $select); if ($map_config) { foreach ($map_config as $k => $v) { $v && $json[$k] = json_decode($v, true); } } $app['json'] = $json; $this->app = $app; } if (!$key) { return $app; } elseif ($app[$key]) { return $app[$key]; } else { $json = $app['json']; return $json[$key]; } } /** * 获取app的配置 * @param $app_key * @param $app_id * @return null */ protected function get_config($app_key = '', $app_id = '') { $this->config->load('app', true, true); $configs = $this->config->item('app'); if ($app_key) { return $configs[$app_key]; } elseif ($app_id) { foreach ($configs as $k => $v) { if ($app_id == $v['app_id']) { return $v; } } } return null; } /** * @return string */ protected function cityid() { if (!$this->city_id) { $city_id = $this->app_config('city_id'); !$city_id && $city_id = '350200'; $this->city_id = $city_id; } return $this->city_id; } /** * 获取用户当前访问的城市ID * @return mixed */ protected function ucityid() { $json = $this->session['jsondata']; !is_array($json) && $json = json_decode($json, true); return $json['city_id']; } /** * 用户访问城市配置 * @param string $k * @param string $cityid 取默认城市id * @return array */ protected function config_ucity($k = '', $cityid = '') { if ($cityid) { $city_id = $this->cityid(); } else { $city_id = $this->ucityid(); } $citys = $this->app_config("citys"); $config_city = $citys[$city_id]; 1 == $config_city && $config_city = array(); return $k ? $config_city[$k] : $config_city; } protected function get_pager() { $size = $this->input_param('size'); $page = $this->input_param('page'); $page = $page ? $page : '1'; $size = $size ? $size : '10'; return array('page' => $page, 'size' => $size); } /** * 解析获取微信 * @param $code * @return mixed|string */ protected function wx_session($code) { $appid = $this->wx_config['appid']; $secret = $this->wx_config['secret']; $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appid}&secret={$secret}&js_code={$code}&grant_type=authorization_code"; debug_log("[info] " . __FUNCTION__ . "微信授权:\n{$url}", $this->log_file); // $ch = curl_init($url); // curl_setopt($ch, CURLOPT_RETURNTRANSFER,true); // //关闭https验证 // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // $res = curl_exec($ch); $res = file_get_contents($url); //存日志 debug_log("[info] " . __FUNCTION__ . "res={$res}", $this->log_file); $ret = json_decode($res, true); // { // "session_key": "会话密钥", // "openid": "用户唯一标识", // "unionid": "用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明。", // "errcode": "错误码", // "errmsg": "错误信息" // } if (!$ret['session_key']) { debug_log("[fail] " . __FUNCTION__ . ": session_key is null", $this->log_file); } return $ret; } /** * 解析微信数据 * @param $encrypted * @param $iv * @return array|mixed|string */ protected function wx_data($encrypted, $iv) { require_once COMMPATH . "third_party/WeChat/wxBizDataCrypt.php"; $pc = new WXBizDataCrypt($this->wx_config['appid'], $this->session['session_key']); $wx_data = ''; $errCode = $pc->decryptData($encrypted, $iv, $wx_data); debug_log("[info] " . __FUNCTION__ . ":code={$errCode}; wxdata:{$wx_data}", $this->log_file); if ($errCode == 0) { $wx_data = json_decode($wx_data, true); return $wx_data; } debug_log("[warning] " . __FUNCTION__ . ":appid=" . $this->wx_config['appid'] . "; session_key=" . $this->session['session_key'] . "; encrypted={$encrypted}; iv={$iv}; wxdata:{$wx_data}", $this->log_file); return array(); } /** * 输入参数处理 * @param $inputs * @return array */ private function set_input($inputs) { if (!$inputs) { return array(); } foreach ($inputs as $k => $v) { if ('undefined' === $v) {//前端空参数过滤 $inputs[$k] = ''; } } $this->inputs = $inputs; return $this->inputs; } //获取当前门店id protected function get_biz_id() { return $this->session['new_biz_id'] ? $this->session['new_biz_id'] : intval($this->session['biz_id']); } }