00001 <?php
00002 if(!defined('__PRAGYAN_CMS'))
00003 {
00004 header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
00005 echo "<h1>403 Forbidden<h1><h4>You are not authorized to access the page.</h4>";
00006 echo '<hr/>'.$_SERVER['SERVER_SIGNATURE'];
00007 exit(1);
00008 }
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 define('QUIZ_COMPLETED', 1);
00019 define('QUIZ_SUBMISSIONFAILED', false);
00020 define('QUIZ_SUBMISSIONSUCCESSFUL', true);
00021
00022 define('QUIZ_TIMEOUT_ERRORMSG', 'You have run out of time for this quiz. Your test will be evaluated only for the answers you have submitted previously.');
00023 define('QUIZ_SECTION_TIMEOUT_ERRORMSG', 'You have run out of time for this section. Only the answers that you have submitted previously will be evaluated. You can still view sections for which you have time left from the <a href="./+view">Quiz main page</a>.');
00024
00025 class SimpleQuiz implements IQuiz {
00026 private $quizId;
00027 private $quizRow;
00028
00029 public function __construct($quizId) {
00030 $this->quizId = $quizId;
00031 $this->quizRow = getQuizRow($quizId);
00032 }
00033
00034 public function getPropertiesForm($dataSource) {
00035 return 'No quiz specific properties.';
00036 }
00037
00038 public function submitPropertiesForm() {
00039 return true;
00040 }
00041
00042 private function getSectionStartForm($sectionId) {
00043 return <<<SECTIONSTARTFORM
00044 <form name="sectionstartform" method="POST" action="./+view" style="padding:0;margin:0;display:inline">
00045 <input type="hidden" name="hdnSectionId" id="hdnSectionId" value="$sectionId" />
00046 <input type="submit" name="btnStartSection" id="btnStartSection" value="Start" />
00047 </form>
00048 SECTIONSTARTFORM;
00049 }
00050
00051 public function getFrontPage($userId) {
00052 $frontPage = "<h2>{$this->quizRow['quiz_title']}</h2>\n";
00053 $frontPage .= "<div class=\"quiz_headertext\">{$this->quizRow['quiz_headertext']}</div><br /><br />\n";
00054 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00055 $sectionList = getSectionList($this->quizId);
00056 for ($i = 0; $i < count($sectionList); ++$i) {
00057 $frontPage .= '<strong>' . $sectionList[$i]['quiz_sectiontitle'] . '</strong> ';
00058 $attemptRow = getAttemptRow($this->quizId, $sectionList[$i]['quiz_sectionid'], $userId);
00059 if (!$attemptRow || is_null($attemptRow['quiz_attemptstarttime'])) {
00060
00061 $frontPage .= $this->getSectionStartForm($sectionList[$i]['quiz_sectionid']);
00062 }
00063 elseif (is_null($attemptRow['quiz_submissiontime'])) {
00064
00065 $frontPage .= ' <a href="./+view§ionid=' . $sectionList[$i]['quiz_sectionid'] . '">Go to questions</a>';
00066 }
00067 else {
00068
00069 $frontPage .= " Section Completed.";
00070 }
00071 $frontPage .= '<br /><br />';
00072 }
00073 }
00074 else {
00075 $frontPage .= <<<QUIZSTARTFORM
00076 <form name="quizstartform" method="POST" action="./+view" style="padding:0;margin:0;display:inline">
00077 <input type="submit" name="btnStartQuiz" id="btnStartQuiz" value="Start" />
00078 </form>
00079 QUIZSTARTFORM;
00080 }
00081
00082 return $frontPage;
00083 }
00084
00091 public function getQuizPage($userId) {
00092 if ($this->checkQuizCompleted($userId)) {
00093 displayinfo('You seem to have completed this quiz already. You can only take this quiz once.');
00094 return '';
00095 }
00096
00097 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00098
00099 if (isset($_POST['btnStartSection']) && $this->isValidId($_POST['hdnSectionId']) && sectionBelongsToQuiz($this->quizId, $_POST['hdnSectionId']))
00100 $sectionId = intval($_POST['hdnSectionId']);
00101 elseif (isset($_GET['sectionid']) && $this->isValidId($_GET['sectionid']))
00102 $sectionId = intval($_GET['sectionid']);
00103
00104 if (!isset($sectionId))
00105 return $this->getFrontPage($userId);
00106
00107 $attemptRow = getAttemptRow($this->quizId, $sectionId, $userId);
00108 $sectionStarted = $attemptRow ? true : false;
00109 $sectionCompleted = !is_null($attemptRow['quiz_submissiontime']);
00110
00111 if (!$sectionStarted) {
00112 if (!isset($_POST['btnStartSection'])) {
00113 displayerror('Error. You have not started this section yet. Please go to the quiz main page, and click on the Start Section button to view this section.');
00114 return '';
00115 }
00116 if (!startSection($this->quizId, $sectionId, $userId))
00117 return '';
00118 }
00119 elseif ($sectionCompleted) {
00120 displayinfo("You have completed this section.");
00121 return '';
00122 }
00123
00124 if (isset($_POST['btnSubmit'])) {
00125 if ($this->submitQuizPage($userId) === true) {
00126 if ($this->markSectionCompleted($userId, $sectionId)) {
00127
00128 if ($this->checkQuizCompleted($userId)) {
00129 return $this->quizRow['quiz_submittext'];
00130 }
00131 else {
00132 displayinfo('You have completed this section. You can move to another section.');
00133 return $this->getFrontPage($userId);
00134 }
00135 }
00136 else
00137 displayinfo('Your previous page was submitted successfully.');
00138 }
00139 }
00140
00141
00142 if ($this->checkUserTimedOut($userId)) {
00143 displayerror(QUIZ_TIMEOUT_ERRORMSG);
00144 $this->forceQuizCompleted($userId);
00145 return '';
00146 }
00147 elseif ($this->checkUserTimedOut($userId, $sectionId)) {
00148 displayerror(QUIZ_SECTION_TIMEOUT_ERRORMSG);
00149 $this->forceQuizCompleted($userId, $sectionId);
00150 return '';
00151 }
00152
00153 return $this->formatNextPage($userId, $sectionId);
00154 }
00155 else {
00156
00157
00158
00159
00160
00161 $minSectionId = getFirstSectionId($this->quizId);
00162 $attemptRow = getAttemptRow($this->quizId, $minSectionId, $userId);
00163
00164 if (!$attemptRow) {
00165 if (!isset($_POST['btnStartQuiz']))
00166 return $this->getFrontPage($userId);
00167
00168
00169
00170 $attemptQuery = "INSERT INTO `quiz_userattempts`(`page_modulecomponentid`, `quiz_sectionid`, `user_id`, `quiz_attemptstarttime`) " .
00171 "SELECT {$this->quizId}, `quiz_sectionid`, $userId, NOW() FROM `quiz_sections` WHERE `page_modulecomponentid` = {$this->quizId}";
00172 if (!mysql_query($attemptQuery)) {
00173 displayerror('Database Error. Could not update quiz information.');
00174 return '';
00175 }
00176 }
00177
00178 if (isset($_POST['btnSubmit'])) {
00179 if ($this->submitQuizPage($userId) == true) {
00180 if ($this->markSectionCompleted($userId, -1)) {
00181 if ($this->checkQuizCompleted($userId))
00182 return $this->quizRow['quiz_submittext'];
00183 }
00184 else
00185 displayinfo('Your previous page was submitted successfully.');
00186 }
00187 }
00188
00189
00190 if ($this->checkUserTimedOut($userId)) {
00191 displayerror(QUIZ_TIMEOUT_ERRORMSG);
00192 $this->forceQuizCompleted($userId);
00193 return '';
00194 }
00195
00196 return $this->formatNextPage($userId);
00197 }
00198 }
00199
00205 public function submitQuizPage($userId) {
00206
00207
00208 $questionQuery = "SELECT `quiz_questions`.`quiz_sectionid` AS `quiz_sectionid`, " .
00209 "`quiz_questions`.`quiz_questionid` AS `quiz_questionid`, " .
00210 "`quiz_questions`.`quiz_questiontype` AS `quiz_questiontype`, " .
00211 "`quiz_questions`.`quiz_answermaxlength` AS `quiz_answermaxlength` " .
00212 "FROM `quiz_answersubmissions`, `quiz_questions` WHERE " .
00213 "`quiz_questions`.`page_modulecomponentid` = `quiz_answersubmissions`.`page_modulecomponentid` AND " .
00214 "`quiz_questions`.`quiz_sectionid` = `quiz_answersubmissions`.`quiz_sectionid` AND " .
00215 "`quiz_questions`.`quiz_questionid` = `quiz_answersubmissions`.`quiz_questionid` AND " .
00216 "`quiz_questions`.`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND " .
00217 "`quiz_questionviewtime` IS NOT NULL AND `quiz_answersubmittime` IS NULL ";
00218 if($this->quizRow['quiz_allowsectionrandomaccess'] == 1)
00219 $questionQuery .= "AND `quiz_answersubmissions`.`quiz_sectionid` = {$_GET['sectionid']} ";
00220 $questionQuery .= "ORDER BY `quiz_answersubmissions`.`quiz_questionrank` LIMIT {$this->quizRow['quiz_questionsperpage']}";
00221 $questionResult = mysql_query($questionQuery);
00222 if (!$questionResult) {
00223 displayerror('Invalid query. ' . $questionQuery . ' ' . mysql_error());
00224 return false;
00225 }
00226
00227
00228 if ($this->checkUserTimedOut($userId, -1, '1 MINUTE')) {
00229 displayerror('Sorry, you have exceeded your time limit for the quiz. Your latest submission cannot be evaluated.');
00230 return false;
00231 }
00232
00233 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00234 $sectionId = intval($_GET['sectionid']);
00235 if ($this->checkUserTimedOut($userId, $sectionId, '1 MINUTE')) {
00236 displayerror('Sorry, you have exceeded your time limit for this section. Your latest submission cannot be evaluated.');
00237 return false;
00238 }
00239 }
00240
00241 $submittedAnswers = array();
00242 $rollbackQuery = array();
00243 while ($questionRow = mysql_fetch_assoc($questionResult)) {
00244 $rollbackQuery[] = "(`quiz_sectionid` = {$questionRow['quiz_sectionid']} AND `quiz_questionid` = {$questionRow['quiz_questionid']})";
00245 $questionType = $questionRow['quiz_questiontype'];
00246
00247 if (!isset($_POST['hdnQuestion' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid']])) {
00248 displayerror(
00249 'Error. The answers that you submitted do not match the list of questions you were shown. You may have refreshed the page, and resubmitted your previous page\'s answers. ' .
00250 'Please do not use the navigation buttons on your browser while taking the quiz.'
00251 );
00252 return false;
00253 }
00254
00255 if ($questionType == 'sso' || $questionType == 'mso') {
00256 $options = getQuestionOptionList($this->quizId, $questionRow['quiz_sectionid'], $questionRow['quiz_questionid']);
00257 if ($questionType == 'sso') {
00258 $fieldName = 'optAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00259 $submittedAnswer = isset($_POST[$fieldName]) && is_numeric($_POST[$fieldName]) ? intval($_POST[$fieldName]) : '';
00260 $optionFound = false;
00261 for ($i = 0; $i < count($options); ++$i) {
00262 if ($options[$i]['quiz_optionid'] == $submittedAnswer) {
00263 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], $submittedAnswer);
00264 $optionFound = true;
00265 break;
00266 }
00267 }
00268
00269 if (!$optionFound)
00270 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], '');
00271 }
00272 else {
00273 $submittedAnswer = array();
00274 for ($i = 0; $i < count($options); ++$i) {
00275 $fieldName = 'chkAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'] . '_' . $options[$i]['quiz_optionid'];
00276 if (isset($_POST[$fieldName]) && is_numeric($_POST[$fieldName]))
00277 $submittedAnswer[] = intval($options[$i]['quiz_optionid']);
00278 }
00279 sort($submittedAnswer);
00280 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], implode('|', $submittedAnswer));
00281 }
00282 }
00283 elseif ($questionType == 'subjective') {
00284 $fieldName = 'txtAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00285 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], isset($_POST[$fieldName]) ? escape($_POST[$fieldName]) : '');
00286 }
00287 }
00288
00289 $rollbackQuery = "UPDATE `quiz_answersubmissions` SET `quiz_answersubmittime` = NULL WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND (" . implode(' OR ', $rollbackQuery) . ")";
00290 for ($i = 0; $i < count($submittedAnswers); ++$i) {
00291 $updateQuery = "UPDATE `quiz_answersubmissions` SET `quiz_submittedanswer` = '{$submittedAnswers[$i][3]}', `quiz_answersubmittime` = NOW() WHERE " .
00292 "`page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = {$submittedAnswers[$i][0]} AND " .
00293 "`quiz_questionid` = {$submittedAnswers[$i][1]} AND `user_id` = $userId";
00294 if (!mysql_query($updateQuery)) {
00295 displayerror('Invalid Query. Could not save answers.');
00296 mysql_query($rollbackQuery);
00297 return false;
00298 }
00299 }
00300
00301 return true;
00302 }
00303
00309 private function checkQuizInitialized($userId) {
00310 $countQuery = "SELECT COUNT(*) FROM `quiz_answersubmissions` WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00311 $countResult = mysql_query($countQuery);
00312
00313 $countRow = mysql_fetch_row($countResult);
00314
00315 return $countRow[0] == $this->quizRow['quiz_questionspertest'];
00316 }
00317
00323 public function initQuiz($userId) {
00324
00325
00326 if ($this->checkQuizInitialized($userId))
00327 return true;
00328
00329 $this->deleteEntries($userId);
00330 $sectionList = getSectionList($this->quizId);
00331 $questionList = array();
00332 $sections = array();
00333 for ($i = 0; $i < count($sectionList); ++$i) {
00334 $questionList[$i] = $this->getSectionQuestions($sectionList[$i]);
00335 for ($j = 0; $j < count($questionList[$i]); ++$j)
00336 $sections[] = $i;
00337 }
00338
00339 if ($this->quizRow['quiz_allowsectionrandomaccess'] == 0 && $this->quizRow['quiz_mixsections'])
00340 shuffle($sections);
00341
00342 $offsets = array_fill(0, count($questionList), 0);
00343 for ($i = 0; $i < count($sections); ++$i) {
00344 $insertQuery = "INSERT INTO `quiz_answersubmissions`(`page_modulecomponentid`, `quiz_sectionid`, `quiz_questionid`, `user_id`, `quiz_questionrank`) VALUES" .
00345 "({$this->quizId}, {$sectionList[$sections[$i]]['quiz_sectionid']}, {$questionList[$sections[$i]][$offsets[$sections[$i]]]}, $userId, $i)";
00346 if (!mysql_query($insertQuery)) {
00347 displayerror('Database Error. Could not initialize quiz.');
00348 return false;
00349 }
00350 $offsets[$sections[$i]]++;
00351 }
00352 return true;
00353 }
00354
00358 public function deleteEntries($userId) {
00359 $tableNames = array('quiz_userattempts', 'quiz_answersubmissions');
00360 $affectedRows = array();
00361 return deleteItem($tableNames, "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId", $affectedRows);
00362 }
00363
00364
00365 private function getPageQuestions($userId, $sectionId = -1) {
00366 $questionsPerPage = $this->quizRow['quiz_questionsperpage'];
00367 $questionQuery = "SELECT `quiz_sectionid`, `quiz_questionid` FROM `quiz_answersubmissions` WHERE `user_id` = $userId AND `page_modulecomponentid` = {$this->quizId} AND `quiz_answersubmittime` IS NULL ";
00368 if ($this->quizRow['quiz_allowsectionrandomaccess'] == 1)
00369 $questionQuery .= " AND `quiz_sectionid` = $sectionId ";
00370 $questionQuery .= " ORDER BY `quiz_questionrank` LIMIT $questionsPerPage";
00371 $questionResult = mysql_query($questionQuery);
00372 if (!$questionResult) {
00373 displayerror('Database Error. Could not fetch questions.');
00374 return null;
00375 }
00376 $questionIds = array();
00377 while ($questionRow = mysql_fetch_row($questionResult))
00378 $questionIds[] = $questionRow;
00379 return $questionIds;
00380 }
00381
00382 private function getTimerHtml($userId, $sectionId = -1) {
00383 $testElapsedTime = $this->getElapsedTime($userId);
00384 $testElapsedTime = explode(':', $testElapsedTime);
00385 $testElapsedTime = implode(', ', $testElapsedTime);
00386 $sectionElapsedTime = $this->getElapsedTime($userId,$sectionId);
00387 $sectionElapsedTime = explode(':', $sectionElapsedTime);
00388 $sectionElapsedTime = implode(', ', $sectionElapsedTime);
00389
00390 $testTime = $this->quizRow['quiz_testduration'];
00391 $testTime = explode(':', $testTime);
00392 $testTime = implode(', ', $testTime);
00393
00394 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00395 $sectionTime = mysql_fetch_array(mysql_query("SELECT `quiz_sectiontimelimit` FROM `quiz_sections` WHERE `page_modulecomponentid` = '{$this->quizId}' AND `quiz_sectionid` = '$sectionId'"));
00396
00397 $sectionTime = $sectionTime[0];
00398 $sectionTime = explode(':', $sectionTime);
00399 $sectionTime = implode(', ', $sectionTime);
00400 $scripts[] = "var sectionTimer = new JSTimer('sectionTimerContainer', $sectionElapsedTime);\nsectionTimer.addTickHandler($sectionTime, forceQuizSubmit)";
00401 }
00402
00403
00404 $scripts[] = "var testTimer = new JSTimer('testTimerContainer', $testElapsedTime);\ntestTimer.addTickHandler($testTime, forceQuizSubmit)";
00405
00406 $divs = array();
00407 if ($this->quizRow['quiz_showquiztimer']) {
00408
00409 $divs[] = '<div id="testTimerContainer" class="quiz_testtimer">Total Quiz Time Elapsed: </div>';
00410
00411 }
00412
00413 if ($this->quizRow['quiz_showpagetimer']) {
00414 $divs[] = '<div id="pageTimerContainer" class="quiz_pagetimer"></div>';
00415 $scripts[] = "var pageTimer = new JSTimer('pageTimerContainer', 0, 0, 0);\n";
00416 }
00417
00418 $sectionRow = getSectionRow($this->quizId, $sectionId);
00419 if ($sectionRow['quiz_sectionshowlimit']) {
00420 $sectionRow = getSectionRow($this->quizId,$sectionId);
00421 $limit = $sectionRow['quiz_sectiontimelimit'];
00422 $divs[] = '<div id="pageTimerlimit" class="quiz_limit">Section Limit: ' . $limit . '</div>';
00423 $divs[] = '<div id="sectionTimerContainer" class="quiz_testtimer">Section Time Elapsed: </div>';
00424 }
00425
00426 global $urlRequestRoot, $cmsFolder, $moduleFolder;
00427 $timerScriptSrc = "$urlRequestRoot/$cmsFolder/$moduleFolder/quiz/timer.js";
00428
00429 if (count($divs)) {
00430 $divs = implode("\n", $divs);
00431 $scripts = implode("\n", $scripts);
00432
00433 $timerScript = <<<TIMERSCRIPT
00434 <script type="text/javascript" src="$timerScriptSrc"></script>
00435 $divs
00436 <script type="text/javascript">
00437 function forceQuizSubmit() {
00438 alert("Your time is up. Please click Ok to submit the quiz. If you do not submit within 30 seconds, your quiz will expire, and your answers to this page will not be recorded.");
00439 var quizForm = document.getElementById('quizForm');
00440 var submitButton = document.getElementById('btnSubmit');
00441 submitButton.type = 'hidden';
00442 quizForm.submit();
00443 }
00444
00445 $scripts
00446 </script>
00447 TIMERSCRIPT;
00448 }
00449
00450 return $timerScript;
00451 }
00452
00458 private function formatQuestion($questionRow, $questionNumber = -1) {
00459 $questionType = $questionRow['quiz_questiontype'];
00460 if ($questionType == 'subjective') {
00461 $fieldName = 'txtAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00462 $answer = '<textarea rows="6" cols="36" name="' . $fieldName . '" id="' . $fieldName . '"></textarea>';
00463 }
00464 else {
00465 $optionList = getQuestionOptionList($this->quizId, $questionRow['quiz_sectionid'], $questionRow['quiz_questionid']);
00466
00467 $answer = '<table class="objectivecontainer" width="100%">';
00468 for ($i = 0; $i < count($optionList); ++$i) {
00469 $fieldType = ($questionType == 'sso' ? 'radio' : 'checkbox');
00470 $fieldName = '';
00471 $fieldId = '';
00472 if ($questionType == 'sso') {
00473 $fieldName = 'optAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00474 $fieldId = $fieldName . '_' . $optionList[$i]['quiz_optionid'];
00475 }
00476 elseif ($questionType == 'mso') {
00477 $fieldName = 'chkAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'] . '_' . $optionList[$i]['quiz_optionid'];
00478 $fieldId = $fieldName;
00479 }
00480 $answer .= "<tr><td width=\"24\"><input type=\"$fieldType\" name=\"$fieldName\" id=\"$fieldId\" value=\"{$optionList[$i]['quiz_optionid']}\" /> </td><td><label for=\"$fieldId\"> {$optionList[$i]['quiz_optiontext']}</label></td></tr>\n";
00481 }
00482 $answer .= '</table>';
00483 }
00484
00485 $hiddenFieldName = "hdnQuestion{$questionRow['quiz_sectionid']}_{$questionRow['quiz_questionid']}";
00486
00487 $questionDesc = $questionRow['quiz_question'];
00488 if ($questionNumber > 0) $questionDesc = $questionNumber . ') ' . $questionDesc;
00489
00490 global $sourceFolder, $moduleFolder;
00491 require_once($sourceFolder."/latexRender.class.php");
00492 $render = new latexrender();
00493 $questionDesc = $render->transform($questionDesc);
00494 $answer = $render->transform($answer);
00495
00496 return <<<QUESTIONFORM
00497 <input type="hidden" name="$hiddenFieldName" id="$hiddenFieldName" value="" />
00498 <div class="quiz_questioncontainer">
00499 {$questionDesc}
00500 </div>
00501 <div class="quiz_answercontainer">
00502 $answer
00503 </div>
00504 QUESTIONFORM;
00505 }
00506
00510 private function formatNextPage($userId, $sectionId = -1) {
00511 $questionCount = $this->quizRow['quiz_questionsperpage'];
00512 $questionQuery = "SELECT `quiz_questions`.`quiz_sectionid` AS `quiz_sectionid`, `quiz_questions`.`quiz_questionid` AS `quiz_questionid`, `quiz_question`, `quiz_questiontype`, `quiz_questionweight`, `quiz_answermaxlength`, `quiz_rightanswer`, `quiz_questionviewtime`, `quiz_answersubmittime` " .
00513 "FROM `quiz_questions`, `quiz_answersubmissions` WHERE " .
00514 "`quiz_questions`.`page_modulecomponentid` = {$this->quizId} AND " .
00515 "`quiz_answersubmissions`.`user_id` = $userId AND " .
00516 "`quiz_questions`.`page_modulecomponentid` = `quiz_answersubmissions`.`page_modulecomponentid` AND " .
00517 "`quiz_questions`.`quiz_sectionid` = `quiz_answersubmissions`.`quiz_sectionid` AND " .
00518 "`quiz_questions`.`quiz_questionid` = `quiz_answersubmissions`.`quiz_questionid` AND " .
00519 "`quiz_answersubmissions`.`quiz_answersubmittime` IS NULL ";
00520 if ($this->quizRow['quiz_allowsectionrandomaccess'] == 1)
00521 $questionQuery .= "AND `quiz_answersubmissions`.`quiz_sectionid` = $sectionId ";
00522 $questionQuery .= "ORDER BY `quiz_answersubmissions`.`quiz_questionrank` " .
00523 "LIMIT $questionCount";
00524
00525 $questionResult = mysql_query($questionQuery);
00526
00527 $questionNumber = 1;
00528 $questionPage = $this->getTimerHtml($userId, $sectionId);
00529 $questionPage .= '<form name="quizquestions" id="quizForm" method="POST" action="./+view' . ($sectionId == -1 ? '' : '§ionid=' . $sectionId) . '" onsubmit="return confirm(\'Are you sure you wish to submit this page?\')">';
00530 while ($questionRow = mysql_fetch_assoc($questionResult)) {
00531 if (is_null($questionRow['quiz_questionviewtime']))
00532 mysql_query("UPDATE `quiz_answersubmissions` SET `quiz_questionviewtime` = NOW() WHERE `page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = {$questionRow['quiz_sectionid']} AND `quiz_questionid` = {$questionRow['quiz_questionid']}");
00533 $questionPage .= $this->formatQuestion($questionRow, $questionNumber);
00534 ++$questionNumber;
00535 }
00536 $questionPage .= '<input type="submit" name="btnSubmit" id="btnSubmit" value="Submit" />';
00537 $questionPage .= '</form>';
00538
00539 $questionPage .= <<<QUESTIONPAGESCRIPT
00540 <script type="text/javascript">
00541
00542 var inputFields = document.getElementById('quizForm').getElementsByTagName('input');
00543 for (var i = 0; i < inputFields.length; ++i) {
00544 if (inputFields[i].type == 'radio')
00545 inputFields[i].onclick = function(e) {
00546 if (this.rel == 'checked') {
00547 this.checked = false;
00548 this.rel = '';
00549 }
00550 else {
00551 var elements = document.getElementsByName(this.name);
00552 for (var i = 0; i < elements.length; ++i) {
00553 elements[i].rel = '';
00554 elements[i].checked = false;
00555 }
00556 this.checked = true;
00557 this.rel = 'checked';
00558 }
00559 };
00560 }
00561 </script>
00562 QUESTIONPAGESCRIPT;
00563 return $questionPage;
00564 }
00565
00572 private function countAttemptedQuestions($userId, $sectionId = -1) {
00573 $countQuery = "SELECT COUNT(*) FROM `quiz_submittedanswers` WHERE `page_modulecomponentid` = {$this->quizId}";
00574 if ($sectionId != -1)
00575 $countQuery .= " AND `quiz_sectionid` = $sectionId";
00576 $countQuery .= " `user_id` = $userId AND `quiz_answersubmittime` IS NOT NULL";
00577 $countResult = mysql_query($countQuery);
00578 if (!$countResult) {
00579 displayerror('Database Error. Could not retrieve user attempt information.');
00580 return false;
00581 }
00582 $countRow = mysql_fetch_row($countResult);
00583 return $countRow[0];
00584 }
00585
00586 private function getSectionQuestions($sectionRow) {
00587 $questionTypes = array_keys(getQuestionTypes());
00588 $sectionId = $sectionRow['quiz_sectionid'];
00589
00590 if ($sectionRow['quiz_sectionquestionshuffled'] == 0) {
00591 $limit = 0;
00592 for ($i = 0; $i < count($questionTypes); ++$i)
00593 $limit += $sectionRow["quiz_section{$questionTypes[$i]}count"];
00594 $questionQuery = "SELECT `quiz_questionid` FROM `quiz_questions` WHERE `page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId ORDER BY `quiz_questionrank` LIMIT $limit";
00595 }
00596 else {
00597 $questionIdQueries = array();
00598 for ($i = 0; $i < count($questionTypes); ++$i) {
00599 $limit = $sectionRow["quiz_section{$questionTypes[$i]}count"];
00600 if ($limit) {
00601 $questionIdQueries[] =
00602 "(SELECT `quiz_questionid` FROM `quiz_questions` WHERE `page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId AND `quiz_questiontype` = '{$questionTypes[$i]}' ORDER BY RAND() LIMIT $limit)";
00603 }
00604 }
00605
00606 $questionQuery = "SELECT `quiz_questionid` FROM (" . implode(' UNION ', $questionIdQueries) . ") AS `questions` ORDER BY RAND()";
00607 }
00608
00609 $questionIds = array();
00610 $questionResult = mysql_query($questionQuery) or die(mysql_error());
00611 while ($questionRow = mysql_fetch_row($questionResult))
00612 $questionIds[] = $questionRow[0];
00613 return $questionIds;
00614 }
00615
00622 private function checkQuizCompleted($userId) {
00623 $countQuery = "SELECT COUNT(*) FROM `quiz_userattempts`, `quiz_sections` WHERE " .
00624 "`quiz_sections`.`page_modulecomponentid` = `quiz_userattempts`.`page_modulecomponentid` AND " .
00625 "`quiz_sections`.`quiz_sectionid` = `quiz_userattempts`.`quiz_sectionid` AND " .
00626 "`quiz_sections`.`page_modulecomponentid` = {$this->quizId} AND " .
00627 "`quiz_userattempts`.`user_id` = $userId AND " .
00628 "`quiz_submissiontime` IS NOT NULL";
00629 $countResult = mysql_query($countQuery);
00630 if (!$countResult) {
00631 displayerror('Database Error. Could not fetch section information.');
00632 return false;
00633 }
00634 $countRow = mysql_fetch_row($countResult);
00635 $completedCount = $countRow[0];
00636 $countQuery = "SELECT COUNT(*) FROM `quiz_sections` WHERE `page_modulecomponentid` = {$this->quizId}";
00637 $countResult = mysql_query($countQuery);
00638 $countRow = mysql_fetch_row($countResult);
00639 return $countRow[0] == $completedCount;
00640 }
00641
00647 private function isValidId($id) {
00648 return isset($id) && is_numeric($id) && $id > 0;
00649 }
00650
00655 private function markSectionCompleted($userId, $sectionId = -1) {
00656 if ($sectionId == -1) {
00657 $sections = getSectionList($this->quizId);
00658 $allOk = true;
00659 for ($i = 0; $i < count($sections); ++$i)
00660 $allOk = $this->markSectionCompleted($userId, $sections[$i]['quiz_sectionid']) && $allOk;
00661 return $allOk;
00662 }
00663
00664 $attemptRow = getAttemptRow($this->quizId, $sectionId, $userId);
00665 if (is_null($attemptRow['quiz_submissiontime'])) {
00666
00667 $questionQuery = "SELECT COUNT(*) FROM `quiz_answersubmissions` WHERE " .
00668 "`page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId AND `user_id` = $userId AND `quiz_answersubmittime` IS NULL";
00669 $questionResult = mysql_query($questionQuery);
00670 $questionRow = mysql_fetch_row($questionResult);
00671
00672 if ($questionRow[0] != 0)
00673 return false;
00674
00675 $updateQuery = "UPDATE `quiz_userattempts` SET `quiz_submissiontime` = NOW() WHERE `page_modulecomponentid` = $this->quizId AND `quiz_sectionid` = $sectionId AND `user_id` = $userId";
00676 if (mysql_query($updateQuery))
00677 return true;
00678 else {
00679 displayerror('Database Error. Could not mark section as completed.');
00680 return -1;
00681 }
00682 }
00683 else
00684 return true;
00685 }
00686
00692 private function markQuizCompleted($userId) {
00693 $updateQueries = array(
00694 "UPDATE `quiz_answersubmissions` SET `quiz_submittedanswer` = '', `quiz_answersubmittime` = NOW() WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND `quiz_answersubmittime` IS NULL",
00695 "UPDATE `quiz_userattempts` SET `quiz_submissiontime` = NOW() WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND `quiz_submissiontime` IS NULL"
00696 );
00697
00698 if (!mysql_query($updateQueries[0]) || !mysql_query($updateQueries[1])) {
00699 displayerror('Error. Could not mark quiz as completed.');
00700 return false;
00701 }
00702
00703 return true;
00704 }
00705
00711 private function getElapsedTime($userId, $sectionId = -1) {
00712 if ($sectionId < 0)
00713 $elapsedQuery = "SELECT TIMEDIFF(NOW(), MIN(`quiz_attemptstarttime`)) FROM `quiz_userattempts` WHERE " .
00714 "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00715 else
00716 $elapsedQuery = "SELECT TIMEDIFF(NOW(), `quiz_attemptstarttime`) FROM `quiz_userattempts` WHERE " .
00717 "`page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId AND `user_id` = $userId";
00718
00719 $elapsedResult = mysql_query($elapsedQuery);
00720 if (!$elapsedResult)
00721 displayerror('Error. ' . $elapsedQuery . '<br />' . mysql_error());
00722 $elapsedRow = mysql_fetch_row($elapsedResult);
00723 return $elapsedRow[0];
00724 }
00725
00726 private function getRemainingTime($userId, $sectionId = -1) {
00727 if ($sectionId < 0) {
00728 $remainingQuery = "SELECT TIMEDIFF(NOW(), ADDTIME(MIN(`quiz_attemptstarttime`), '{$this->quizRow['quiz_testduration']}')) FROM `quiz_userattempts` WHERE " .
00729 "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00730 }
00731 else {
00732 $remainingQuery = "SELECT TIMEDIFF(NOW(), ADDTIME(`quiz_attemptstarttime`, '{$this->quizRow['quiz_testduration']}')) FROM `quiz_userattempts` WHERE " .
00733 "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00734 }
00735
00736 $remainingResult = mysql_query($remainingQuery);
00737 $remainingRow = mysql_fetch_row($remainingResult);
00738 return $remainingRow[0];
00739 }
00740
00748 private function checkUserTimedOut($userId, $sectionId = -1, $offset = '0 SECOND') {
00749 if ($sectionId < 0) {
00750
00751
00752
00753 $timeoutQuery = "SELECT IF(DATE_SUB(NOW(), INTERVAL $offset) > ADDTIME(MIN(`quiz_attemptstarttime`), '{$this->quizRow['quiz_testduration']}'), 1, 0) AS `quiz_expired` FROM " .
00754 "`quiz_userattempts` WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00755 }
00756 else {
00757 $sectionRow = getSectionRow($this->quizId, $sectionId);
00758
00759 if ($sectionRow['quiz_sectiontimelimit'] == '00:00:00')
00760 return false;
00761
00762 $timeoutQuery = "SELECT IF(DATE_SUB(NOW(), INTERVAL $offset) > ADDTIME(`quiz_attemptstarttime`, '{$sectionRow['quiz_sectiontimelimit']}'), 1, 0) AS `quiz_expired` FROM " .
00763 "`quiz_userattempts` WHERE `page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId AND `user_id` = $userId";
00764 }
00765
00766 $timeoutResult = mysql_query($timeoutQuery);
00767 if (!$timeoutResult) {
00768 displayerror('Database Error. Could not retrieve time information.');
00769 return -1;
00770 }
00771
00772 $timeoutRow = mysql_fetch_row($timeoutResult);
00773 if (is_null($timeoutRow[0])) {
00774
00775
00776 return true;
00777 }
00778
00779 return $timeoutRow[0];
00780 }
00781
00788 private function forceQuizCompleted($userId, $sectionId = -1) {
00789 $updateQuery = "UPDATE `quiz_userattempts` SET `quiz_submissiontime` = NOW() WHERE `quiz_submissiontime` IS NULL AND `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00790 if ($sectionId >= 0)
00791 $updateQuery .= " AND `quiz_sectionid` = $sectionId";
00792 if (!mysql_query($updateQuery)) {
00793 displayerror('Database Error. Could not mark quiz as completed.');
00794 return false;
00795 }
00796 return true;
00797 }
00798 };