Fixed couple bugs in query, and improved logic of querylib.
[moodle.git] / file.php
1 <?php // $Id$
2       // This script fetches files from the dataroot directory
3       // Syntax:      file.php/courseid/dir/dir/dir/filename.ext
4       //              file.php/courseid/dir/dir/dir/filename.ext?forcedownload=1 (download instead of inline)
5       //              file.php/courseid/dir (returns index.html from dir)
6       // Workaround:  file.php?file=/courseid/dir/dir/dir/filename.ext
7       // Test:        file.php/testslasharguments
9     require_once('config.php');
10     require_once('lib/filelib.php');
12     if (empty($CFG->filelifetime)) {
13         $lifetime = 86400;     // Seconds for files to remain in caches
14     } else {
15         $lifetime = $CFG->filelifetime;
16     }
17     
19     $relativepath = get_file_argument('file.php');
20     $forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
21     
22     // relative path must start with '/', because of backup/restore!!!
23     if (!$relativepath) {
24         error('No valid arguments supplied or incorrect server configuration');
25     } else if ($relativepath{0} != '/') {
26         error('No valid arguments supplied, path does not start with slash!');
27     }
29     $pathname = $CFG->dataroot.$relativepath;
31     // extract relative path components
32     $args = explode('/', trim($relativepath, '/'));
33     if (count($args) == 0) { // always at least courseid, may search for index.html in course root
34         error('No valid arguments supplied');
35     }
37     // security: limit access to existing course subdirectories
38     // note: course ID must be specified
39     // note: the lang field is needed for the course language switching hack in weblib.php
40     if (!$course = get_record_sql("SELECT id, lang FROM {$CFG->prefix}course WHERE id='".(int)$args[0]."'")) {
41         error('Invalid course ID');
42     }
44     // security: prevent access to "000" or "1 something" directories
45     if ($args[0] != $course->id) {
46         error('Invalid course ID');
47     }
49     // security: login to course if necessary
50     if ($course->id != SITEID) {
51         require_login($course->id);
52     } else if ($CFG->forcelogin) {
53         require_login();
54     }
56     // security: only editing teachers can access backups
57     if ((!has_capability('moodle/site:backup', get_context_instance(CONTEXT_COURSE, $course->id)))
58         and (count($args) >= 2)
59         and (strtolower($args[1]) == 'backupdata')) {
61         error('Access not allowed');
62     }
64     if (is_dir($pathname)) {
65         if (file_exists($pathname.'/index.html')) {
66             $pathname = rtrim($pathname, '/').'/index.html';
67             $args[] = 'index.html';
68         } else if (file_exists($pathname.'/index.htm')) {
69             $pathname = rtrim($pathname, '/').'/index.htm';
70             $args[] = 'index.htm';
71         } else if (file_exists($pathname.'/Default.htm')) {
72             $pathname = rtrim($pathname, '/').'/Default.htm';
73             $args[] = 'Default.htm';
74         } else {
75             // security: do not return directory node!
76             not_found($course->id);
77         }
78     }
80     // security: teachers can view all assignments, students only their own
81     if ((count($args) >= 3)
82         and (strtolower($args[1]) == 'moddata')
83         and (strtolower($args[2]) == 'assignment')) {
85         $lifetime = 0;  // do not cache assignments, students may reupload them
86         if ((!has_capability('mod/assignment:grade', get_context_instance(CONTEXT_COURSE, $course->id))) && (count($args) != 6 || $args[4] != $USER->id)) {
87            error('Access not allowed');
88         }
89     }
91     // security: force download of all attachments submitted by students
92     if ((count($args) >= 3)
93         and (strtolower($args[1]) == 'moddata')
94         and ((strtolower($args[2]) == 'forum')
95             or (strtolower($args[2]) == 'assignment')
96             or (strtolower($args[2]) == 'data')
97             or (strtolower($args[2]) == 'glossary')
98             or (strtolower($args[2]) == 'wiki')
99             or (strtolower($args[2]) == 'exercise')
100             or (strtolower($args[2]) == 'workshop')
101             )) {
102         $forcedownload  = 1; // force download of all attachments
103     }
105     // security: some protection of hidden resource files
106     // warning: it may break backwards compatibility
107     if ((!empty($CFG->preventaccesstohiddenfiles)) 
108         and (count($args) >= 2)
109         and (!isteacher($course->id))) {
111         $reference = ltrim($relativepath, "/{$args[0]}/");
113         $sql = "SELECT COUNT(r.id) " .
114                  "FROM {$CFG->prefix}resource r, " .
115                       "{$CFG->prefix}course_modules cm, " .
116                       "{$CFG->prefix}modules m " .
117                  "WHERE r.course    = '{$course->id}' " .
118                    "AND m.name      = 'resource' " .
119                    "AND cm.module   = m.id " .
120                    "AND cm.instance = r.id " .
121                    "AND cm.visible  = 0 " .
122                    "AND r.type      = 'file' " .
123                    "AND r.reference = '{$reference}'";
124         if (count_records_sql($sql)) {
125            error('Access not allowed');
126         }
127     }
129     // check that file exists
130     if (!file_exists($pathname)) {
131         not_found($course->id);
132     }
134     // extra security: keep symbolic links inside dataroot/courseid if required
135     /*if (!empty($CFG->checksymlinks)) {
136         $realpath = realpath($pathname);
137         $realdataroot = realpath($CFG->dataroot.'/'.$course->id);
138         if (strpos($realpath, $realdataroot) !== 0) {
139             not_found($course->id);
140         }
141     }*/
143     // ========================================
144     // finally send the file
145     // ========================================
146     session_write_close(); // unlock session during fileserving
147     $filename = $args[count($args)-1];
148     send_file($pathname, $filename, $lifetime, $CFG->filteruploadedfiles, false, $forcedownload);
150     function not_found($courseid) {
151         global $CFG;
152         header('HTTP/1.0 404 not found');
153         error(get_string('filenotfound', 'error'), $CFG->wwwroot.'/course/view.php?id='.$courseid); //this is not displayed on IIS??
154     }
155 ?>