PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/mods/_standard/tests/take_test_q.php

https://github.com/harriswong/ATutor
PHP | 282 lines | 187 code | 51 blank | 44 comment | 58 complexity | 2a9db9520d4a865e4a3d33490b3aa495 MD5 | raw file
  1. <?php
  2. /****************************************************************/
  3. /* ATutor */
  4. /****************************************************************/
  5. /* Copyright (c) 2002-2010 */
  6. /* Inclusive Design Institute */
  7. /* http://atutor.ca */
  8. /* */
  9. /* This program is free software. You can redistribute it and/or*/
  10. /* modify it under the terms of the GNU General Public License */
  11. /* as published by the Free Software Foundation. */
  12. /****************************************************************/
  13. // $Id$
  14. define('AT_INCLUDE_PATH', '../../../include/');
  15. require(AT_INCLUDE_PATH.'vitals.inc.php');
  16. require(AT_INCLUDE_PATH.'../mods/_standard/tests/lib/test_result_functions.inc.php');
  17. require(AT_INCLUDE_PATH.'../mods/_standard/tests/classes/testQuestions.class.php');
  18. $tid = intval($_REQUEST['tid']);
  19. if (isset($_REQUEST['cid']))
  20. {
  21. $cid = intval($_REQUEST['cid']);
  22. $cid_url = SEP.'cid='.$cid;
  23. }
  24. if (isset($_REQUEST['gid']))
  25. $mid = $addslashes($_REQUEST['gid']);
  26. else
  27. $mid = $_SESSION['member_id'];
  28. //make sure max attempts not reached, and still on going
  29. $sql = "SELECT *, UNIX_TIMESTAMP(start_date) AS start_date, UNIX_TIMESTAMP(end_date) AS end_date FROM ".TABLE_PREFIX."tests WHERE test_id=".$tid." AND course_id=".$_SESSION['course_id'];
  30. $result= mysql_query($sql, $db);
  31. $test_row = mysql_fetch_assoc($result);
  32. /* check to make sure we can access this test: */
  33. if (!$test_row['guests'] && ($_SESSION['enroll'] == AT_ENROLL_NO || $_SESSION['enroll'] == AT_ENROLL_ALUMNUS)) {
  34. require(AT_INCLUDE_PATH.'header.inc.php');
  35. $msg->printInfos('NOT_ENROLLED');
  36. require(AT_INCLUDE_PATH.'footer.inc.php');
  37. exit;
  38. }
  39. if (!$test_row['guests'] && !authenticate_test($tid)) {
  40. header('Location: '.url_rewrite('mods/_standard/tests/my_tests.php', AT_PRETTY_URL_IS_HEADER));
  41. exit;
  42. }
  43. // checks one/all questions per page, and forward user to the correct one
  44. if (!$test_row['display']) {
  45. header('Location: '.url_rewrite('mods/_standard/tests/take_test.php?tid='.$tid.$cid_url, AT_PRETTY_URL_IS_HEADER));
  46. }
  47. $out_of = $test_row['out_of'];
  48. $sql = "SELECT COUNT(*) AS num_questions FROM ".TABLE_PREFIX."tests_questions_assoc WHERE test_id=$tid";
  49. $result = mysql_query($sql, $db);
  50. $row = mysql_fetch_assoc($result);
  51. if (!$test_row['random'] || $test_row['num_questions'] > $row['num_questions']) {
  52. $test_row['num_questions'] = $row['num_questions'];
  53. }
  54. $sql = "SELECT COUNT(*) AS cnt FROM ".TABLE_PREFIX."tests_results WHERE status=1 AND test_id=".$tid." AND member_id='".$mid."'";
  55. $takes_result= mysql_query($sql, $db) or die(mysql_error());
  56. $takes = mysql_fetch_assoc($takes_result);
  57. if ( (($test_row['start_date'] > time()) || ($test_row['end_date'] < time())) ||
  58. ( ($test_row['num_takes'] != AT_TESTS_TAKE_UNLIMITED) && ($takes['cnt'] >= $test_row['num_takes']) ) ) {
  59. require(AT_INCLUDE_PATH.'header.inc.php');
  60. $msg->printInfos('MAX_ATTEMPTS');
  61. require(AT_INCLUDE_PATH.'footer.inc.php');
  62. exit;
  63. }
  64. if (!isset($_GET['pos'])) {
  65. $pos = 0; // first question
  66. } else {
  67. $pos = abs($_GET['pos']);
  68. }
  69. $max_pos = 0;
  70. // get and check for a valid result_id. if there is none then get all the questions and insert them as in progress.
  71. // note: for guests without guest information, the result_id is stored in session, but no need to really know that here;
  72. // for guests with guest information, always start a new test.
  73. if (isset($_REQUEST['gid']))
  74. $result_id = 0;
  75. else
  76. $result_id = get_test_result_id($tid, $max_pos);
  77. // set position to allow users to return to a test they have partially completed, and continue from where they left of.
  78. if (!isset($_GET['pos']) && $result_id > 0)
  79. {
  80. $sql = "SELECT COUNT(*) total_questions FROM ".TABLE_PREFIX."tests_answers WHERE result_id = ". $result_id;
  81. $total_result = mysql_query($sql, $db) or die(mysql_error());
  82. $total = mysql_fetch_assoc($total_result);
  83. $sql = "SELECT COUNT(*) pos FROM ".TABLE_PREFIX."tests_answers WHERE result_id = ". $result_id ." AND answer <> ''";
  84. $answer_result = mysql_query($sql, $db) or die(mysql_error());
  85. $answer = mysql_fetch_assoc($answer_result);
  86. // if user answered all the questions without cliking last "next" button, resume test at the last question
  87. $pos = ($total['total_questions'] == $answer['pos']) ? (--$answer['pos']) : $answer['pos'];
  88. }
  89. if ($result_id == 0) {
  90. // there is no test in progress, yet.
  91. // init this test.
  92. // simple safety op to make sure nothing is being posted (as it shouldn't!)
  93. // $_POST = array(); // don't need this because of the else-if
  94. // basically, shouldn't be able to post to this page if there isn't a valid result_id first (how can someone post an answer
  95. // to a question they haven't viewed? [unless they're trying to 'hack' something])
  96. $result_id = init_test_result_questions($tid, (bool) $test_row['random'], $test_row['num_questions'], $mid);
  97. if (!$_SESSION['member_id']) {
  98. // this is a guest, so we store the result_id in SESSION
  99. $_SESSION['test_result_id'] = $result_id;
  100. }
  101. $pos = 0; // force to always start at the first question
  102. } else if (isset($_POST['next']) || isset($_POST['previous'])) {
  103. // if the test isn't time limited, then what happens when only a few questions are answered? the test result
  104. // will be inconsistant.
  105. // need to keep track of the max(pos) answered, so that we know if a question is being re-answered.
  106. // store 'max_pos' in session or db or form?
  107. // assuming only one question is displayed
  108. $question_id = intval(key($_POST['answers']));
  109. // get the old score (incase this question is being re-answered)
  110. $sql = "SELECT score FROM ".TABLE_PREFIX."tests_answers WHERE result_id=$result_id AND question_id=$question_id";
  111. $result = mysql_query($sql, $db);
  112. $row = mysql_fetch_assoc($result);
  113. $old_score = $row['score'];
  114. $score = 0;
  115. $sql = "SELECT TQA.weight, TQA.question_id, TQ.type, TQ.answer_0, TQ.answer_1, TQ.answer_2, TQ.answer_3, TQ.answer_4, TQ.answer_5, TQ.answer_6, TQ.answer_7, TQ.answer_8, TQ.answer_9 FROM ".TABLE_PREFIX."tests_questions_assoc TQA INNER JOIN ".TABLE_PREFIX."tests_questions TQ USING (question_id) WHERE TQA.test_id=$tid AND TQA.question_id=$question_id";
  116. $result = mysql_query($sql, $db);
  117. if ($row = mysql_fetch_assoc($result)) {
  118. if (isset($_POST['answers'][$row['question_id']])) {
  119. $obj = TestQuestions::getQuestion($row['type']);
  120. $score = $obj->mark($row);
  121. $sql = "UPDATE ".TABLE_PREFIX."tests_answers SET answer='{$_POST[answers][$row[question_id]]}', score='$score' WHERE result_id=$result_id AND question_id=$row[question_id]";
  122. mysql_query($sql, $db);
  123. if (is_null($score) && $test_row['result_release']==AT_RELEASE_MARKED)
  124. $_REQUEST['efs'] = 1; // set final score to empty if there's any unmarked question and release option is "once quiz submitted and all questions are marked"
  125. }
  126. }
  127. $pos++;
  128. if ($_REQUEST['efs']) // set final score to empty if there's any unmarked question and release option is "once quiz submitted and all questions are marked"
  129. {
  130. $sql = "UPDATE ".TABLE_PREFIX."tests_results SET final_score=null, date_taken=date_taken, end_time=NOW(), max_pos=$pos WHERE result_id=$result_id";
  131. $result = mysql_query($sql, $db);
  132. }
  133. // update the final score
  134. // update status to complate to fix refresh test issue.
  135. else if ($pos > $max_pos) {
  136. $sql = "UPDATE ".TABLE_PREFIX."tests_results SET final_score=final_score + $score, date_taken=date_taken, end_time=NOW(), max_pos=$pos WHERE result_id=$result_id";
  137. $result = mysql_query($sql, $db);
  138. } else {
  139. // this question has already been answered, so we have to re-mark it, which means finding the OLD score for this question and adjusting
  140. // $score with the positive or negative difference.
  141. // no need to update max_pos b/c we're only updating a previously answered question.
  142. $score = $old_score - $score;
  143. $sql = "UPDATE ".TABLE_PREFIX."tests_results SET final_score=final_score - $score, date_taken=date_taken, end_time=NOW() WHERE result_id=$result_id";
  144. $result = mysql_query($sql, $db);
  145. }
  146. if (isset($_POST['previous'])) {
  147. $pos-=2;
  148. if ($pos < 0) {
  149. $pos = 0;
  150. }
  151. }
  152. if ($pos >= $test_row['num_questions']) {
  153. // end of the test.
  154. $sql = "UPDATE ".TABLE_PREFIX."tests_results SET status=1, date_taken=date_taken, end_time=NOW() WHERE result_id=$result_id";
  155. $result = mysql_query($sql, $db);
  156. $msg->addFeedback('ACTION_COMPLETED_SUCCESSFULLY');
  157. if ((!$_SESSION['enroll'] && !isset($cid)) || $test_row['result_release']==AT_RELEASE_IMMEDIATE) {
  158. header('Location: '.url_rewrite('mods/_standard/tests/view_results.php?tid='.$tid.SEP.'rid='.$result_id.$cid_url, AT_PRETTY_URL_IS_HEADER));
  159. exit;
  160. }
  161. if (isset($cid)) header('Location: '.url_rewrite('content.php?cid='.$cid, AT_PRETTY_URL_IS_HEADER));
  162. else header('Location: '.url_rewrite('mods/_standard/tests/my_tests.php', AT_PRETTY_URL_IS_HEADER));
  163. exit;
  164. } // else:
  165. header('Location: '.url_rewrite('mods/_standard/tests/take_test_q.php?tid='.$tid.SEP.'pos='.$pos.SEP.'efs='.$_REQUEST['efs'].$cid_url, AT_PRETTY_URL_IS_HEADER));
  166. exit;
  167. }
  168. if (defined('AT_FORCE_GET_FILE') && AT_FORCE_GET_FILE) {
  169. $content_base_href = 'get.php/';
  170. } else {
  171. $course_base_href = 'content/' . $_SESSION['course_id'] . '/';
  172. }
  173. require(AT_INCLUDE_PATH.'header.inc.php');
  174. /* Retrieve the content_id of this test */
  175. $num_questions = $test_row['num_questions'];
  176. $content_id = $test_row['content_id'];
  177. $anonymous = $test_row['anonymous'];
  178. $instructions = $test_row['instructions'];
  179. $title = $test_row['title'];
  180. $_letters = array(_AT('A'), _AT('B'), _AT('C'), _AT('D'), _AT('E'), _AT('F'), _AT('G'), _AT('H'), _AT('I'), _AT('J'));
  181. // this is a kludge to get the question number incremented.
  182. // a diff approach could be to pass the position to the display() method.
  183. for ($i = 0; $i < $pos; $i++) {
  184. TestQuestionCounter(true);
  185. }
  186. // retrieve the test questions that were saved to `tests_answers`
  187. if ($test_row['random']) {
  188. $sql = "SELECT R.*, A.*, Q.* FROM ".TABLE_PREFIX."tests_answers R INNER JOIN ".TABLE_PREFIX."tests_questions_assoc A USING (question_id) INNER JOIN ".TABLE_PREFIX."tests_questions Q USING (question_id) WHERE R.result_id=$result_id AND A.test_id=$tid ORDER BY Q.question_id LIMIT $pos, 1";
  189. } else {
  190. $sql = "SELECT R.*, A.*, Q.* FROM ".TABLE_PREFIX."tests_answers R INNER JOIN ".TABLE_PREFIX."tests_questions_assoc A USING (question_id) INNER JOIN ".TABLE_PREFIX."tests_questions Q USING (question_id) WHERE R.result_id=$result_id AND A.test_id=$tid ORDER BY A.ordering, Q.question_id LIMIT $pos, 1";
  191. }
  192. $result = mysql_query($sql, $db);
  193. $question_row = mysql_fetch_assoc($result);
  194. if (!$result || !$question_row) {
  195. echo '<p>'._AT('no_questions').'</p>';
  196. require(AT_INCLUDE_PATH.'footer.inc.php');
  197. exit;
  198. }
  199. ?>
  200. <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>?pos=<?php echo $pos; ?>">
  201. <input type="hidden" name="tid" value="<?php echo $tid; ?>" />
  202. <?php if (isset($_REQUEST['cid'])) {?> <input type="hidden" name="cid" value="<?php echo $cid; ?>" /> <?php }?>
  203. <div class="input-form" style="width:95%">
  204. <fieldset class="group_form"><legend class="group_form"><?php echo $title ?> (<?php echo _AT('question').' '. ($pos+1).'/'.$test_row['num_questions']; ?>)</legend>
  205. <?php if ($_REQUEST['efs']){?>
  206. <input type="hidden" name="efs" value=<?php echo $_REQUEST['efs']; ?> />
  207. <?php }?>
  208. <?php
  209. // retrieve the answer to re-populate the form (so we can edit our answer)
  210. $sql = "SELECT answer FROM ".TABLE_PREFIX."tests_answers WHERE result_id=$result_id AND question_id=$question_row[question_id]";
  211. $result = mysql_query($sql, $db);
  212. $row = mysql_fetch_assoc($result);
  213. $obj = TestQuestions::getQuestion($question_row['type']);
  214. $obj->display($question_row, $row['answer']);
  215. ?>
  216. <div class="row buttons">
  217. <div style="display:none"><input type="submit" value="<?php echo _AT('next'); ?>" name="next"/></div>
  218. <?php if ($pos > 0): ?>
  219. <input type="submit" name="previous" value="<?php echo _AT('previous'); ?>" />
  220. <?php endif; ?>
  221. <?php if (($pos+1) == $test_row['num_questions']): ?>
  222. <input type="submit" name="next" value="<?php echo _AT('submit'); ?>" accesskey="s" onclick="confirmSubmit(this, '<?php echo $addslashes(_AT("test_confirm_submit")); ?>'); return false;"/>
  223. <?php else: ?>
  224. <input type="submit" name="next" value="<?php echo _AT('next'); ?>" accesskey="s" />
  225. <?php endif; ?>
  226. </div>
  227. </fieldset>
  228. </div>
  229. </form>
  230. <script type="text/javascript" src="<?php echo $_base_href;?>/mods/_standard/tests/lib/take_test.js">
  231. <?php require(AT_INCLUDE_PATH.'footer.inc.php'); ?>