MDL-15901 completion disabled by default
[moodle.git] / file.php
CommitLineData
e7f927a0 1<?php // $Id$
2 // This script fetches files from the dataroot directory
5a254a29 3 //
4 // You should use the get_file_url() function, available in lib/filelib.php, to link to file.php.
5 // This ensures proper formatting and offers useful options.
6 //
e7f927a0 7 // Syntax: file.php/courseid/dir/dir/dir/filename.ext
69faecce 8 // file.php/courseid/dir/dir/dir/filename.ext?forcedownload=1 (download instead of inline)
e7f927a0 9 // file.php/courseid/dir (returns index.html from dir)
10 // Workaround: file.php?file=/courseid/dir/dir/dir/filename.ext
48283ff6 11 // Test: file.php/testslasharguments
e7f927a0 12
feaf5d06 13
14 //TODO: Blog attachments do not have access control implemented - anybody can read them!
15 // It might be better to move the code to separate file because the access
16 // control is quite complex - see bolg/index.php
17
822a1063 18 require_once('config.php');
4d68dff4 19 require_once('lib/filelib.php');
f9903ed0 20
f44762bd 21 if (!isset($CFG->filelifetime)) {
e7f927a0 22 $lifetime = 86400; // Seconds for files to remain in caches
6ed3da1d 23 } else {
e7f927a0 24 $lifetime = $CFG->filelifetime;
2464c592 25 }
26
7eb0b60a 27 // disable moodle specific debug messages
28 disable_debugging();
3f8247c2 29
e7f927a0 30 $relativepath = get_file_argument('file.php');
69faecce 31 $forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
e7f927a0 32
33 // relative path must start with '/', because of backup/restore!!!
34 if (!$relativepath) {
33aa5723 35 print_error('invalidargorconf');
e7f927a0 36 } else if ($relativepath{0} != '/') {
33aa5723 37 print_error('pathdoesnotstartslash');
f9903ed0 38 }
39
e7f927a0 40 $pathname = $CFG->dataroot.$relativepath;
ae67d9cd 41
e7f927a0 42 // extract relative path components
43 $args = explode('/', trim($relativepath, '/'));
44 if (count($args) == 0) { // always at least courseid, may search for index.html in course root
33aa5723 45 print_error('invalidarguments');
55b8ac31 46 }
7d0e5a95 47
e7f927a0 48 // security: limit access to existing course subdirectories
f33e1ed4 49 if (($args[0]!='blog') and (!$course = $DB->get_record_sql("SELECT * FROM {course} WHERE id=?", array((int)$args[0])))) {
33aa5723 50 print_error('invalidcourseid');
a4557331 51 }
52
e7f927a0 53 // security: prevent access to "000" or "1 something" directories
7d0e5a95 54 // hack for blogs, needs proper security check too
feaf5d06 55 if (($args[0] != 'blog') and ($args[0] != $course->id)) {
33aa5723 56 print_error('invalidcourseid');
76112421 57 }
21ddaf60 58
e7f927a0 59 // security: login to course if necessary
f4013c10 60 // Note: file.php always calls require_login() with $setwantsurltome=false
61 // in order to avoid messing redirects. MDL-14495
feaf5d06 62 if ($args[0] == 'blog') {
63 if (empty($CFG->bloglevel)) {
33aa5723 64 print_error('blogdisable', 'blog');
feaf5d06 65 } else if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL) {
f4013c10 66 require_login(0, true, null, false);
feaf5d06 67 } else if ($CFG->forcelogin) {
f4013c10 68 require_login(0, true, null, false);
feaf5d06 69 }
70 } else if ($course->id != SITEID) {
f4013c10 71 require_login($course->id, true, null, false);
f57cd38b 72 } else if ($CFG->forcelogin) {
90a32fd5 73 if (!empty($CFG->sitepolicy)
74 and ($CFG->sitepolicy == $CFG->wwwroot.'/file.php'.$relativepath
75 or $CFG->sitepolicy == $CFG->wwwroot.'/file.php?file='.$relativepath)) {
76 //do not require login for policy file
77 } else {
f4013c10 78 require_login(0, true, null, false);
90a32fd5 79 }
f9903ed0 80 }
81
e7f927a0 82 // security: only editing teachers can access backups
de9a33f3 83 if ((count($args) >= 2) and (strtolower($args[1]) == 'backupdata')) {
84 if (!has_capability('moodle/site:backup', get_context_instance(CONTEXT_COURSE, $course->id))) {
33aa5723 85 print_error('nopermissions');
de9a33f3 86 } else {
87 $lifetime = 0; //disable browser caching for backups
88 }
e7f927a0 89 }
f9903ed0 90
e7f927a0 91 if (is_dir($pathname)) {
92 if (file_exists($pathname.'/index.html')) {
93 $pathname = rtrim($pathname, '/').'/index.html';
94 $args[] = 'index.html';
95 } else if (file_exists($pathname.'/index.htm')) {
96 $pathname = rtrim($pathname, '/').'/index.htm';
97 $args[] = 'index.htm';
98 } else if (file_exists($pathname.'/Default.htm')) {
99 $pathname = rtrim($pathname, '/').'/Default.htm';
100 $args[] = 'Default.htm';
101 } else {
102 // security: do not return directory node!
103 not_found($course->id);
104 }
105 }
3cf4ab97 106
fd05dffe 107 // security: teachers can view all assignments, students only their own
108 if ((count($args) >= 3)
109 and (strtolower($args[1]) == 'moddata')
110 and (strtolower($args[2]) == 'assignment')) {
111
112 $lifetime = 0; // do not cache assignments, students may reupload them
9da3dfa4 113 if ($args[4] == $USER->id) {
114 //can view own assignemnt submissions
115 } else {
116 $instance = (int)$args[3];
117 if (!$cm = get_coursemodule_from_instance('assignment', $instance, $course->id)) {
118 not_found($course->id);
119 }
120 if (!has_capability('mod/assignment:grade', get_context_instance(CONTEXT_MODULE, $cm->id))) {
121 print_error('nopermissions');
122 }
123 }
fd05dffe 124 }
125
69faecce 126 // security: force download of all attachments submitted by students
127 if ((count($args) >= 3)
128 and (strtolower($args[1]) == 'moddata')
129 and ((strtolower($args[2]) == 'forum')
130 or (strtolower($args[2]) == 'assignment')
3d050945 131 or (strtolower($args[2]) == 'data')
69faecce 132 or (strtolower($args[2]) == 'glossary')
133 or (strtolower($args[2]) == 'wiki')
134 or (strtolower($args[2]) == 'exercise')
135 or (strtolower($args[2]) == 'workshop')
136 )) {
137 $forcedownload = 1; // force download of all attachments
138 }
feaf5d06 139 if ($args[0] == 'blog') {
140 $forcedownload = 1; // force download of all attachments
141 }
69faecce 142
fd05dffe 143 // security: some protection of hidden resource files
144 // warning: it may break backwards compatibility
fd05dffe 145 if ((!empty($CFG->preventaccesstohiddenfiles))
146 and (count($args) >= 2)
0cd482e5 147 and (!(strtolower($args[1]) == 'moddata' and strtolower($args[2]) != 'resource')) // do not block files from other modules!
c5a3467a 148 and (!has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_COURSE, $course->id)))) {
fd05dffe 149
0cd482e5 150 $rargs = $args;
151 array_shift($rargs);
152 $reference = implode('/', $rargs);
fd05dffe 153
f33e1ed4 154 $sql = "SELECT COUNT(r.id)
155 FROM {resource} r, {course_modules} cm, {modules} m
156 WHERE r.course = ?
157 AND m.name = 'resource'
158 AND cm.module = m.id
159 AND cm.instance = r.id
160 AND cm.visible = 0
161 AND r.type = 'file'
162 AND r.reference = ?";
163 $params = array($course->id, $reference);
164
165 if ($DB->count_records_sql($sql, $params)) {
33aa5723 166 print_error('nopermissions');
fd05dffe 167 }
168 }
169
e7f927a0 170 // check that file exists
171 if (!file_exists($pathname)) {
172 not_found($course->id);
173 }
e5890e71 174
e7f927a0 175 // ========================================
176 // finally send the file
177 // ========================================
2ea55bc0 178 session_write_close(); // unlock session during fileserving
e7f927a0 179 $filename = $args[count($args)-1];
b9709b76 180 send_file($pathname, $filename, $lifetime, $CFG->filteruploadedfiles, false, $forcedownload);
e7f927a0 181
182 function not_found($courseid) {
183 global $CFG;
822a1063 184 header('HTTP/1.0 404 not found');
5a2a5331 185 print_error('filenotfound', 'error', $CFG->wwwroot.'/course/view.php?id='.$courseid); //this is not displayed on IIS??
f9903ed0 186 }
e7f927a0 187?>