notify(get_string('attemptsdeleted','quiz'), 'notifysuccess');
}
}
+
+/**
+ * Checks whether the current user is allowed to view a file uploaded in a quiz.
+ * Teachers can view any from their courses, students can only view their own.
+ *
+ * @param int $attemptid int attempt id
+ * @param int $questionid int question id
+ * @return boolean to indicate access granted or denied
+ */
+function quiz_check_file_access($attemptid, $questionid) {
+ global $USER;
+
+ $attempt = get_record("quiz_attempts", 'id', $attemptid);
+ $quiz = get_record("quiz", 'id', $attempt->quiz);
+ $context = get_context_instance(CONTEXT_COURSE, $quiz->course);
+
+ // access granted if the current user submitted this file
+ if ($attempt->userid == $USER->id) {
+ return true;
+ // access granted if the current user has permission to grade quizzes in this course
+ } else if (has_capability('mod/quiz:viewreports', $context) || has_capability('mod/quiz:grade', $context)) {
+ return true;
+ }
+
+ // otherwise, this user does not have permission
+ return false;
+}
?>
\ No newline at end of file
--- /dev/null
+<?php
+ // This script fetches files from the dataroot/questionattempt directory
+ // It is based on the top-level file.php
+ //
+ // On a module-by-module basis (currently only implemented for quiz), it checks
+ // whether the user has permission to view the file.
+ //
+ // Syntax: question/file.php/questionattempt/attemptid/questionid/filename.ext
+ // question/file.php/questionattempt/attemptid/questionid/filename.ext?forcedownload=1 (download instead of inline)
+ // Workaround: question/file.php?file=/questionattempt/attemptid/questionid
+ // Test: question/file.php/testslasharguments
+
+ require_once('../config.php');
+ require_once('../lib/filelib.php');
+
+ // disable moodle specific debug messages
+ disable_debugging();
+
+ $relativepath = get_file_argument('file.php');
+ $forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
+
+ // relative path must start with '/', because of backup/restore!!!
+ if (!$relativepath) {
+ error('No valid arguments supplied or incorrect server configuration');
+ } else if ($relativepath{0} != '/') {
+ error('No valid arguments supplied, path does not start with slash!');
+ }
+
+ $pathname = $CFG->dataroot.$relativepath;
+
+ // extract relative path components
+ $args = explode('/', trim($relativepath, '/'));
+ if (count($args) == 0) { // always at least courseid, may search for index.html in course root
+ error('No valid arguments supplied');
+ }
+
+ // security: only allow access to questionattempt directory
+ if ($args[0] != 'questionattempt') {
+ question_attempt_not_found();
+ }
+
+ // security: require login
+ require_login();
+
+ // security: do not return directory node!
+ if (is_dir($pathname)) {
+ question_attempt_not_found();
+ }
+
+ $lifetime = 0; // do not cache because students may reupload files
+
+ // force download for any student-submitted files
+ $forcedownload = 1;
+
+ // security: check that the user has permission to access this file
+ $haspermission = false;
+ if ($attempt = get_record("question_attempts", "id", $args[1])) {
+ $modfile = $CFG->dirroot .'/mod/'. $attempt->modulename .'/lib.php';
+ $modcheckfileaccess = $attempt->modulename .'_check_file_access';
+ if (file_exists($modfile)) {
+ @require_once($modfile);
+ if (function_exists($modcheckfileaccess)) {
+ $haspermission = $modcheckfileaccess($args[1], $args[2]);
+ }
+ }
+ }
+
+ if ($haspermission) {
+ // check that file exists
+ if (!file_exists($pathname)) {
+ question_attempt_not_found();
+ }
+
+ // send the file
+ session_write_close(); // unlock session during fileserving
+ $filename = $args[count($args)-1];
+ send_file($pathname, $filename, $lifetime, $CFG->filteruploadedfiles, false, $forcedownload);
+ } else {
+ question_attempt_not_found();
+ }
+
+ function question_attempt_not_found() {
+ global $CFG;
+ header('HTTP/1.0 404 not found');
+ error(get_string('filenotfound', 'error'), $CFG->wwwroot); //this is not displayed on IIS??
+ }
+?>
\ No newline at end of file