123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851 |
- <?php
- namespace Question\Src;
- use Dever;
- class Api
- {
- private $hidden = true;
- private $exam = array();
- private $question = array();
- private $user = array();
- private $redis;
- private $rank = DEVER_PROJECT . '_score';
- /**
- * 获取某个答题规则的数据接口 api.get?id=1
- *
- * @return mixed
- */
- public function get()
- {
- $result = array();
- $id = Dever::input('id');
- if ($id <= 0 || !$id) {
- Dever::alert('规则不存在');
- }
- $this->exam = Dever::db('question/exam')->one($id);
- if (!$this->exam) {
- Dever::alert('规则不存在');
- }
- $question = array();
- if ($this->exam['type'] == 1) {
- # 首次抽取题目,题目保存在user表中,user表保存答题进度
- $question = $this->getQuestion($this->exam['cate_id'], $this->exam['num']);
- } elseif ($this->exam['type'] == 3) {
- # 固定id得到题目,题目保存在user表中,user表保存答题进度
- $question = $this->getQuestion($this->exam['cate_id'], 0, $this->exam['info_ids']);
- }
- $this->initUser($question);
- $result['exam'] = $this->exam;
- $result['user'] = $this->user;
- $yes = Dever::input('yes', 1);
- # 未完成,并且设置了yes==1,则立即开始答题
- if ($yes == 1 && $this->user && $this->user['status'] < 3) {
- $result['question'] = $this->getQuestionInfo();
- }
- $result['exam']['continue_num'] = $this->getOverContinueNum();
- unset($result['exam']['level_ids']);
- return $result;
- }
- private function getOverContinueNum()
- {
- $continue = $this->getContinueNum();
- if ($continue['id'] > 0) {
- $this->exam['continue_num'] = $this->exam['continue_num'] - $continue['num'];
- }
- return $this->exam['continue_num'];
- }
- /**
- * 获取用户信息接口 api.getUserInfo?uid=1
- *
- * @return mixed
- */
- public function getUserInfo()
- {
- $this->getUser(true);
- if ($this->user['uid'] > 0) {
- $info = Dever::db('question/ranking')->one(array('uid' => $this->user['uid']));
- $this->user['ranking_score'] = $this->user['score'];
- if ($info) {
- $this->user['ranking_score'] = $info['score'];
- }
- $this->result();
-
- $result['user'] = $this->user;
-
- $where['score'] = $this->user['score'];
- $result['total'] = Dever::db('question/ranking')->getTotal($where);
- } else {
- $this->user['ranking_score'] = $this->user['score'];
- $result['user'] = $this->user;
- $result['total'] = 0;
- }
- $result['exam'] = $this->exam;
- return $result;
- }
- /**
- * 排行榜接口
- *
- * @return mixed
- */
- public function ranking()
- {
- $uid = Dever::input('uid');
- $this->redis();
- $result = array();
- if ($this->redis) {
- $ranking = $this->redis->zRevRange($this->rank, 0, 7, true);
-
- $rank = -1;
- $data = array();
- if ($ranking) {
- $i = 0;
- foreach ($ranking as $k => $v) {
- if ($k) {
- $data[$i] = Dever::db('passport/user')->one($k);
- $data[$i]['score'] = $v;
- $data[$i]['rank'] = $i;
- # 这个用户是不是自己
- $data[$i]['my'] = 2;
- if ($k == $uid) {
- $data[$i]['my'] = 1;
- $rank = $i;
- }
- $i++;
- }
- }
- }
- $result['list'] = $data;
- if ($uid) {
- if ($rank < 0) {
- # 获取当前用户的排名
- $rank = $this->redis->zRevRank($this->rank, $uid);
- }
- $user = Dever::db('passport/user')->one($uid);
- $ranking = Dever::db('question/ranking')->one(array('option_uid' => $uid));
- $user['score'] = $ranking['score'];
- $result['user'] = $user;
- $result['user']['rank'] = $rank;
- }
- }
- return $result;
- }
- /**
- * 定时更新所有排行榜数据接口 可以将这个放到cron中,定时执行 question/api.upRanking
- *
- * @return mixed
- */
- public function upRanking()
- {
- $this->redis();
- if ($this->redis) {
- $data = Dever::db('question/ranking')->state();
-
- if ($data) {
- foreach ($data as $k => $v) {
- $this->redis->zAdd($this->rank, $v['score'], $v['uid']);
- }
- }
- }
- return true;
- }
- /**
- * 从某个活动中抽取题目并保存下来
- * $category 分类id
- * $num 取多少题
- * $ids 题目id
- * $index 当前是第几题
- * $level_ids 难度数量
- *
- * @return mixed
- */
- private function getQuestion($category, $num, $ids = false, $index = 0, $level_ids = false)
- {
- $where = array();
- $where['cate_id'] = $category;
- if ($ids) {
- $where['ids'] = $ids;
- }
- if ($level_ids) {
- $where['level_id'] = $this->getLevel($level_ids, $index);
- }
- $question_id = Dever::input('question_id');
- $data = Dever::db('question/info')->getAll($where);
- if ($question_id > 0) {
- if (isset($data[$question_id])) {
- return array($data[$question_id]);
- } else {
- Dever::alert('错误的题目信息');
- }
- }
- $result = array();
- if ($data && $num) {
- $result = $this->getQuestionOne($question_id, $data, $num);
- }
- return $result;
- }
- private function getQuestionOne($question_id, $data, $num)
- {
- $one['user_id'] = $this->user['id'];
- $one['uid'] = Dever::input('uid');
- if (!$question_id && $num == 1) {
- $answer = Dever::db('question/user_answer')->getAll($one);
- # 去除已经答过的题
- if ($answer) {
- $data = array_diff_key($data, $answer);
- }
- }
- $count = count($data);
- if ($num > $count) {
- $num = $count;
- }
- $result = array();
- $keys = array_rand($data, $num);
- if (is_array($keys)) {
- foreach ($keys as $k => $v) {
- $result[$v] = $data[$v];
- }
- } else {
- $result[0] = $data[$keys];
- }
- return $result;
- }
- /**
- * 获取等级id
- *
- * @return mixed
- */
- private function getLevel($level_ids, $index)
- {
- # 如果有难度 比较自由的模式 1,3 换行 2,3
- $level = explode("\r\n", $level_ids);
- $level_data = Dever::db('question/level')->all();
- $index = $index + 1;
- $level_info = array();
- $i = 1;
- foreach ($level as $v) {
- $v = explode(',', $v);
- $start = $i;
- $end = $v[1];
- $i = $end + $i;
- $end = $start + $end - 1;
- if ($index >= $start && $index <= $end) {
- if (isset($level_data[$v[0]])) {
- $level_info = $level_data[$v[0]];
- }
-
- break;
- }
- }
- /*
- 3,3,4形式,已废弃
- $level = explode(',', $level_ids);
- $level_data = Dever::db('question/level')->getAll();
- $index = $index + 1;
- $level_info = array();
- $i = 1;
- foreach ($level as $k => $v) {
- $start = $i;
- $end = $v;
- $i = $end + $i;
- $end = $start + $end - 1;
- if ($index >= $start && $index <= $end) {
- if (isset($level_data[$k])) {
- $level_info = $level_data[$k];
- }
-
- break;
- }
- }
- */
- if (isset($level_info)) {
- return $level_info['id'];
- } else {
- Dever::alert('难度获取失败');
- }
- }
- /**
- * 初始化用户信息
- *
- * @return mixed
- */
- private function initUser($question = array())
- {
- if (!$this->exam) {
- Dever::alert('规则不存在');
- }
- $uid = $this->getUid();
- # 获取当前最新的一条已完成记录
- if ($this->exam['continue'] == 1) {
- # 答错可以继续答题 则答完所有题才算完成
- $where['where_status'] = 4;
- } elseif ($this->exam['continue'] >= 2) {
- # 答错不可以继续答题 则错误也算完成
- $where['where_status'] = 3;
- }
- $where['where_uid'] = $uid;
- $where['where_exam_id'] = $this->exam['id'];
- # 获取已完成记录
- $finish = Dever::db('question/user')->getFinish($where);
- if ($this->exam['continue'] == 3 && $finish && $finish['status'] == 3) {
- # 最新一次如果是错误的,则停止继续
- $this->user = $finish;
- return;
- }
- # 获取正在进行中的记录
- $this->user = Dever::db('question/user')->getUnFinish($where);
- $times = 1;
- if($finish) {
- if ($this->user && $finish['times'] >= $this->user['times']) {
- $update['where_id'] = $this->user['id'];
- $update['status'] = 3;
- Dever::db('question/user')->update($update);
- return $this->initUser($question);
- }
- $times = $finish['times'] + 1;
- }
- if (!$this->user) {
- $insert = array();
- $insert['num'] = $this->exam['num'];
- if ($question) {
- $question = array_keys($question);
- $insert['num'] = count($question);
- $insert['info_ids'] = implode(',', $question);
- }
- $insert['uid'] = $uid;
- $insert['exam_id'] = $this->exam['id'];
- $insert['index'] = 0;
- $insert['score'] = 0;
- $insert['status'] = 1;
- # 检查答题次数 第一次
- $insert['times'] = $times;
- $id = Dever::db('question/user')->insert($insert);
- $this->user = Dever::db('question/user')->one($id);
- } else {
- $id = $this->user['id'];
- }
- # 获取规则
- $this->result();
- }
- private function result()
- {
- if ($this->user['status'] >= 3) {
- $this->exam['content'] = Dever::array_decode($this->exam['content']);
- $this->exam['result'] = array();
- foreach ($this->exam['content'] as $k => $v) {
- if (strstr($v['score'], '~')) {
- $temp = explode('~', $v['score']);
- if ($this->user['score'] >= $temp[0] && $this->user['score'] <= $temp[1]) {
- unset($v['score']);
- $this->exam['result'] = $v;
- break;
- }
- } else {
- if ($this->user['score'] == $v['score']) {
- unset($v['score']);
- $this->exam['result'] = $v;
- break;
- }
- }
- }
- if (isset($this->exam['result']['info']) && $this->exam['result']['info']) {
- $this->exam['result']['info_text'] = strip_tags($this->exam['result']['info']);
- }
- if (isset($this->exam['result']['pic']) && $this->exam['result']['pic']) {
- $this->exam['result']['pic_https'] = str_replace('http://' , 'https://', $this->exam['result']['pic']);
- }
- unset($this->exam['content']);
- } else {
- unset($this->exam['content']);
- }
- }
- /**
- * 获取用户id
- *
- * @return mixed
- */
- private function getUid()
- {
- $id = Dever::input('uid');
- if (!$id) {
- $save = new \Dever\Session\Oper(DEVER_PROJECT, 'cookie');
- $id = $save->get('uid');
- if (!$id) {
- $id = Dever::id();
- $save->add('uid', $id);
- }
- }
-
- return $id;
- }
- /**
- * 获取题目接口:api.getInfo?user_data_id=1&uid=1
- *
- * @return mixed
- */
- public function getInfo()
- {
- $this->getUser();
- return $this->getQuestionInfo();
- }
- /**
- * 获取最新一条用户参与信息
- *
- * @return mixed
- */
- private function getUser($state = false)
- {
- $uid = $this->getUid();
- //$id = Dever::input('user_data_id');
- $this->user = Dever::db('question/user')->get(array('where_uid' => $uid));
- if (!$this->user) {
- if ($state == false) {
- Dever::alert('错误的用户信息');
- } else {
- $this->user['id'] = -1;
- $this->user['uid'] = -1;
- $this->user['score'] = 0;
- }
- }
- $this->exam = Dever::db('question/exam')->one($this->user['exam_id']);
- }
- /**
- * 获取题目
- *
- * @return mixed
- */
- private function getQuestionInfo()
- {
- if ($this->user && $this->exam) {
- # 验证是否答完
- if ($this->user['status'] == 4) {
- Dever::alert('已经答完所有题目');
- }
- # 验证是否答错
- if ($this->exam['continue'] >= 2 && $this->user['status'] == 3) {
- Dever::alert('不能继续答题');
- }
- # 进行中
- Dever::db('question/user')->update(array('where_id' => $this->user['id'], 'status' => 2));
- if ($this->exam['type'] == 1 && $this->user['info_ids']) {
- $question = explode(",", $this->user['info_ids']);
- } elseif ($this->exam['type'] == 2) {
- # 随机抽取
- $data = $this->getQuestion($this->exam['cate_id'], 1, false, $this->user['index']);
- $question[$this->user['index']] = $data[0];
- } elseif ($this->exam['type'] == 3 && $this->exam['info_ids']) {
- # 固定的
- $question = explode("\r\n", $this->exam['info_ids']);
- } elseif ($this->exam['type'] == 4) {
- # 随机抽取并且按照难度抽取
- $data = $this->getQuestion($this->exam['cate_id'], 1, false, $this->user['index'], $this->exam['level_ids']);
- $question[$this->user['index']] = $data[0];
- } else {
- Dever::alert('错误的题目类型');
- }
- }
- if (isset($question[$this->user['index']])) {
- $data = $question[$this->user['index']];
- if (!is_array($data)) {
- $data = Dever::db('question/info')->one($data);
- }
- $data['index'] = $this->user['index'];
- $data['num'] = $this->user['num'];
- $data['content'] = Dever::array_decode($data['content']);
- if ($this->hidden == true) {
- foreach ($data['content'] as $k => $v) {
- unset($data['content'][$k]['score']);
- }
- } else {
- //$data['user_info_ids'] = $this->user['user_info_ids'];
- $data['score'] = $this->user['score'];
- $data['total'] = $this->exam['num'];
- }
- $data['user_data_id'] = $this->user['id'];
-
- return $data;
- }
- Dever::alert('错误的题目信息');
- }
- /**
- * 开始答题接口: api.submit?question_id=1&option=0&uid=1
- * 返回参数:status 2为进行中 3答题错误 4答题正确
- *
- * @return mixed
- */
- public function submit()
- {
- $this->getUser();
- $question_id = Dever::input('question_id');
- if (!$question_id) {
- Dever::alert('错误的题目信息');
- }
- $option = Dever::input('option', 0);
- $one['user_id'] = $this->user['id'];
- $one['uid'] = Dever::input('uid');
- $one['info_id'] = Dever::input('question_id');
- $one = Dever::db('question/user_answer')->one($one);
- if ($one) {
- $update['status'] = $this->user['status'];
- } else {
- /*
- if ($this->exam['continue'] >= 2 && $this->exam['continue_times'] > 0) {
- $cur = time();
- # 后端超时设置
- $times = $this->exam['continue_times'];
- if ($cur - $this->user['cdate'] > $times) {
- # 超时
- $option = -1;
- }
- }
- */
- $this->hidden = false;
- $data = $this->getQuestionInfo();
-
- if ($option == -1) {
- # 超时
- $data['content'][$option] = array();
- $data['content'][$option]['score'] = 0;
- $data['content'][$option]['title'] = '超时';
- }
- if (!isset($data['content'][$option])) {
- Dever::alert('错误的选项信息');
- }
- /*
- $update['user_info_ids'] = $data['user_info_ids'];
- if ($update['user_info_ids']) {
- $update['user_info_ids'] = explode(',', $update['user_info_ids']);
- $update['user_info_ids'][] = $data['id'];
- $update['user_info_ids'] = implode(',', $update['user_info_ids']);
- } else {
- $update['user_info_ids'] = $data['id'];
- }
- */
- $update['score'] = $data['score'] + $data['content'][$option]['score'];
- $update['where_id'] = $data['user_data_id'];
- $update['status'] = 2;
- if ($this->exam['continue'] >= 2 && $data['content'][$option]['score'] == 0) {
- # 答题错误 进度不变
- $update['status'] = 3;
- # 将当前分数同步到排行榜中去
- $this->setRanking($update['score']);
- # 答题完成后,进度变化
- if ($this->exam['continue_index'] == 2) {
- $update['index'] = $data['index'] + 1;
- } else {
- $update['index'] = $data['index'];
- }
- } else {
- $update['index'] = $data['index'] + 1;
- }
- if ($update['index'] >= $data['num'] && $update['status'] == 2) {
- # 答题完成
- $update['status'] = 4;
- # 将当前分数同步到排行榜中去
- $this->setRanking($update['score']);
- }
-
- Dever::db('question/user')->update($update);
- if ($update['index'] > $data['index']) {
- $insert['user_id'] = $data['user_data_id'];
- $insert['info_id'] = $data['id'];
- $insert['score'] = $data['content'][$option]['score'];
- $insert['option'] = $option;
- $insert['uid'] = $this->user['uid'];
- $insert['option_name'] = $data['content'][$option]['title'];
- Dever::db('question/user_answer')->insert($insert);
- }
- }
- $result = array();
- $result['status'] = $update['status'];
- $result['question_id'] = $question_id;
- $result['option'] = $option;
- $result['continue_num'] = $this->getOverContinueNum();
- return $result;
- }
- /**
- * 积分榜单
- *
- * @return mixed
- */
- private function setRanking($score)
- {
- $ranking = Dever::db('question/ranking')->one(array
- (
- 'uid' => $this->user['uid'],
- 'exam_id' => $this->user['exam_id'],
- ));
- $state = false;
- if ($ranking) {
- if ($ranking['score'] < $score) {
- $state = true;
- $update['uid'] = $this->user['uid'];
- $update['exam_id'] = $this->user['exam_id'];
- $update['score'] = $score;
- $update['times'] = $this->user['times'];
- $update['where_id'] = $ranking['id'];
- Dever::db('question/ranking')->update($update);
- }
-
- } else {
- $state = true;
- $insert['uid'] = $this->user['uid'];
- $insert['exam_id'] = $this->user['exam_id'];
- $insert['score'] = $score;
- $insert['times'] = $this->user['times'];
- Dever::db('question/ranking')->insert($insert);
- }
- if ($state == true) {
- $this->redis();
- if ($this->redis) {
- $this->redis->zAdd($this->rank, $score, $this->user['uid']);
- }
- }
- }
- /**
- * 复活接口 把当前的status状态值为2即可
- *
- * @return mixed
- */
- public function go_continue()
- {
- $this->getUser();
- # 先验证当前的状态是否是3
- if ($this->user['status'] == 3) {
-
- $this->checkContinue();
- $update['where_id'] = $this->user['id'];
- if ($this->user['index'] >= $this->user['num']) {
- $update['status'] = 4;
- } else {
- $update['status'] = 2;
- }
- Dever::db('question/user')->update($update);
- }
- return true;
- }
- /**
- * 无限复活接口 慎用
- *
- * @return mixed
- */
- public function go_all_continue()
- {
- $this->getUser();
- # 先验证当前的状态是否是3
- if ($this->user['status'] == 3) {
- $update['where_id'] = $this->user['id'];
- if ($this->user['index'] >= $this->user['num']) {
- $update['status'] = 4;
- } else {
- $update['status'] = 2;
- }
-
- Dever::db('question/user')->update($update);
- }
- return true;
- }
- /**
- * 验证当前的复活次数够不够
- *
- * @return mixed
- */
- private function checkContinue()
- {
- $continue_num = $this->exam['continue_num'];
- if ($continue_num > 0) {
- $continue = $this->getContinueNum();
- if ($continue['id'] > 0) {
- if ($continue['num'] < $continue_num) {
- #可以继续复活
- $update['where_id'] = $continue['id'];
- $update['num'] = $continue['num'] + 1;
- Dever::db('question/continue')->update($update);
- } else {
- Dever::alert('无法复活');
- }
- } else {
- $insert['exam_id'] = $this->user['exam_id'];
- $insert['uid'] = $this->user['uid'];
- $insert['user_id'] = $this->user['id'];
- $insert['num'] = 1;
- Dever::db('question/continue')->insert($insert);
- }
- }
- }
- private function getContinueNum()
- {
- $continue_num_user = $this->exam['continue_num_user'];
-
- $where['exam_id'] = $this->user['exam_id'];
- if ($continue_num_user == 1) {
- $where['uid'] = $this->user['uid'];
- } elseif ($continue_num_user == 2) {
- $where['user_id'] = $this->user['id'];
- }
- $continue = Dever::db('question/continue')->one($where);
- if ($continue) {
- $time = time();
- $continue_num_type = $this->exam['continue_num_type'];
- $continue_num_type_times = $this->exam['continue_num_type_times'];
- # 查看时间间隔
- if ($continue_num_type == 1) {
- # 按照自然天
- $continue_num_type_times = 0;
- $date = Dever::maketime(date('Y-m-d 00:00:00', strtotime("+1 day", $continue['cdate'])));
- if ($time >= $date) {
- $continue['num'] = 0;
- }
- } elseif ($continue_num_type == 2) {
- # 按照小时
- $continue_num_type_times = $continue_num_type_times * 3600;
- } elseif ($continue_num_type == 3) {
- # 按照天
- $continue_num_type_times = $continue_num_type_times * 86400;
- }
- if ($continue_num_type_times > 0 && $time - $continue['cdate'] >= $continue_num_type_times) {
- $continue['num'] = 0;
- }
- } else {
- $continue['id'] = 0;
- $continue['num'] = 0;
- }
- return $continue;
- }
- /**
- * 重新挑战接口,重新开始,当前结束
- *
- * @return mixed
- */
- public function reset()
- {
- $this->getUser();
- $update['where_id'] = $this->user['id'];
- $update['status'] = 4;
- Dever::db('question/user')->update($update);
- return true;
- }
- /**
- * 初始化redis
- *
- * @return mixed
- */
- private function redis()
- {
- $this->redis = false;
- if ($this->redis) {
- return $this->redis;
- }
- $config = Dever::config('database')->redis;
- if ($config) {
- if (class_exists('\\Redis')) {
- $this->redis = new \Redis;
- $this->redis->connect($config['host'], $config['port']);
- }
- }
- return $this->redis;
- }
- }
|