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