dirroot . '/mod/quiz/locallib.php'); /// Remember the current time as the time any responses were submitted /// (so as to make sure students don't get penalized for slow processing on this page) $timenow = time(); /// Get submitted parameters. $attemptid = required_param('attempt', PARAM_INT); $nextpage = optional_param('nextpage', 0, PARAM_INT); $submittedquestionids = required_param('questionids', PARAM_SEQUENCE); $finishattempt = optional_param('finishattempt', 0, PARAM_BOOL); $timeup = optional_param('timeup', 0, PARAM_BOOL); // True if form was submitted by timer. $attemptobj = new quiz_attempt($attemptid); /// Set $nexturl now. It will be updated if a particular question was sumbitted in /// adaptive mode. if ($nextpage == -1) { $nexturl = $attemptobj->summary_url(); } else { $nexturl = $attemptobj->attempt_url(0, $nextpage); } /// We treat automatically closed attempts just like normally closed attempts if ($timeup) { $finishattempt = 1; } /// Check login. require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm()); require_sesskey(); /// Check that this attempt belongs to this user. if ($attemptobj->get_userid() != $USER->id) { quiz_error($attemptobj->get_quiz(), 'notyourattempt'); } /// Check capabilites. if (!$attemptobj->is_preview_user()) { $attemptobj->require_capability('mod/quiz:attempt'); } /// If the attempt is already closed, send them to the review page. if ($attemptobj->is_finished()) { quiz_error($attemptobj->get_quiz(), 'attemptalreadyclosed'); } /// Don't log - we will end with a redirect to a page that is logged. /// Get the list of questions needed by this page. if (!empty($submittedquestionids)) { $submittedquestionids = explode(',', $submittedquestionids); } else { $submittedquestionids = array(); } if ($finishattempt) { $questionids = $attemptobj->get_question_ids(); } else { $questionids = $submittedquestionids; } /// Load those questions we need, and just the submitted states for now. $attemptobj->load_questions($questionids); if (!empty($submittedquestionids)) { $attemptobj->load_question_states($submittedquestionids); } /// Process the responses ///////////////////////////////////////////////// if (!$responses = data_submitted()) { quiz_error($attemptobj->get_quiz(), 'nodatasubmitted'); } /// Set the default event. This can be overruled by individual buttons. if ($finishattempt) { $event = QUESTION_EVENTCLOSE; } else { $event = QUESTION_EVENTSAVE; } /// Unset any variables we know are not responses unset($responses->id); unset($responses->q); unset($responses->oldpage); unset($responses->newpage); unset($responses->review); unset($responses->questionids); unset($responses->finishattempt); // same as $finishattempt unset($responses->forcenewattempt); /// Extract the responses. $actions will be an array indexed by the questions ids. $actions = question_extract_responses($attemptobj->get_questions($submittedquestionids), $responses, $event); /// Process each question in turn $success = true; $attempt = $attemptobj->get_attempt(); foreach($submittedquestionids as $id) { if (!isset($actions[$id])) { $actions[$id]->responses = array('' => ''); $actions[$id]->event = QUESTION_EVENTOPEN; } $actions[$id]->timestamp = $timenow; /// If a particular question was submitted, update the nexturl to go back to that question. if ($actions[$id]->event == QUESTION_EVENTSUBMIT) { $nexturl = $attemptobj->attempt_url($id); } $state = $attemptobj->get_question_state($id); if (question_process_responses($attemptobj->get_question($id), $state, $actions[$id], $attemptobj->get_quiz(), $attempt)) { save_question_session($attemptobj->get_question($id), $state); } else { $success = false; } } if (!$success) { print_error('errorprocessingresponses', 'question', $attemptobj->attempt_url(0, $page)); } /// If we do not have to finish the attempts (if we are only processing responses) /// save the attempt and redirect to the next page. if (!$finishattempt) { $attempt->timemodified = $timenow; $DB->update_record('quiz_attempts', $attempt); redirect($nexturl); } /// We have been asked to finish attempt, so do that ////////////////////// /// Now load the state of every question, reloading the ones we messed around /// with above. $attemptobj->preload_question_states(); $attemptobj->load_question_states(); /// Move each question to the closed state. $success = true; $attempt = $attemptobj->get_attempt(); foreach ($attemptobj->get_questions() as $id => $question) { $state = $attemptobj->get_question_state($id); $action = new stdClass; $action->event = QUESTION_EVENTCLOSE; $action->responses = $state->responses; $action->responses['_flagged'] = $state->flagged; $action->timestamp = $state->timestamp; if (question_process_responses($attemptobj->get_question($id), $state, $action, $attemptobj->get_quiz(), $attempt)) { save_question_session($attemptobj->get_question($id), $state); } else { $success = false; } } if (!$success) { print_error('errorprocessingresponses', 'question', $attemptobj->attempt_url(0, $page)); } /// Log the end of this attempt. add_to_log($attemptobj->get_courseid(), 'quiz', 'close attempt', 'review.php?attempt=' . $attemptobj->get_attemptid(), $attemptobj->get_quizid(), $attemptobj->get_cmid()); /// Update the quiz attempt record. $attempt->timemodified = $timenow; $attempt->timefinish = $timenow; $DB->update_record('quiz_attempts', $attempt); if (!$attempt->preview) { /// Record this user's best grade (if this is not a preview). quiz_save_best_grade($attemptobj->get_quiz()); /// Send any notification emails (if this is not a preview). $attemptobj->quiz_send_notification_emails(); } /// Clear the password check flag in the session. $accessmanager = $attemptobj->get_access_manager($timenow); $accessmanager->clear_password_access(); /// Send the user to the review page. redirect($attemptobj->review_url()); ?>