MDL-19676 MDL-14408 MDL-8776 Blog improvements
[moodle.git] / pluginfile.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * This script delegates file serving to individual plugins
20  *
21  * @package    moodlecore
22  * @subpackage file
23  * @copyright  2008 Petr Skoda (http://skodak.org)
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 require_once('config.php');
28 require_once('lib/filelib.php');
30 // disable moodle specific debug messages
31 disable_debugging();
33 $relativepath = get_file_argument();
34 $forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
36 // relative path must start with '/'
37 if (!$relativepath) {
38     print_error('invalidargorconf');
39 } else if ($relativepath[0] != '/') {
40     print_error('pathdoesnotstartslash');
41 }
43 // extract relative path components
44 $args = explode('/', ltrim($relativepath, '/'));
46 if (count($args) == 0) { // always at least user id
47     print_error('invalidarguments');
48 }
50 $contextid = (int)array_shift($args);
51 $filearea = array_shift($args);
53 if (!$context = get_context_instance_by_id($contextid)) {
54     send_file_not_found();
55 }
56 $fs = get_file_storage();
59 if ($context->contextlevel == CONTEXT_SYSTEM) {
60     if ($filearea === 'blog_attachment' || $filearea === 'blog_post') {
62         if (empty($CFG->bloglevel)) {
63             print_error('siteblogdisable', 'blog');
64         }
65         if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL) {
66             require_login();
67             if (isguestuser()) {
68                 print_error('noguest');
69             }
70             if ($CFG->bloglevel == BLOG_USER_LEVEL) {
71                 if ($USER->id != $entry->userid) {
72                     send_file_not_found();
73                 }
74             }
75         }
76         $entryid = (int)array_shift($args);
77         if (!$entry = $DB->get_record('post', array('module'=>'blog', 'id'=>$entryid))) {
78             send_file_not_found();
79         }
80         if ('publishstate' === 'public') {
81             if ($CFG->forcelogin) {
82                 require_login();
83             }
85         } else if ('publishstate' === 'site') {
86             require_login();
87             //ok
88         } else if ('publishstate' === 'draft') {
89             require_login();
90             if ($USER->id != $entry->userid) {
91                 send_file_not_found();
92             }
93         }
95         //TODO: implement shared course and shared group access
97         $relativepath = '/'.implode('/', $args);
98         $fullpath = $context->id.$filearea.$entryid.$relativepath;
100         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
101             send_file_not_found();
102         }
104         send_stored_file($file, 10*60, 0, true); // download MUST be forced - security!
106     } else {
107         send_file_not_found();
108     }
111 } else if ($context->contextlevel == CONTEXT_USER) {
112     send_file_not_found();
115 } else if ($context->contextlevel == CONTEXT_COURSECAT) {
116     if ($filearea !== 'coursecat_intro') {
117         send_file_not_found();
118     }
120     if ($CFG->forcelogin) {
121         // no login necessary - unless login forced everywhere
122         require_login();
123     }
125     $relativepath = '/'.implode('/', $args);
126     $fullpath = $context->id.'coursecat_intro0'.$relativepath;
128     if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->get_filename() == '.') {
129         send_file_not_found();
130     }
132     session_get_instance()->write_close(); // unlock session during fileserving
133     send_stored_file($file, 60*60, 0, $forcedownload);
136 } else if ($context->contextlevel == CONTEXT_COURSE) {
137     if (!$course = $DB->get_record('course', array('id'=>$context->instanceid))) {
138         print_error('invalidcourseid');
139     }
141     if ($filearea === 'course_backup') {
142         require_login($course);
143         require_capability('moodle/site:backupdownload', $context);
145         $relativepath = '/'.implode('/', $args);
146         $fullpath = $context->id.'course_backup0'.$relativepath;
148         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
149             send_file_not_found();
150         }
152         session_get_instance()->write_close(); // unlock session during fileserving
153         send_stored_file($file, 0, 0, true);
155     } else if ($filearea === 'course_intro') {
156         if ($CFG->forcelogin) {
157             require_login();
158         }
160         $relativepath = '/'.implode('/', $args);
161         $fullpath = $context->id.'course_intro0'.$relativepath;
163         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
164             send_file_not_found();
165         }
167         session_get_instance()->write_close(); // unlock session during fileserving
168         send_stored_file($file, 60*60, 0, false); // TODO: change timeout?
170     } else if ($filearea === 'course_section') {
171         if ($CFG->forcelogin) {
172             require_login($course);
173         } else if ($course->id !== SITEID) {
174             require_login($course);
175         }
177         $sectionid = (int)array_shift($args);
179         if ($course->numsections < $sectionid) {
180             if (!has_capability('moodle/course:update', $context)) {
181                 // disable access to invisible sections if can not edit course
182                 // this is going to break some ugly hacks, but is necessary
183                 send_file_not_found();
184             }
185         }
187         $relativepath = '/'.implode('/', $args);
188         $fullpath = $context->id.'course_section'.$sectionid.$relativepath;
190         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
191             send_file_not_found();
192         }
194         session_get_instance()->write_close(); // unlock session during fileserving
195         send_stored_file($file, 60*60, 0, false); // TODO: change timeout?
197     } else if ($filearea === 'user_profile') {
198         $userid = (int)array_shift($args);
199         $usercontext = get_context_instance(CONTEXT_USER, $userid);
201         if (!empty($CFG->forceloginforprofiles)) {
202             require_login();
203             if (isguestuser()) {
204                 print_error('noguest');
205             }
207             if (!isteacherinanycourse()
208                 and !isteacherinanycourse($userid)
209                 and !has_capability('moodle/user:viewdetails', $usercontext)) {
210                 print_error('usernotavailable');
211             }
212             if (!has_capability('moodle/user:viewdetails', $context) &&
213                 !has_capability('moodle/user:viewdetails', $usercontext)) {
214                 print_error('cannotviewprofile');
215             }
216             if (!has_capability('moodle/course:view', $context, $userid, false)) {
217                 print_error('notenrolledprofile');
218             }
219             if (groups_get_course_groupmode($course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
220                 print_error('groupnotamember');
221             }
222         }
224         $relativepath = '/'.implode('/', $args);
225         $fullpath = $usercontext->id.'user_profile0'.$relativepath;
227         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
228             send_file_not_found();
229         }
231         session_get_instance()->write_close(); // unlock session during fileserving
232         send_stored_file($file, 0, 0, true); // must force download - security!
234     } else {
235         send_file_not_found();
236     }
238 } else if ($context->contextlevel == CONTEXT_MODULE) {
240     if (!$coursecontext = get_context_instance_by_id(get_parent_contextid($context))) {
241         send_file_not_found();
242     }
244     if (!$course = $DB->get_record('course', array('id'=>$coursecontext->instanceid))) {
245         send_file_not_found();
246     }
247     $modinfo = get_fast_modinfo($course);
248     if (empty($modinfo->cms[$context->instanceid])) {
249         send_file_not_found();
250     }
252     $cminfo = $modinfo->cms[$context->instanceid];
253     $modname = $cminfo->modname;
254     $libfile = "$CFG->dirroot/mod/$modname/lib.php";
255     if (!file_exists($libfile)) {
256         send_file_not_found();
257     }
259     require_once($libfile);
260     if ($filearea === $modname.'_intro') {
261         if (!plugin_supports('mod', $modname, FEATURE_MOD_INTRO, true)) {
262             send_file_not_found();
263         }
264         if (!$cminfo->uservisible) {
265             send_file_not_found();
266         }
267         // all users may access it
268         $relativepath = '/'.implode('/', $args);
269         $fullpath = $context->id.$filearea.'0'.$relativepath;
271         $fs = get_file_storage();
272         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
273             send_file_not_found();
274         }
276         $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
278         // finally send the file
279         send_stored_file($file, $lifetime, 0);
280     }
282     $filefunction = $modname.'_pluginfile';
283     if (function_exists($filefunction)) {
284         // if the function exists, it must send the file and terminate. Whatever it returns leads to "not found"
285         $filefunction($course, $cminfo, $context, $filearea, $args, $forcedownload);
286     }
288     send_file_not_found();
290 } else if ($context->contextlevel == CONTEXT_BLOCK) {
291     //not supported yet
292     send_file_not_found();
295 } else {
296     send_file_not_found();