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
00038 public function getPropertiesForm($dataSource) {
00039 return 'No quiz specific properties.';
00040 }
00041
00042 public function submitPropertiesForm() {
00043 return true;
00044 }
00045
00051 private function getSectionStartForm($sectionId) {
00052 return <<<SECTIONSTARTFORM
00053 <form name="sectionstartform" method="POST" action="./+view" style="padding:0;margin:0;display:inline">
00054 <input type="hidden" name="hdnSectionId" id="hdnSectionId" value="$sectionId" />
00055 <input type="submit" name="btnStartSection" id="btnStartSection" value="Start" />
00056 </form>
00057 SECTIONSTARTFORM;
00058 }
00059
00064 public function getFrontPage($userId) {
00065 $frontPage = "<h2>{$this->quizRow['quiz_title']}</h2>\n";
00066 $frontPage .= "<div class=\"quiz_headertext\">{$this->quizRow['quiz_headertext']}</div><br /><br />\n";
00067 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00068 $sectionList = getSectionList($this->quizId);
00069 for ($i = 0; $i < count($sectionList); ++$i) {
00070 $frontPage .= '<strong>' . $sectionList[$i]['quiz_sectiontitle'] . '</strong> ';
00071 $attemptRow = getAttemptRow($this->quizId, $sectionList[$i]['quiz_sectionid'], $userId);
00072 if (!$attemptRow || is_null($attemptRow['quiz_attemptstarttime'])) {
00073
00074 $frontPage .= $this->getSectionStartForm($sectionList[$i]['quiz_sectionid']);
00075 }
00076 elseif (is_null($attemptRow['quiz_submissiontime'])) {
00077
00078 $frontPage .= ' <a href="./+view§ionid=' . $sectionList[$i]['quiz_sectionid'] . '">Go to questions</a>';
00079 }
00080 else {
00081
00082 $frontPage .= " Section Completed.";
00083 }
00084 $frontPage .= '<br /><br />';
00085 }
00086 }
00087 else {
00088 $frontPage .= <<<QUIZSTARTFORM
00089 <form name="quizstartform" method="POST" action="./+view" style="padding:0;margin:0;display:inline">
00090 <input type="submit" name="btnStartQuiz" id="btnStartQuiz" value="Start" />
00091 </form>
00092 QUIZSTARTFORM;
00093 }
00094
00095 return $frontPage;
00096 }
00097
00105 public function getQuizPage($userId) {
00106 if ($this->checkQuizCompleted($userId)) {
00107 displayinfo('You seem to have completed this quiz already. You can only take this quiz once.');
00108 return '';
00109 }
00110
00111 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00112
00113 if (isset($_POST['btnStartSection']) && $this->isValidId($_POST['hdnSectionId']) && sectionBelongsToQuiz($this->quizId, $_POST['hdnSectionId']))
00114 $sectionId = intval($_POST['hdnSectionId']);
00115 elseif (isset($_GET['sectionid']) && $this->isValidId($_GET['sectionid']))
00116 $sectionId = intval($_GET['sectionid']);
00117
00118 if (!isset($sectionId))
00119 return $this->getFrontPage($userId);
00120
00121 $attemptRow = getAttemptRow($this->quizId, $sectionId, $userId);
00122 $sectionStarted = $attemptRow ? true : false;
00123 $sectionCompleted = !is_null($attemptRow['quiz_submissiontime']);
00124
00125 if (!$sectionStarted) {
00126 if (!isset($_POST['btnStartSection'])) {
00127 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.');
00128 return '';
00129 }
00130 if (!startSection($this->quizId, $sectionId, $userId))
00131 return '';
00132 }
00133 elseif ($sectionCompleted) {
00134 displayinfo("You have completed this section.");
00135 return '';
00136 }
00137
00138 if (isset($_POST['btnSubmit'])) {
00139 if ($this->submitQuizPage($userId) === true) {
00140 if ($this->markSectionCompleted($userId, $sectionId)) {
00141
00142 if ($this->checkQuizCompleted($userId)) {
00143 return $this->quizRow['quiz_submittext'];
00144 }
00145 else {
00146 displayinfo('You have completed this section. You can move to another section.');
00147 return $this->getFrontPage($userId);
00148 }
00149 }
00150 else
00151 displayinfo('Your previous page was submitted successfully.');
00152 }
00153 }
00154
00155
00156 if ($this->checkUserTimedOut($userId)) {
00157 displayerror(QUIZ_TIMEOUT_ERRORMSG);
00158 $this->forceQuizCompleted($userId);
00159 return '';
00160 }
00161 elseif ($this->checkUserTimedOut($userId, $sectionId)) {
00162 displayerror(QUIZ_SECTION_TIMEOUT_ERRORMSG);
00163 $this->forceQuizCompleted($userId, $sectionId);
00164 return '';
00165 }
00166
00167 return $this->formatNextPage($userId, $sectionId);
00168 }
00169 else {
00170
00171
00172
00173
00174
00175 $minSectionId = getFirstSectionId($this->quizId);
00176 $attemptRow = getAttemptRow($this->quizId, $minSectionId, $userId);
00177
00178 if (!$attemptRow) {
00179 if (!isset($_POST['btnStartQuiz']))
00180 return $this->getFrontPage($userId);
00181
00182
00183
00184 $attemptQuery = "INSERT INTO `quiz_userattempts`(`page_modulecomponentid`, `quiz_sectionid`, `user_id`, `quiz_attemptstarttime`) " .
00185 "SELECT {$this->quizId}, `quiz_sectionid`, $userId, NOW() FROM `quiz_sections` WHERE `page_modulecomponentid` = {$this->quizId}";
00186 if (!mysql_query($attemptQuery)) {
00187 displayerror('Database Error. Could not update quiz information.');
00188 return '';
00189 }
00190 }
00191
00192 if (isset($_POST['btnSubmit'])) {
00193 if ($this->submitQuizPage($userId) == true) {
00194 if ($this->markSectionCompleted($userId, -1)) {
00195 if ($this->checkQuizCompleted($userId))
00196 return $this->quizRow['quiz_submittext'];
00197 }
00198 else
00199 displayinfo('Your previous page was submitted successfully.');
00200 }
00201 }
00202
00203
00204 if ($this->checkUserTimedOut($userId)) {
00205 displayerror(QUIZ_TIMEOUT_ERRORMSG);
00206 $this->forceQuizCompleted($userId);
00207 return '';
00208 }
00209
00210 return $this->formatNextPage($userId);
00211 }
00212 }
00213
00220 public function submitQuizPage($userId) {
00221
00222
00223 $questionQuery = "SELECT `quiz_questions`.`quiz_sectionid` AS `quiz_sectionid`, " .
00224 "`quiz_questions`.`quiz_questionid` AS `quiz_questionid`, " .
00225 "`quiz_questions`.`quiz_questiontype` AS `quiz_questiontype`, " .
00226 "`quiz_questions`.`quiz_answermaxlength` AS `quiz_answermaxlength` " .
00227 "FROM `quiz_answersubmissions`, `quiz_questions` WHERE " .
00228 "`quiz_questions`.`page_modulecomponentid` = `quiz_answersubmissions`.`page_modulecomponentid` AND " .
00229 "`quiz_questions`.`quiz_sectionid` = `quiz_answersubmissions`.`quiz_sectionid` AND " .
00230 "`quiz_questions`.`quiz_questionid` = `quiz_answersubmissions`.`quiz_questionid` AND " .
00231 "`quiz_questions`.`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND " .
00232 "`quiz_questionviewtime` IS NOT NULL AND `quiz_answersubmittime` IS NULL ";
00233 if($this->quizRow['quiz_allowsectionrandomaccess'] == 1)
00234 $questionQuery .= "AND `quiz_answersubmissions`.`quiz_sectionid` = {$_GET['sectionid']} ";
00235 $questionQuery .= "ORDER BY `quiz_answersubmissions`.`quiz_questionrank` LIMIT {$this->quizRow['quiz_questionsperpage']}";
00236 $questionResult = mysql_query($questionQuery);
00237 if (!$questionResult) {
00238 displayerror('Invalid query. ' . $questionQuery . ' ' . mysql_error());
00239 return false;
00240 }
00241
00242
00243 if ($this->checkUserTimedOut($userId, -1, '1 MINUTE')) {
00244 displayerror('Sorry, you have exceeded your time limit for the quiz. Your latest submission cannot be evaluated.');
00245 return false;
00246 }
00247
00248 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00249 $sectionId = intval($_GET['sectionid']);
00250 if ($this->checkUserTimedOut($userId, $sectionId, '1 MINUTE')) {
00251 displayerror('Sorry, you have exceeded your time limit for this section. Your latest submission cannot be evaluated.');
00252 return false;
00253 }
00254 }
00255
00256 $submittedAnswers = array();
00257 $rollbackQuery = array();
00258 while ($questionRow = mysql_fetch_assoc($questionResult)) {
00259 $rollbackQuery[] = "(`quiz_sectionid` = {$questionRow['quiz_sectionid']} AND `quiz_questionid` = {$questionRow['quiz_questionid']})";
00260 $questionType = $questionRow['quiz_questiontype'];
00261
00262 if (!isset($_POST['hdnQuestion' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid']])) {
00263 displayerror(
00264 '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. ' .
00265 'Please do not use the navigation buttons on your browser while taking the quiz.'
00266 );
00267 return false;
00268 }
00269
00270 if ($questionType == 'sso' || $questionType == 'mso') {
00271 $options = getQuestionOptionList($this->quizId, $questionRow['quiz_sectionid'], $questionRow['quiz_questionid']);
00272 if ($questionType == 'sso') {
00273 $fieldName = 'optAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00274 $submittedAnswer = isset($_POST[$fieldName]) && is_numeric($_POST[$fieldName]) ? intval($_POST[$fieldName]) : '';
00275 $optionFound = false;
00276 for ($i = 0; $i < count($options); ++$i) {
00277 if ($options[$i]['quiz_optionid'] == $submittedAnswer) {
00278 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], $submittedAnswer);
00279 $optionFound = true;
00280 break;
00281 }
00282 }
00283
00284 if (!$optionFound)
00285 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], '');
00286 }
00287 else {
00288 $submittedAnswer = array();
00289 for ($i = 0; $i < count($options); ++$i) {
00290 $fieldName = 'chkAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'] . '_' . $options[$i]['quiz_optionid'];
00291 if (isset($_POST[$fieldName]) && is_numeric($_POST[$fieldName]))
00292 $submittedAnswer[] = intval($options[$i]['quiz_optionid']);
00293 }
00294 sort($submittedAnswer);
00295 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], implode('|', $submittedAnswer));
00296 }
00297 }
00298 elseif ($questionType == 'subjective') {
00299 $fieldName = 'txtAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00300 $submittedAnswers[] = array($questionRow['quiz_sectionid'], $questionRow['quiz_questionid'], $questionRow['quiz_questiontype'], isset($_POST[$fieldName]) ? escape($_POST[$fieldName]) : '');
00301 }
00302 }
00303
00304 $rollbackQuery = "UPDATE `quiz_answersubmissions` SET `quiz_answersubmittime` = NULL WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND (" . implode(' OR ', $rollbackQuery) . ")";
00305 for ($i = 0; $i < count($submittedAnswers); ++$i) {
00306 $updateQuery = "UPDATE `quiz_answersubmissions` SET `quiz_submittedanswer` = '{$submittedAnswers[$i][3]}', `quiz_answersubmittime` = NOW() WHERE " .
00307 "`page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = {$submittedAnswers[$i][0]} AND " .
00308 "`quiz_questionid` = {$submittedAnswers[$i][1]} AND `user_id` = $userId";
00309 if (!mysql_query($updateQuery)) {
00310 displayerror('Invalid Query. Could not save answers.');
00311 mysql_query($rollbackQuery);
00312 return false;
00313 }
00314 }
00315
00316 return true;
00317 }
00318
00325 private function checkQuizInitialized($userId) {
00326 $countQuery = "SELECT COUNT(*) FROM `quiz_answersubmissions` WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00327 $countResult = mysql_query($countQuery);
00328
00329 $countRow = mysql_fetch_row($countResult);
00330
00331 return $countRow[0] == $this->quizRow['quiz_questionspertest'];
00332 }
00333
00340 public function initQuiz($userId) {
00341
00342
00343 if ($this->checkQuizInitialized($userId))
00344 return true;
00345
00346 $this->deleteEntries($userId);
00347 $sectionList = getSectionList($this->quizId);
00348 $questionList = array();
00349 $sections = array();
00350 for ($i = 0; $i < count($sectionList); ++$i) {
00351 $questionList[$i] = $this->getSectionQuestions($sectionList[$i]);
00352 for ($j = 0; $j < count($questionList[$i]); ++$j)
00353 $sections[] = $i;
00354 }
00355
00356 if ($this->quizRow['quiz_allowsectionrandomaccess'] == 0 && $this->quizRow['quiz_mixsections'])
00357 shuffle($sections);
00358
00359 $offsets = array_fill(0, count($questionList), 0);
00360 for ($i = 0; $i < count($sections); ++$i) {
00361 $insertQuery = "INSERT INTO `quiz_answersubmissions`(`page_modulecomponentid`, `quiz_sectionid`, `quiz_questionid`, `user_id`, `quiz_questionrank`) VALUES" .
00362 "({$this->quizId}, {$sectionList[$sections[$i]]['quiz_sectionid']}, {$questionList[$sections[$i]][$offsets[$sections[$i]]]}, $userId, $i)";
00363 if (!mysql_query($insertQuery)) {
00364 displayerror('Database Error. Could not initialize quiz.');
00365 return false;
00366 }
00367 $offsets[$sections[$i]]++;
00368 }
00369 return true;
00370 }
00371
00376 public function deleteEntries($userId) {
00377 $tableNames = array('quiz_userattempts', 'quiz_answersubmissions');
00378 $affectedRows = array();
00379 return deleteItem($tableNames, "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId", $affectedRows);
00380 }
00381
00386 private function getPageQuestions($userId, $sectionId = -1) {
00387 $questionsPerPage = $this->quizRow['quiz_questionsperpage'];
00388 $questionQuery = "SELECT `quiz_sectionid`, `quiz_questionid` FROM `quiz_answersubmissions` WHERE `user_id` = $userId AND `page_modulecomponentid` = {$this->quizId} AND `quiz_answersubmittime` IS NULL ";
00389 if ($this->quizRow['quiz_allowsectionrandomaccess'] == 1)
00390 $questionQuery .= " AND `quiz_sectionid` = $sectionId ";
00391 $questionQuery .= " ORDER BY `quiz_questionrank` LIMIT $questionsPerPage";
00392 $questionResult = mysql_query($questionQuery);
00393 if (!$questionResult) {
00394 displayerror('Database Error. Could not fetch questions.');
00395 return null;
00396 }
00397 $questionIds = array();
00398 while ($questionRow = mysql_fetch_row($questionResult))
00399 $questionIds[] = $questionRow;
00400 return $questionIds;
00401 }
00402
00408 private function getTimerHtml($userId, $sectionId = -1) {
00409 $testElapsedTime = $this->getElapsedTime($userId);
00410 $testElapsedTime = explode(':', $testElapsedTime);
00411 $testElapsedTime = implode(', ', $testElapsedTime);
00412 $sectionElapsedTime = $this->getElapsedTime($userId,$sectionId);
00413 $sectionElapsedTime = explode(':', $sectionElapsedTime);
00414 $sectionElapsedTime = implode(', ', $sectionElapsedTime);
00415
00416 $testTime = $this->quizRow['quiz_testduration'];
00417 $testTime = explode(':', $testTime);
00418 $testTime = implode(', ', $testTime);
00419
00420 if ($this->quizRow['quiz_allowsectionrandomaccess']) {
00421 $sectionTime = mysql_fetch_array(mysql_query("SELECT `quiz_sectiontimelimit` FROM `quiz_sections` WHERE `page_modulecomponentid` = '{$this->quizId}' AND `quiz_sectionid` = '$sectionId'"));
00422
00423 $sectionTime = $sectionTime[0];
00424 $sectionTime = explode(':', $sectionTime);
00425 $sectionTime = implode(', ', $sectionTime);
00426 $scripts[] = "var sectionTimer = new JSTimer('sectionTimerContainer', $sectionElapsedTime);\nsectionTimer.addTickHandler($sectionTime, forceQuizSubmit)";
00427 }
00428
00429
00430 $scripts[] = "var testTimer = new JSTimer('testTimerContainer', $testElapsedTime);\ntestTimer.addTickHandler($testTime, forceQuizSubmit)";
00431
00432 $divs = array();
00433 if ($this->quizRow['quiz_showquiztimer']) {
00434
00435 $divs[] = '<div id="testTimerContainer" class="quiz_testtimer">Total Quiz Time Elapsed: </div>';
00436
00437 }
00438
00439 if ($this->quizRow['quiz_showpagetimer']) {
00440 $divs[] = '<div id="pageTimerContainer" class="quiz_pagetimer"></div>';
00441 $scripts[] = "var pageTimer = new JSTimer('pageTimerContainer', 0, 0, 0);\n";
00442 }
00443
00444 $sectionRow = getSectionRow($this->quizId, $sectionId);
00445 if ($sectionRow['quiz_sectionshowlimit']) {
00446 $sectionRow = getSectionRow($this->quizId,$sectionId);
00447 $limit = $sectionRow['quiz_sectiontimelimit'];
00448 $divs[] = '<div id="pageTimerlimit" class="quiz_limit">Section Limit: ' . $limit . '</div>';
00449 $divs[] = '<div id="sectionTimerContainer"
00450 class="quiz_testtimer">Section Time Elapsed: </div><br /><br />';
00451 }
00452
00453 global $urlRequestRoot, $cmsFolder, $moduleFolder;
00454 $timerScriptSrc = "$urlRequestRoot/$cmsFolder/$moduleFolder/quiz/timer.js";
00455
00456 if (count($divs)) {
00457 $divs = implode("\n", $divs);
00458 $scripts = implode("\n", $scripts);
00459
00460 $timerScript = <<<TIMERSCRIPT
00461 <script type="text/javascript" src="$timerScriptSrc"></script>
00462 $divs
00463 <script type="text/javascript">
00464 function forceQuizSubmit() {
00465 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.");
00466 var quizForm = document.getElementById('quizForm');
00467 var submitButton = document.getElementById('btnSubmit');
00468 submitButton.type = 'hidden';
00469 quizForm.submit();
00470 }
00471
00472 $scripts
00473 </script>
00474 TIMERSCRIPT;
00475 }
00476
00477 return $timerScript;
00478 }
00479
00486 private function formatQuestion($questionRow, $questionNumber = -1) {
00487 $questionType = $questionRow['quiz_questiontype'];
00488 if ($questionType == 'subjective') {
00489 $fieldName = 'txtAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00490 $answer = '<textarea
00491 style="width:95%;height:100px;" name="' .
00492 $fieldName . '" id="' . $fieldName . '"></textarea>';
00493 }
00494 else {
00495 $optionList = getQuestionOptionList($this->quizId, $questionRow['quiz_sectionid'], $questionRow['quiz_questionid']);
00496
00497 $answer = '<table class="objectivecontainer" width="100%">';
00498 for ($i = 0; $i < count($optionList); ++$i) {
00499 $fieldType = ($questionType == 'sso' ? 'radio' : 'checkbox');
00500 $fieldName = '';
00501 $fieldId = '';
00502 if ($questionType == 'sso') {
00503 $fieldName = 'optAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'];
00504 $fieldId = $fieldName . '_' . $optionList[$i]['quiz_optionid'];
00505 }
00506 elseif ($questionType == 'mso') {
00507 $fieldName = 'chkAnswer' . $questionRow['quiz_sectionid'] . '_' . $questionRow['quiz_questionid'] . '_' . $optionList[$i]['quiz_optionid'];
00508 $fieldId = $fieldName;
00509 }
00510 $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";
00511 }
00512 $answer .= '</table>';
00513 }
00514
00515 $hiddenFieldName = "hdnQuestion{$questionRow['quiz_sectionid']}_{$questionRow['quiz_questionid']}";
00516
00517 $questionDesc = $questionRow['quiz_question'];
00518 if ($questionNumber > 0) $questionDesc = $questionNumber . ') ' . $questionDesc;
00519
00520 global $sourceFolder, $moduleFolder;
00521 require_once($sourceFolder."/latexRender.class.php");
00522 $render = new latexrender();
00523 $questionDesc = $render->transform($questionDesc);
00524 $answer = $render->transform($answer);
00525
00526 return <<<QUESTIONFORM
00527 <input type="hidden" name="$hiddenFieldName" id="$hiddenFieldName" value="" />
00528 <div class="quiz_questioncontainer">
00529 <br /><b>{$questionDesc}</b><br /><br />
00530 </div>
00531 <div class="quiz_answercontainer">
00532 $answer
00533 </div>
00534 QUESTIONFORM;
00535 }
00536
00541 private function formatNextPage($userId, $sectionId = -1) {
00542 $questionCount = $this->quizRow['quiz_questionsperpage'];
00543 $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` " .
00544 "FROM `quiz_questions`, `quiz_answersubmissions` WHERE " .
00545 "`quiz_questions`.`page_modulecomponentid` = {$this->quizId} AND " .
00546 "`quiz_answersubmissions`.`user_id` = $userId AND " .
00547 "`quiz_questions`.`page_modulecomponentid` = `quiz_answersubmissions`.`page_modulecomponentid` AND " .
00548 "`quiz_questions`.`quiz_sectionid` = `quiz_answersubmissions`.`quiz_sectionid` AND " .
00549 "`quiz_questions`.`quiz_questionid` = `quiz_answersubmissions`.`quiz_questionid` AND " .
00550 "`quiz_answersubmissions`.`quiz_answersubmittime` IS NULL ";
00551 if ($this->quizRow['quiz_allowsectionrandomaccess'] == 1)
00552 $questionQuery .= "AND `quiz_answersubmissions`.`quiz_sectionid` = $sectionId ";
00553 $questionQuery .= "ORDER BY `quiz_answersubmissions`.`quiz_questionrank` " .
00554 "LIMIT $questionCount";
00555
00556 $questionResult = mysql_query($questionQuery);
00557
00558 $questionNumber = 1;
00559 $questionPage = $this->getTimerHtml($userId, $sectionId);
00560 $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?\')">';
00561 while ($questionRow = mysql_fetch_assoc($questionResult)) {
00562 if (is_null($questionRow['quiz_questionviewtime']))
00563 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']}");
00564 $questionPage .= $this->formatQuestion($questionRow, $questionNumber);
00565 ++$questionNumber;
00566 }
00567 $questionPage .= '<input type="submit" name="btnSubmit" id="btnSubmit" value="Submit" />';
00568 $questionPage .= '</form>';
00569
00570 $questionPage .= <<<QUESTIONPAGESCRIPT
00571 <script type="text/javascript">
00572
00573 var inputFields = document.getElementById('quizForm').getElementsByTagName('input');
00574 for (var i = 0; i < inputFields.length; ++i) {
00575 if (inputFields[i].type == 'radio')
00576 inputFields[i].onclick = function(e) {
00577 if (this.rel == 'checked') {
00578 this.checked = false;
00579 this.rel = '';
00580 }
00581 else {
00582 var elements = document.getElementsByName(this.name);
00583 for (var i = 0; i < elements.length; ++i) {
00584 elements[i].rel = '';
00585 elements[i].checked = false;
00586 }
00587 this.checked = true;
00588 this.rel = 'checked';
00589 }
00590 };
00591 }
00592 </script>
00593 QUESTIONPAGESCRIPT;
00594 return $questionPage;
00595 }
00596
00604 private function countAttemptedQuestions($userId, $sectionId = -1) {
00605 $countQuery = "SELECT COUNT(*) FROM `quiz_submittedanswers` WHERE `page_modulecomponentid` = {$this->quizId}";
00606 if ($sectionId != -1)
00607 $countQuery .= " AND `quiz_sectionid` = $sectionId";
00608 $countQuery .= " `user_id` = $userId AND `quiz_answersubmittime` IS NOT NULL";
00609 $countResult = mysql_query($countQuery);
00610 if (!$countResult) {
00611 displayerror('Database Error. Could not retrieve user attempt information.');
00612 return false;
00613 }
00614 $countRow = mysql_fetch_row($countResult);
00615 return $countRow[0];
00616 }
00617
00622 private function getSectionQuestions($sectionRow) {
00623 $questionTypes = array_keys(getQuestionTypes());
00624 $sectionId = $sectionRow['quiz_sectionid'];
00625
00626 if ($sectionRow['quiz_sectionquestionshuffled'] == 0) {
00627 $limit = 0;
00628 for ($i = 0; $i < count($questionTypes); ++$i)
00629 $limit += $sectionRow["quiz_section{$questionTypes[$i]}count"];
00630 $questionQuery = "SELECT `quiz_questionid` FROM `quiz_questions` WHERE `page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId ORDER BY `quiz_questionrank` LIMIT $limit";
00631 }
00632 else {
00633 $questionIdQueries = array();
00634 for ($i = 0; $i < count($questionTypes); ++$i) {
00635 $limit = $sectionRow["quiz_section{$questionTypes[$i]}count"];
00636 if ($limit) {
00637 $questionIdQueries[] =
00638 "(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)";
00639 }
00640 }
00641
00642 $questionQuery = "SELECT `quiz_questionid` FROM (" . implode(' UNION ', $questionIdQueries) . ") AS `questions` ORDER BY RAND()";
00643 }
00644
00645 $questionIds = array();
00646 $questionResult = mysql_query($questionQuery) or die(mysql_error());
00647 while ($questionRow = mysql_fetch_row($questionResult))
00648 $questionIds[] = $questionRow[0];
00649 return $questionIds;
00650 }
00651
00659 private function checkQuizCompleted($userId) {
00660 $countQuery = "SELECT COUNT(*) FROM `quiz_userattempts`, `quiz_sections` WHERE " .
00661 "`quiz_sections`.`page_modulecomponentid` = `quiz_userattempts`.`page_modulecomponentid` AND " .
00662 "`quiz_sections`.`quiz_sectionid` = `quiz_userattempts`.`quiz_sectionid` AND " .
00663 "`quiz_sections`.`page_modulecomponentid` = {$this->quizId} AND " .
00664 "`quiz_userattempts`.`user_id` = $userId AND " .
00665 "`quiz_submissiontime` IS NOT NULL";
00666 $countResult = mysql_query($countQuery);
00667 if (!$countResult) {
00668 displayerror('Database Error. Could not fetch section information.');
00669 return false;
00670 }
00671 $countRow = mysql_fetch_row($countResult);
00672 $completedCount = $countRow[0];
00673 $countQuery = "SELECT COUNT(*) FROM `quiz_sections` WHERE `page_modulecomponentid` = {$this->quizId}";
00674 $countResult = mysql_query($countQuery);
00675 $countRow = mysql_fetch_row($countResult);
00676 return $countRow[0] == $completedCount;
00677 }
00678
00685 private function isValidId($id) {
00686 return isset($id) && is_numeric($id) && $id > 0;
00687 }
00688
00694 private function markSectionCompleted($userId, $sectionId = -1) {
00695 if ($sectionId == -1) {
00696 $sections = getSectionList($this->quizId);
00697 $allOk = true;
00698 for ($i = 0; $i < count($sections); ++$i)
00699 $allOk = $this->markSectionCompleted($userId, $sections[$i]['quiz_sectionid']) && $allOk;
00700 return $allOk;
00701 }
00702
00703 $attemptRow = getAttemptRow($this->quizId, $sectionId, $userId);
00704 if (is_null($attemptRow['quiz_submissiontime'])) {
00705
00706 $questionQuery = "SELECT COUNT(*) FROM `quiz_answersubmissions` WHERE " .
00707 "`page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId AND `user_id` = $userId AND `quiz_answersubmittime` IS NULL";
00708 $questionResult = mysql_query($questionQuery);
00709 $questionRow = mysql_fetch_row($questionResult);
00710
00711 if ($questionRow[0] != 0)
00712 return false;
00713
00714 $updateQuery = "UPDATE `quiz_userattempts` SET `quiz_submissiontime` = NOW() WHERE `page_modulecomponentid` = $this->quizId AND `quiz_sectionid` = $sectionId AND `user_id` = $userId";
00715 if (mysql_query($updateQuery))
00716 return true;
00717 else {
00718 displayerror('Database Error. Could not mark section as completed.');
00719 return -1;
00720 }
00721 }
00722 else
00723 return true;
00724 }
00725
00732 private function markQuizCompleted($userId) {
00733 $updateQueries = array(
00734 "UPDATE `quiz_answersubmissions` SET `quiz_submittedanswer` = '', `quiz_answersubmittime` = NOW() WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND `quiz_answersubmittime` IS NULL",
00735 "UPDATE `quiz_userattempts` SET `quiz_submissiontime` = NOW() WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId AND `quiz_submissiontime` IS NULL"
00736 );
00737
00738 if (!mysql_query($updateQueries[0]) || !mysql_query($updateQueries[1])) {
00739 displayerror('Error. Could not mark quiz as completed.');
00740 return false;
00741 }
00742
00743 return true;
00744 }
00745
00752 private function getElapsedTime($userId, $sectionId = -1) {
00753 if ($sectionId < 0)
00754 $elapsedQuery = "SELECT TIMEDIFF(NOW(), MIN(`quiz_attemptstarttime`)) FROM `quiz_userattempts` WHERE " .
00755 "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00756 else
00757 $elapsedQuery = "SELECT TIMEDIFF(NOW(), `quiz_attemptstarttime`) FROM `quiz_userattempts` WHERE " .
00758 "`page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId AND `user_id` = $userId";
00759
00760 $elapsedResult = mysql_query($elapsedQuery);
00761 if (!$elapsedResult)
00762 displayerror('Error. ' . $elapsedQuery . '<br />' . mysql_error());
00763 $elapsedRow = mysql_fetch_row($elapsedResult);
00764 return $elapsedRow[0];
00765 }
00766
00767 private function getRemainingTime($userId, $sectionId = -1) {
00768 if ($sectionId < 0) {
00769 $remainingQuery = "SELECT TIMEDIFF(NOW(), ADDTIME(MIN(`quiz_attemptstarttime`), '{$this->quizRow['quiz_testduration']}')) FROM `quiz_userattempts` WHERE " .
00770 "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00771 }
00772 else {
00773 $remainingQuery = "SELECT TIMEDIFF(NOW(), ADDTIME(`quiz_attemptstarttime`, '{$this->quizRow['quiz_testduration']}')) FROM `quiz_userattempts` WHERE " .
00774 "`page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00775 }
00776
00777 $remainingResult = mysql_query($remainingQuery);
00778 $remainingRow = mysql_fetch_row($remainingResult);
00779 return $remainingRow[0];
00780 }
00781
00790 private function checkUserTimedOut($userId, $sectionId = -1, $offset = '0 SECOND') {
00791 if ($sectionId < 0) {
00792
00793
00794
00795 $timeoutQuery = "SELECT IF(DATE_SUB(NOW(), INTERVAL $offset) > ADDTIME(MIN(`quiz_attemptstarttime`), '{$this->quizRow['quiz_testduration']}'), 1, 0) AS `quiz_expired` FROM " .
00796 "`quiz_userattempts` WHERE `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00797 }
00798 else {
00799 $sectionRow = getSectionRow($this->quizId, $sectionId);
00800
00801 if ($sectionRow['quiz_sectiontimelimit'] == '00:00:00')
00802 return false;
00803
00804 $timeoutQuery = "SELECT IF(DATE_SUB(NOW(), INTERVAL $offset) > ADDTIME(`quiz_attemptstarttime`, '{$sectionRow['quiz_sectiontimelimit']}'), 1, 0) AS `quiz_expired` FROM " .
00805 "`quiz_userattempts` WHERE `page_modulecomponentid` = {$this->quizId} AND `quiz_sectionid` = $sectionId AND `user_id` = $userId";
00806 }
00807
00808 $timeoutResult = mysql_query($timeoutQuery);
00809 if (!$timeoutResult) {
00810 displayerror('Database Error. Could not retrieve time information.');
00811 return -1;
00812 }
00813
00814 $timeoutRow = mysql_fetch_row($timeoutResult);
00815 if (is_null($timeoutRow[0])) {
00816
00817
00818 return true;
00819 }
00820
00821 return $timeoutRow[0];
00822 }
00823
00831 private function forceQuizCompleted($userId, $sectionId = -1) {
00832 $updateQuery = "UPDATE `quiz_userattempts` SET `quiz_submissiontime` = NOW() WHERE `quiz_submissiontime` IS NULL AND `page_modulecomponentid` = {$this->quizId} AND `user_id` = $userId";
00833 if ($sectionId >= 0)
00834 $updateQuery .= " AND `quiz_sectionid` = $sectionId";
00835 if (!mysql_query($updateQuery)) {
00836 displayerror('Database Error. Could not mark quiz as completed.');
00837 return false;
00838 }
00839 return true;
00840 }
00841 };