MDL-22547 course->legacyfiles switch implemented
[moodle.git] / lib / file / file_browser.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/>.
19 /**
20  * Utility class for browsing of files.
21  *
22  * @package    moodlecore
23  * @subpackage file-browser
24  * @copyright  2008 Petr Skoda (http://skodak.org)
25  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26  */
28 require_once("$CFG->libdir/file/file_info.php");
29 require_once("$CFG->libdir/file/file_info_module.php");
30 require_once("$CFG->libdir/file/file_info_stored.php");
31 require_once("$CFG->libdir/file/file_info_system.php");
32 require_once("$CFG->libdir/file/file_info_user.php");
33 require_once("$CFG->libdir/file/file_info_coursecat.php");
34 require_once("$CFG->libdir/file/file_info_course.php");
35 require_once("$CFG->libdir/file/file_info_coursesection.php");
36 require_once("$CFG->libdir/file/file_info_coursesectionbackup.php");
37 require_once("$CFG->libdir/file/file_info_coursefile.php");
38 require_once("$CFG->libdir/file/virtual_root_file.php");
40 /**
41  * This class provides the main entry point for other code wishing to get
42  * information about files.
43  *
44  * The whole file storage for a Moodle site can be seen as a huge virtual tree.
45  * The spine of the tree is the tree of contexts (system, course-categories,
46  * courses, modules, also users). Then, within each context, there may be any number of
47  * file areas, and a file area contains folders and files. The various file_info
48  * subclasses return info about the things in this tree. They should be obtained
49  * from an instance of this class.
50  *
51  * This virtual tree is different for each user depending of his/her current permissions.
52  * Some branches such as draft areas are hidden, but accessible.
53  *
54  * Always use this abstraction when you need to access module files from core code.
55  */
56 class file_browser {
58     /**
59      * Looks up file_info instance
60      * @param object $context
61      * @param string $filearea
62      * @param int $itemid
63      * @param string $filepath
64      * @param string $filename
65      * @return file_info instance or null if not found or access not allowed
66      */
67     public function get_file_info($context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
68         switch ($context->contextlevel) {
69             case CONTEXT_SYSTEM:
70                 return $this->get_file_info_system($context, $filearea, $itemid, $filepath, $filename);
71             case CONTEXT_USER:
72                 return $this->get_file_info_user($context, $filearea, $itemid, $filepath, $filename);
73             case CONTEXT_COURSECAT:
74                 return $this->get_file_info_coursecat($context, $filearea, $itemid, $filepath, $filename);
75             case CONTEXT_COURSE:
76                 return $this->get_file_info_course($context, $filearea, $itemid, $filepath, $filename);
77             case CONTEXT_MODULE:
78                 return $this->get_file_info_module($context, $filearea, $itemid, $filepath, $filename);
79         }
81         return null;
82     }
84     /**
85      * Returns info about the files at System context
86      * @param object $context
87      * @param string $filearea
88      * @return file_info_system
89      */
90     private function get_file_info_system($context, $filearea=null) {
91         if (is_null($filearea)) {
92             return new file_info_system($this);
93         }
94         //TODO: question files browsing
96         return null;
97     }
99     /**
100      * Returns info about the files at User context
101      * @param object $context
102      * @param string $filearea
103      * @return file_info_system
104      */
105     private function get_file_info_user($context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
106         global $USER, $DB;
107         if ($context->instanceid == $USER->id) {
108             $user = $USER;
109         } else {
110             $user = $DB->get_record('user', array('id'=>$context->instanceid));
111         }
113         if (isguestuser($user) or empty($user->id)) {
114             // no guests or not logged in users here
115             return null;
116         }
118         if ($user->deleted) {
119             return null;
120         }
122         if (is_null($filearea)) {
123             // access control: list areas only for myself
124             if ($context->instanceid != $USER->id) {
125                 return null;
126             }
128             return new file_info_user($this, $context);
130         } else {
131             $methodname = "get_file_info_$filearea";
132             if (method_exists($this, $methodname)) {
133                 return $this->$methodname($user, $context, $filearea, $itemid, $filepath, $filename);
134             }
135         }
137         return null;
138     }
140     private function get_file_info_user_private($user, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
141         global $USER, $CFG;
143         $fs = get_file_storage();
145         // access control: only my files for now, nobody else
146         if ($context->instanceid != $USER->id) {
147             return null;
148         }
150         if (is_null($itemid)) {
151             return new file_info_user($this, $context);
152         }
153         $filepath = is_null($filepath) ? '/' : $filepath;
154         $filename = is_null($filename) ? '.' : $filename;
156         if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
157             if ($filepath === '/' and $filename === '.') {
158                 $storedfile = new virtual_root_file($context->id, $filearea, 0);
159             } else {
160                 // not found
161                 return null;
162             }
163         }
164         $urlbase = $CFG->wwwroot.'/userfile.php';
165         return new file_info_stored($this, $context, $storedfile, $urlbase, get_string('areauserpersonal', 'repository'), false, true, true, false);
166     }
168     private function get_file_info_user_profile($user, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
169         global $USER, $CFG;
171         $fs = get_file_storage();
173         if (is_null($itemid)) {
174             return new file_info_user($this, $context);
175         }
177         // access controll here must match user edit forms
178         if ($user->id == $USER->id) {
179              if (!has_capability('moodle/user:editownprofile', get_context_instance(CONTEXT_SYSTEM))) {
180                 return null;
181              }
182         } else {
183             if (!has_capability('moodle/user:editprofile', $context) and !has_capability('moodle/user:update', $context)) {
184                 return null;
185             }
186         }
188         $filepath = is_null($filepath) ? '/' : $filepath;
189         $filename = is_null($filename) ? '.' : $filename;
191         if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
192             if ($filepath === '/' and $filename === '.') {
193                 $storedfile = new virtual_root_file($context->id, $filearea, 0);
194             } else {
195                 // not found
196                 return null;
197             }
198         }
199         $urlbase = $CFG->wwwroot.'/userfile.php';
200         return new file_info_stored($this, $context, $storedfile, $urlbase, get_string('areauserprofile', 'repository'), false, true, true, false);
201     }
203     private function get_file_info_user_draft($user, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
204         global $USER, $CFG;
206         $fs = get_file_storage();
208         // access control: only my files
209         if ($context->instanceid != $USER->id) {
210             return null;
211         }
213         if (empty($itemid)) {
214             // do not browse itemids - you most know the draftid to see what is there
215             return null;
216         }
217         $urlbase = $CFG->wwwroot.'/draftfile.php';
219         $filepath = is_null($filepath) ? '/' : $filepath;
220         $filename = is_null($filename) ? '.' : $filename;
222         if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
223             if ($filepath === '/' and $filename === '.') {
224                 $storedfile = new virtual_root_file($context->id, $filearea, $itemid);
225             } else {
226                 // not found
227                 return null;
228             }
229         }
230         return new file_info_stored($this, $context, $storedfile, $urlbase, get_string('areauserdraft', 'repository'), true, true, true, true);
231     }
233     private function get_file_info_user_backup($user, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
234         global $USER, $CFG;
236         $fs = get_file_storage();
238         // only current user can access this area
239         if ($context->instanceid != $USER->id) {
240             return null;
241         }
242         if ($USER->id != $user->id) {
243             return null;
244         }
246         $urlbase = $CFG->wwwroot.'/userfile.php';
248         $filepath = is_null($filepath) ? '/' : $filepath;
249         $filename = is_null($filename) ? '.' : $filename;
251         if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
252             if ($filepath === '/' and $filename === '.') {
253                 $storedfile = new virtual_root_file($context->id, $filearea, 0);
254             } else {
255                 // not found
256                 return null;
257             }
258         }
259         return new file_info_stored($this, $context, $storedfile, $urlbase, get_string('areauserbackup', 'repository'), false, true, true, false);
260     }
262     private function get_file_info_coursecat($context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
263         global $DB, $CFG;
265         $fs = get_file_storage();
267         if (!$category = $DB->get_record('course_categories', array('id'=>$context->instanceid))) {
268             return null;
269         }
271         if (!$category->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
272             return null;
273         }
275         if (!is_null($filearea) and !in_array($filearea, array('coursecat_intro'))) {
276             // file area does not exist, sorry
277             $filearea = null;
278         }
280         if (is_null($filearea) or is_null($itemid)) {
281             return new file_info_coursecat($this, $context, $category);
283         } else {
284             if ($filearea == 'coursecat_intro') {
285                 if (!has_capability('moodle/course:update', $context)) {
286                     return null;
287                 }
289                 $filepath = is_null($filepath) ? '/' : $filepath;
290                 $filename = is_null($filename) ? '.' : $filename;
292                 $urlbase = $CFG->wwwroot.'/pluginfile.php';
293                 if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
294                     if ($filepath === '/' and $filename === '.') {
295                         $storedfile = new virtual_root_file($context->id, $filearea, 0);
296                     } else {
297                         // not found
298                         return null;
299                     }
300                 }
301                 return new file_info_stored($this, $context, $storedfile, $urlbase, get_string('areacategoryintro', 'repository'), false, true, true, false);
302             }
303         }
305         return null;
306     }
308     private function get_file_info_course($context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
309         global $DB, $COURSE;
311         if ($context->instanceid == $COURSE->id) {
312             $course = $COURSE;
313         } else if (!$course = $DB->get_record('course', array('id'=>$context->instanceid))) {
314             return null;
315         }
317         if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
318             return null;
319         }
321         if (!is_null($filearea) and !in_array($filearea, array('course_intro', 'course_content', 'course_section', 'course_backup', 'section_backup'))) {
322             // file area does not exist, sorry
323             $filearea = null;
324         }
326         if ($filearea === 'course_content' and $course->legacyfiles != 2) {
327             // bad luck, legacy course files not used any more
328             return null;
329         }
331         $filepath = is_null($filepath) ? '/' : $filepath;
332         $filename = is_null($filename) ? '.' : $filename;
334         if (is_null($filearea)) {
335             return new file_info_course($this, $context, $course);
337         } else {
338             $methodname = "get_file_info_$filearea";
339             if (method_exists($this, $methodname)) {
340                 return $this->$methodname($course, $context, $filearea, $itemid, $filepath, $filename);
341             }
342         }
344         return null;
345     }
347     private function get_file_info_course_intro($course, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
348         global $CFG;
350         $fs = get_file_storage();
352         if (!has_capability('moodle/course:update', $context)) {
353             return null;
354         }
355         if (is_null($itemid)) {
356             return new file_info_course($this, $context, $course);
357         }
359         $urlbase = $CFG->wwwroot.'/pluginfile.php';
360         if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
361             if ($filepath === '/' and $filename === '.') {
362                 $storedfile = new virtual_root_file($context->id, $filearea, 0);
363             } else {
364                 // not found
365                 return null;
366             }
367         }
368         return new file_info_stored($this, $context, $storedfile, $urlbase, get_string('areacourseintro', 'repository'), false, true, true, false);
370     }
372     private function get_file_info_course_section($course, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
373         global $CFG, $DB;
375         $fs = get_file_storage();
377         if (!has_capability('moodle/course:update', $context)) {
378             return null;
379         }
380         $urlbase = $CFG->wwwroot.'/pluginfile.php';
382         if (empty($itemid)) {
383             // list all sections
384             return new file_info_coursesection($this, $context, $course);
385         }
387         if (!$section = $DB->get_record('course_sections', array('course'=>$course->id, 'id'=>$itemid))) {
388             return null; // does not exist
389         }
391         if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
392             if ($filepath === '/' and $filename === '.') {
393                 $storedfile = new virtual_root_file($context->id, $filearea, $itemid);
394             } else {
395                 // not found
396                 return null;
397             }
398         }
399         return new file_info_stored($this, $context, $storedfile, $urlbase, $section->section, true, true, true, false);
401     }
403     private function get_file_info_course_backup($course, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
404         global $CFG;
406         $fs = get_file_storage();
408         if (!has_capability('moodle/backup:backupcourse', $context) and !has_capability('moodle/restore:restorecourse', $context)) {
409             return null;
410         }
411         if (is_null($itemid)) {
412             return new file_info_course($this, $context, $course);
413         }
415         $urlbase = $CFG->wwwroot.'/pluginfile.php';
416         if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
417             if ($filepath === '/' and $filename === '.') {
418                 $storedfile = new virtual_root_file($context->id, $filearea, 0);
419             } else {
420                 // not found
421                 return null;
422             }
423         }
425         $downloadable = has_capability('moodle/backup:downloadfile', $context);
426         $uploadable   = has_capability('moodle/restore:uploadfile', $context);
427         return new file_info_stored($this, $context, $storedfile, $urlbase, get_string('coursebackup', 'repository'), false, $downloadable, $uploadable, false);
429     }
431     private function get_file_info_section_backup($course, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
432         global $CFG, $DB;
434         $fs = get_file_storage();
435         if (empty($itemid)) {
436             // list all sections
437             return new file_info_coursesectionbackup($this, $context, $course);
438         }
440         if (!has_capability('moodle/backup:backupcourse', $context) and !has_capability('moodle/restore:restorecourse', $context)) {
441             return null;
442         }
444         if (!$section = $DB->get_record('course_sections', array('course'=>$course->id, 'id'=>$itemid))) {
445             return null; // does not exist
446         }
449         $urlbase = $CFG->wwwroot.'/pluginfile.php';
450         if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
451             if ($filepath === '/' and $filename === '.') {
452                 $storedfile = new virtual_root_file($context->id, $filearea, $itemid);
453             } else {
454                 // not found
455                 return null;
456             }
457         }
459         $downloadable = has_capability('moodle/backup:downloadfile', $context);
460         $uploadable   = has_capability('moodle/restore:uploadfile', $context);
461         return new file_info_stored($this, $context, $storedfile, $urlbase, $section->id, true, $downloadable, $uploadable, false);
462     }
464     private function get_file_info_course_content($course, $context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
465         $fs = get_file_storage();
467         if (!has_capability('moodle/course:managefiles', $context)) {
468             return null;
469         }
470         if (is_null($itemid)) {
471             return new file_info_course($this, $context, $course);
472         }
474         if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
475             if ($filepath === '/' and $filename === '.') {
476                 $storedfile = new virtual_root_file($context->id, $filearea, 0);
477             } else {
478                 // not found
479                 return null;
480             }
481         }
483         return new file_info_coursefile($this, $context, $storedfile);
484     }
486     private function get_file_info_module($context, $filearea=null, $itemid=null, $filepath=null, $filename=null) {
487         global $COURSE, $DB, $CFG;
489         $fs = get_file_storage();
491         if (!$cm = get_coursemodule_from_id('', $context->instanceid)) {
492             return null;
493         }
495         if ($cm->course == $COURSE->id) {
496             $course = $COURSE;
497         } else if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
498             return null;
499         }
501         $modinfo = get_fast_modinfo($course);
503         if (empty($modinfo->cms[$cm->id]->uservisible)) {
504             return null;
505         }
507         $modname = $modinfo->cms[$cm->id]->modname;
509         $libfile = "$CFG->dirroot/mod/$modname/lib.php";
510         if (!file_exists($libfile)) {
511             return null;
512         }
513         require_once($libfile);
515         $fileinfofunction = $modname.'_get_file_areas';
516         if (function_exists($fileinfofunction)) {
517             $areas = $fileinfofunction($course, $cm, $context);
518         } else {
519             $areas = array();
520         }
521         if (!isset($areas[$modname.'_intro'])
522           and plugin_supports('mod', $modname, FEATURE_MOD_INTRO, true)
523           and has_capability('moodle/course:managefiles', $context)) {
524             $areas = array_merge(array($modname.'_intro'=>get_string('moduleintro')), $areas);
525         }
527         if (has_capability('moodle/backup:downloadfile', $context)) {
528             $areas = array_merge(array('activity_backup'=>get_string('activitybackup', 'repository')), $areas);
529         }
531         if (empty($areas)) {
532             return null;
533         }
535         if ($filearea === $modname.'_intro' || $filearea === 'activity_backup') {
536             // always only itemid 0
537             if (!has_capability('moodle/course:managefiles', $context)) {
538                 return null;
539             }
540             // need downloadfile cap when accessing activity_backup area
541             if ($filearea === 'activity_backup' && !has_capability('moodle/backup:downloadfile', $context)) {
542                 return null;
543             }
545             $filepath = is_null($filepath) ? '/' : $filepath;
546             $filename = is_null($filename) ? '.' : $filename;
548             $urlbase = $CFG->wwwroot.'/pluginfile.php';
549             if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
550                 if ($filepath === '/' and $filename === '.') {
551                     $storedfile = new virtual_root_file($context->id, $filearea, 0);
552                 } else {
553                     // not found
554                     return null;
555                 }
556             }
557             return new file_info_stored($this, $context, $storedfile, $urlbase, $areas[$filearea], false, true, true, false);
559         } else if (is_null($filearea)) {
560             // modules have to decide if they want to use itemids
561             return new file_info_module($this, $course, $cm, $context, $areas);
563         } else if (!array_key_exists($filearea, $areas)) {
564             return null;
566         } else {
567             $fileinfofunction = $modname.'_get_file_info';
568             if (function_exists($fileinfofunction)) {
569                 return $fileinfofunction($this, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename);
570             }
571         }
573         return null;
574     }