5cf165e6f8aa3f367e753435ea1eb23787967916
[moodle.git] / lib / filebrowser / file_info_stored.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 stored files.
21  *
22  * @package    core
23  * @subpackage filebrowser
24  * @copyright  2008 Petr Skoda (http://skodak.org)
25  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26  */
28 defined('MOODLE_INTERNAL') || die();
30 /**
31  * Represents an actual file or folder - a row in the file table -
32  * in the tree navigated by @see{file_browser}.
33  *
34  * @package    core
35  * @subpackage filebrowser
36  * @copyright  2008 Petr Skoda (http://skodak.org)
37  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class file_info_stored extends file_info {
40     protected $lf;
41     protected $urlbase;
42     protected $topvisiblename;
43     protected $itemidused;
44     protected $readaccess;
45     protected $writeaccess;
46     protected $areaonly;
48     /**
49      * Constructor
50      *
51      * @param file_browser $browser
52      * @param object $context
53      * @param stored_file $storedfile
54      * @param string $urlbase the serving script - usually the $CFG->wwwroot/.'pluginfile.php'
55      * @param string $topvisiblename the human readable name of this area
56      * @param string $itemidused false if itemid  always 0 and not included in URL
57      * @param string $readaccess allow file reading
58      * @param string $writeaccess allow file write, delete
59      * @param string $areaonly do not show links to parent context/area
60      */
61     public function __construct(file_browser $browser, $context, $storedfile, $urlbase, $topvisiblename, $itemidused, $readaccess, $writeaccess, $areaonly) {
62         parent::__construct($browser, $context);
64         $this->lf             = $storedfile;
65         $this->urlbase        = $urlbase;
66         $this->topvisiblename = $topvisiblename;
67         $this->itemidused     = $itemidused;
68         $this->readaccess     = $readaccess;
69         $this->writeaccess    = $writeaccess;
70         $this->areaonly       = $areaonly;
71     }
73     /**
74      * Returns list of standard virtual file/directory identification.
75      * The difference from stored_file parameters is that null values
76      * are allowed in all fields
77      * @return array with keys contextid, component, filearea, itemid, filepath and filename
78      */
79     public function get_params() {
80         return array('contextid'=>$this->context->id,
81                      'component' =>$this->lf->get_component(),
82                      'filearea' =>$this->lf->get_filearea(),
83                      'itemid'   =>$this->lf->get_itemid(),
84                      'filepath' =>$this->lf->get_filepath(),
85                      'filename' =>$this->lf->get_filename());
86     }
88     /**
89      * Returns localised visible name.
90      * @return string
91      */
92     public function get_visible_name() {
93         $filename = $this->lf->get_filename();
94         $filepath = $this->lf->get_filepath();
96         if ($filename !== '.') {
97             return $filename;
99         } else {
100             $dir = trim($filepath, '/');
101             $dir = explode('/', $dir);
102             $dir = array_pop($dir);
103             if ($dir === '') {
104                 return $this->topvisiblename;
105             } else {
106                 return $dir;
107             }
108         }
109     }
111     /**
112      * Returns file download url
113      * @param bool $forcedownload
114      * @param bool $htts force https
115      * @return string url
116      */
117     public function get_url($forcedownload=false, $https=false) {
118         if (!$this->is_readable()) {
119             return null;
120         }
122         if ($this->is_directory()) {
123             return null;
124         }
126         $this->urlbase;
127         $contextid = $this->lf->get_contextid();
128         $component = $this->lf->get_component();
129         $filearea  = $this->lf->get_filearea();
130         $filepath  = $this->lf->get_filepath();
131         $filename  = $this->lf->get_filename();
132         $itemid    = $this->lf->get_itemid();
134         if ($this->itemidused) {
135             $path = '/'.$contextid.'/'.$component.'/'.$filearea.'/'.$itemid.$filepath.$filename;
136         } else {
137             $path = '/'.$contextid.'/'.$component.'/'.$filearea.$filepath.$filename;
138         }
139         return file_encode_url($this->urlbase, $path, $forcedownload, $https);
140     }
142     /**
143      * Can I read content of this file or enter directory?
144      * @return bool
145      */
146     public function is_readable() {
147         return $this->readaccess;
148     }
150     /**
151      * Can I add new files or directories?
152      * @return bool
153      */
154     public function is_writable() {
155         return $this->writeaccess;
156     }
158     /**
159      * Returns file size in bytes, null for directories
160      * @return int bytes or null if not known
161      */
162     public function get_filesize() {
163         return $this->lf->get_filesize();
164     }
166     /**
167      * Returns mimetype
168      * @return string mimetype or null if not known
169      */
170     public function get_mimetype() {
171         return $this->lf->get_mimetype();
172     }
174     /**
175      * Returns time created unix timestamp if known
176      * @return int timestamp or null
177      */
178     public function get_timecreated() {
179         return $this->lf->get_timecreated();
180     }
182     /**
183      * Returns time modified unix timestamp if known
184      * @return int timestamp or null
185      */
186     public function get_timemodified() {
187         return $this->lf->get_timemodified();
188     }
190     /**
191      * Is directory?
192      * @return bool
193      */
194     public function is_directory() {
195         return $this->lf->is_directory();
196     }
198     /**
199      * Returns the license type of the file
200      * @return string license short name or null
201      */
202     public function get_license() {
203         return $this->lf->get_license();
204     }
206     /**
207      * Returns the author name of the file
208      * @return string author name or null
209      */
210     public function get_author() {
211         return $this->lf->get_author();
212     }
214     /**
215      * Returns the source of the file
216      * @return string a source url or null
217      */
218     public function get_source() {
219         return $this->lf->get_source();
220     }
222     /**
223      * Returns the sort order of the file
224      * @return int
225      */
226     public function get_sortorder() {
227         return $this->lf->get_sortorder();
228     }
230     /**
231      * Returns list of children.
232      * @return array of file_info instances
233      */
234     public function get_children() {
235         if (!$this->lf->is_directory()) {
236             return array();
237         }
239         $result = array();
240         $fs = get_file_storage();
242         $storedfiles = $fs->get_directory_files($this->context->id, $this->lf->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(),
243                                                 $this->lf->get_filepath(), false, true, "filepath, filename");
244         foreach ($storedfiles as $file) {
245             $result[] = new file_info_stored($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
246                                              $this->itemidused, $this->readaccess, $this->writeaccess, false);
247         }
249         return $result;
250     }
252     /**
253      * Returns parent file_info instance
254      * @return file_info or null for root
255      */
256     public function get_parent() {
257         if ($this->lf->get_filepath() === '/' and $this->lf->is_directory()) {
258             if ($this->areaonly) {
259                 return null;
260             } else if ($this->itemidused) {
261                 return $this->browser->get_file_info($this->context, $this->lf->get_component(), $this->lf->get_filearea());
262             } else {
263                 return $this->browser->get_file_info($this->context);
264             }
265         }
267         if (!$this->lf->is_directory()) {
268             return $this->browser->get_file_info($this->context, $this->lf->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(), $this->lf->get_filepath(), '.');
269         }
271         $filepath = $this->lf->get_filepath();
272         $filepath = trim($filepath, '/');
273         $dirs = explode('/', $filepath);
274         array_pop($dirs);
275         $filepath = implode('/', $dirs);
276         $filepath = ($filepath === '') ? '/' : "/$filepath/";
278         return $this->browser->get_file_info($this->context, $this->lf->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(), $filepath, '.');
279     }
281     /**
282      * Create new directory, may throw exception - make sure
283      * params are valid.
284      * @param string $newdirname name of new directory
285      * @param int id of author, default $USER->id
286      * @return file_info new directory
287      */
288     public function create_directory($newdirname, $userid = NULL) {
289         if (!$this->is_writable() or !$this->lf->is_directory()) {
290             return null;
291         }
293         $newdirname = clean_param($newdirname, PARAM_FILE);
294         if ($newdirname === '') {
295             return null;
296         }
298         $filepath = $this->lf->get_filepath().'/'.$newdirname.'/';
300         $fs = get_file_storage();
302         if ($file = $fs->create_directory($this->lf->get_contextid(), $this->lf->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(), $filepath, $userid)) {
303             return $this->browser->get_file_info($this->context, $this->lf->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
304         }
305         return null;
306     }
309     /**
310      * Create new file from string - make sure
311      * params are valid.
312      * @param string $newfilename name of new file
313      * @param string $content of file
314      * @param int id of author, default $USER->id
315      * @return file_info new file
316      */
317     public function create_file_from_string($newfilename, $content, $userid = NULL) {
318         if (!$this->is_writable() or !$this->lf->is_directory()) {
319             return null;
320         }
322         $newfilename = clean_param($newfilename, PARAM_FILE);
323         if ($newfilename === '') {
324             return null;
325         }
327         $fs = get_file_storage();
329         $now = time();
331         $newrecord = new object();
332         $newrecord->contextid = $this->lf->get_contextid();
333         $newrecord->component = $this->lf->get_component();
334         $newrecord->filearea  = $this->lf->get_filearea();
335         $newrecord->itemid    = $this->lf->get_itemid();
336         $newrecord->filepath  = $this->lf->get_filepath();
337         $newrecord->filename  = $newfilename;
339         if ($fs->file_exists($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->filename)) {
340             // file already exists, sorry
341             return null;
342         }
344         $newrecord->timecreated  = $now;
345         $newrecord->timemodified = $now;
346         $newrecord->mimetype     = mimeinfo('type', $newfilename);
347         $newrecord->userid       = $userid;
349         if ($file = $fs->create_file_from_string($newrecord, $content)) {
350             return $this->browser->get_file_info($this->context, $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
351         }
352         return null;
353     }
355     /**
356      * Create new file from pathname - make sure
357      * params are valid.
358      * @param string $newfilename name of new file
359      * @param string $pathname location of file
360      * @param int id of author, default $USER->id
361      * @return file_info new file
362      */
363     public function create_file_from_pathname($newfilename, $pathname, $userid = NULL) {
364         if (!$this->is_writable() or !$this->lf->is_directory()) {
365             return null;
366         }
368         $newfilename = clean_param($newfilename, PARAM_FILE);
369         if ($newfilename === '') {
370             return null;
371         }
373         $fs = get_file_storage();
375         $now = time();
377         $newrecord = new object();
378         $newrecord->contextid = $this->lf->get_contextid();
379         $newrecord->component = $this->lf->get_component();
380         $newrecord->filearea  = $this->lf->get_filearea();
381         $newrecord->itemid    = $this->lf->get_itemid();
382         $newrecord->filepath  = $this->lf->get_filepath();
383         $newrecord->filename  = $newfilename;
385         if ($fs->file_exists($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->filename)) {
386             // file already exists, sorry
387             return null;
388         }
390         $newrecord->timecreated  = $now;
391         $newrecord->timemodified = $now;
392         $newrecord->mimetype     = mimeinfo('type', $newfilename);
393         $newrecord->userid       = $userid;
395         if ($file = $fs->create_file_from_pathname($newrecord, $pathname)) {
396             return $this->browser->get_file_info($this->context, $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
397         }
398         return null;
399     }
401     /**
402      * Create new file from stored file - make sure
403      * params are valid.
404      * @param string $newfilename name of new file
405      * @param mixed dile id or stored_file of file
406      * @param int id of author, default $USER->id
407      * @return file_info new file
408      */
409     public function create_file_from_storedfile($newfilename, $fid, $userid = NULL) {
410         if (!$this->is_writable() or $this->lf->get_filename() !== '.') {
411             return null;
412         }
414         $newfilename = clean_param($newfilename, PARAM_FILE);
415         if ($newfilename === '') {
416             return null;
417         }
419         $fs = get_file_storage();
421         $now = time();
423         $newrecord = new object();
424         $newrecord->contextid = $this->lf->get_contextid();
425         $newrecord->component = $this->lf->get_component();
426         $newrecord->filearea  = $this->lf->get_filearea();
427         $newrecord->itemid    = $this->lf->get_itemid();
428         $newrecord->filepath  = $this->lf->get_filepath();
429         $newrecord->filename  = $newfilename;
431         if ($fs->file_exists($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->filename)) {
432             // file already exists, sorry
433             return null;
434         }
436         $newrecord->timecreated  = $now;
437         $newrecord->timemodified = $now;
438         $newrecord->mimetype     = mimeinfo('type', $newfilename);
439         $newrecord->userid       = $userid;
441         if ($file = $fs->create_file_from_storedfile($newrecord, $fid)) {
442             return $this->browser->get_file_info($this->context, $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
443         }
444         return null;
445     }
447     /**
448      * Delete file, make sure file is deletable first.
449      * @return bool success
450      */
451     public function delete() {
452         if (!$this->is_writable()) {
453             return false;
454         }
456         if ($this->is_directory()) {
457             $filepath = $this->lf->get_filepath();
458             $fs = get_file_storage();
459             $storedfiles = $fs->get_area_files($this->context->id, $file->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(), "");
460             foreach ($storedfiles as $file) {
461                 if (strpos($file->get_filepath(), $filepath) === 0) {
462                     $file->delete();
463                 }
464             }
465         }
467         return $this->lf->delete();
468     }
470     /**
471      * Copy content of this file to local storage, overriding current file if needed.
472      * @param int $contextid
473      * @param string $filearea
474      * @param int $itemid
475      * @param string $filepath
476      * @param string $filename
477      * @return boolean success
478      */
479     public function copy_to_storage($contextid, $component, $filearea, $itemid, $filepath, $filename) {
480         if (!$this->is_readable() or $this->is_directory()) {
481             return false;
482         }
484         $fs = get_file_storage();
485         if ($existing = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) {
486             $existing->delete();
487         }
488         $file_record = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'filepath'=>$filepath, 'filename'=>$filename);
489         $fs->create_file_from_storedfile($file_record, $this->lf);
491         return true;
492     }
494     /**
495      * Copy content of this file to local storage, overriding current file if needed.
496      * @param string $pathname real local full file name
497      * @return boolean success
498      */
499     public function copy_to_pathname($pathname) {
500         if (!$this->is_readable() or $this->is_directory()) {
501             return false;
502         }
504         if (file_exists($pathname)) {
505             if (!unlink($pathname)) {
506                 return false;
507             }
508         }
510         $this->lf->copy_content_to($pathname);
512         return true;
513     }