weekly release 2.6dev
[moodle.git] / repository / filesystem / lib.php
CommitLineData
4317f92f 1<?php
10d53fd3
DC
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
67233725
DC
17/**
18 * This plugin is used to access files on server file system
19 *
20 * @since 2.0
21 * @package repository_filesystem
22 * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25require_once($CFG->dirroot . '/repository/lib.php');
26require_once($CFG->libdir . '/filelib.php');
27
fdcf5320 28/**
29 * repository_filesystem class
67233725 30 *
fdcf5320 31 * Create a repository from your local filesystem
32 * *NOTE* for security issue, we use a fixed repository path
33 * which is %moodledata%/repository
34 *
d078f6d3 35 * @package repository
67233725 36 * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
d078f6d3 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
fdcf5320 38 */
520de343 39class repository_filesystem extends repository {
67233725
DC
40
41 /**
42 * Constructor
43 *
44 * @param int $repositoryid repository ID
45 * @param int $context context ID
46 * @param array $options
47 */
447c7a19 48 public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
fdcf5320 49 global $CFG;
520de343 50 parent::__construct($repositoryid, $context, $options);
c122f484 51 $root = $CFG->dataroot . '/repository/';
873f2e0f 52 $subdir = $this->get_option('fs_path');
c122f484
FM
53
54 $this->root_path = $root;
55 if (!empty($subdir)) {
56 $this->root_path .= $subdir . '/';
57 }
58
e437618b 59 if (!empty($options['ajax'])) {
fdcf5320 60 if (!is_dir($this->root_path)) {
8512eebe 61 $created = mkdir($this->root_path, $CFG->directorypermissions, true);
520de343 62 $ret = array();
63 $ret['msg'] = get_string('invalidpath', 'repository_filesystem');
64 $ret['nosearch'] = true;
93e9aa27 65 if ($options['ajax'] && !$created) {
fdcf5320 66 echo json_encode($ret);
67 exit;
520de343 68 }
69 }
520de343 70 }
71 }
72 public function get_listing($path = '', $page = '') {
390baf46 73 global $CFG, $OUTPUT;
520de343 74 $list = array();
75 $list['list'] = array();
76 // process breacrumb trail
77 $list['path'] = array(
5bdf63cc 78 array('name'=>get_string('root', 'repository_filesystem'), 'path'=>'')
520de343 79 );
80 $trail = '';
81 if (!empty($path)) {
82 $parts = explode('/', $path);
83 if (count($parts) > 1) {
84 foreach ($parts as $part) {
4a9aff79 85 if (!empty($part)) {
86 $trail .= ('/'.$part);
87 $list['path'][] = array('name'=>$part, 'path'=>$trail);
88 }
520de343 89 }
90 } else {
91 $list['path'][] = array('name'=>$path, 'path'=>$path);
92 }
93 $this->root_path .= ($path.'/');
94 }
520de343 95 $list['manage'] = false;
520de343 96 $list['dynload'] = true;
520de343 97 $list['nologin'] = true;
520de343 98 $list['nosearch'] = true;
7355640a
MG
99 // retrieve list of files and directories and sort them
100 $fileslist = array();
101 $dirslist = array();
520de343 102 if ($dh = opendir($this->root_path)) {
103 while (($file = readdir($dh)) != false) {
104 if ( $file != '.' and $file !='..') {
7355640a
MG
105 if (is_file($this->root_path.$file)) {
106 $fileslist[] = $file;
520de343 107 } else {
7355640a 108 $dirslist[] = $file;
520de343 109 }
110 }
111 }
112 }
2f1e464a
PS
113 core_collator::asort($fileslist, core_collator::SORT_STRING);
114 core_collator::asort($dirslist, core_collator::SORT_STRING);
7355640a
MG
115 // fill the $list['list']
116 foreach ($dirslist as $file) {
117 if (!empty($path)) {
118 $current_path = $path . '/'. $file;
119 } else {
120 $current_path = $file;
121 }
122 $list['list'][] = array(
123 'title' => $file,
124 'children' => array(),
125 'datecreated' => filectime($this->root_path.$file),
126 'datemodified' => filemtime($this->root_path.$file),
127 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
128 'path' => $current_path
129 );
130 }
131 foreach ($fileslist as $file) {
132 $list['list'][] = array(
133 'title' => $file,
134 'source' => $path.'/'.$file,
135 'size' => filesize($this->root_path.$file),
136 'datecreated' => filectime($this->root_path.$file),
137 'datemodified' => filemtime($this->root_path.$file),
138 'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file, 90))->out(false),
139 'icon' => $OUTPUT->pix_url(file_extension_icon($file, 24))->out(false)
140 );
141 }
fb4ee704 142 $list['list'] = array_filter($list['list'], array($this, 'filter'));
520de343 143 return $list;
144 }
520de343 145 public function check_login() {
146 return true;
147 }
520de343 148 public function print_login() {
149 return true;
150 }
520de343 151 public function global_search() {
152 return false;
153 }
67233725 154
951d2d55
DC
155 /**
156 * Return file path
157 * @return array
158 */
520de343 159 public function get_file($file, $title = '') {
160 global $CFG;
161 if ($file{0} == '/') {
162 $file = $this->root_path.substr($file, 1, strlen($file)-1);
951d2d55
DC
163 } else {
164 $file = $this->root_path.$file;
520de343 165 }
166 // this is a hack to prevent move_to_file deleteing files
167 // in local repository
168 $CFG->repository_no_delete = true;
85b5ed5d 169 return array('path'=>$file, 'url'=>'');
520de343 170 }
171
d6453211
DC
172 /**
173 * Return the source information
174 *
175 * @param stdClass $filepath
176 * @return string|null
177 */
178 public function get_file_source_info($filepath) {
179 return $filepath;
180 }
181
520de343 182 public function logout() {
183 return true;
184 }
185
186 public static function get_instance_option_names() {
93e9aa27 187 return array('fs_path');
520de343 188 }
189
b2f8adf4 190 public function set_option($options = array()) {
191 $options['fs_path'] = clean_param($options['fs_path'], PARAM_PATH);
192 $ret = parent::set_option($options);
193 return $ret;
194 }
8e5af6cf 195
4a126f17 196 public static function instance_config_form($mform) {
49d20def 197 global $CFG, $PAGE;
0601e0ee 198 if (has_capability('moodle/site:config', context_system::instance())) {
49d20def
DC
199 $path = $CFG->dataroot . '/repository/';
200 if (!is_dir($path)) {
8512eebe 201 mkdir($path, $CFG->directorypermissions, true);
93e9aa27 202 }
49d20def
DC
203 if ($handle = opendir($path)) {
204 $fieldname = get_string('path', 'repository_filesystem');
205 $choices = array();
206 while (false !== ($file = readdir($handle))) {
207 if (is_dir($path.$file) && $file != '.' && $file!= '..') {
208 $choices[$file] = $file;
209 $fieldname = '';
210 }
211 }
212 if (empty($choices)) {
213 $mform->addElement('static', '', '', get_string('nosubdir', 'repository_filesystem', $path));
6b172cdc 214 $mform->addElement('hidden', 'fs_path', '');
8fb59b10 215 $mform->setType('fs_path', PARAM_PATH);
49d20def
DC
216 } else {
217 $mform->addElement('select', 'fs_path', $fieldname, $choices);
218 $mform->addElement('static', null, '', get_string('information','repository_filesystem', $path));
219 }
220 closedir($handle);
873f2e0f 221 }
49d20def
DC
222 } else {
223 $mform->addElement('static', null, '', get_string('nopermissions', 'error', get_string('configplugin', 'repository_filesystem')));
224 return false;
93e9aa27 225 }
93e9aa27 226 }
8e5af6cf 227
49d20def
DC
228 public static function create($type, $userid, $context, $params, $readonly=0) {
229 global $PAGE;
0601e0ee 230 if (has_capability('moodle/site:config', context_system::instance())) {
49d20def
DC
231 return parent::create($type, $userid, $context, $params, $readonly);
232 } else {
0601e0ee 233 require_capability('moodle/site:config', context_system::instance());
49d20def
DC
234 return false;
235 }
236 }
6b172cdc
DC
237 public static function instance_form_validation($mform, $data, $errors) {
238 if (empty($data['fs_path'])) {
239 $errors['fs_path'] = get_string('invalidadminsettingname', 'error', 'fs_path');
240 }
241 return $errors;
242 }
67233725
DC
243
244 /**
245 * User cannot use the external link to dropbox
246 *
247 * @return int
248 */
249 public function supported_returntypes() {
250 return FILE_INTERNAL | FILE_REFERENCE;
251 }
252
96221c60
MG
253 /**
254 * Return reference file life time
255 *
256 * @param string $ref
257 * @return int
258 */
259 public function get_reference_file_lifetime($ref) {
260 // Does not cost us much to synchronise within our own filesystem, set to 1 minute
261 return 60;
262 }
263
264 /**
265 * Return human readable reference information
266 *
267 * @param string $reference value of DB field files_reference.reference
268 * @param int $filestatus status of the file, 0 - ok, 666 - source missing
269 * @return string
270 */
271 public function get_reference_details($reference, $filestatus = 0) {
272 $details = $this->get_name().': '.$reference;
273 if ($filestatus) {
274 return get_string('lostsource', 'repository', $details);
275 } else {
276 return $details;
277 }
278 }
279
67233725 280 /**
0b2bfbd1 281 * Returns information about file in this repository by reference
67233725 282 *
0b2bfbd1
MG
283 * Returns null if file not found or is not readable
284 *
67233725 285 * @param stdClass $reference file reference db record
0b2bfbd1 286 * @return stdClass|null contains one of the following:
63d8ccef
MG
287 * - 'filesize' if file should not be copied to moodle filepool
288 * - 'filepath' if file should be copied to moodle filepool
67233725
DC
289 */
290 public function get_file_by_reference($reference) {
291 $ref = $reference->reference;
292 if ($ref{0} == '/') {
293 $filepath = $this->root_path.substr($ref, 1, strlen($ref)-1);
294 } else {
295 $filepath = $this->root_path.$ref;
296 }
0b2bfbd1 297 if (file_exists($filepath) && is_readable($filepath)) {
63d8ccef
MG
298 if (file_extension_in_typegroup($filepath, 'web_image')) {
299 // return path to image files so it will be copied into moodle filepool
300 // we need the file in filepool to generate an image thumbnail
301 return (object)array('filepath' => $filepath);
302 } else {
303 // return just the file size so file will NOT be copied into moodle filepool
304 return (object)array(
305 'filesize' => filesize($filepath)
306 );
307 }
0b2bfbd1
MG
308 } else {
309 return null;
310 }
67233725
DC
311 }
312
313 /**
0b2bfbd1
MG
314 * Repository method to serve the referenced file
315 *
316 * @see send_stored_file
67233725 317 *
0b2bfbd1 318 * @param stored_file $storedfile the file that contains the reference
67233725
DC
319 * @param int $lifetime Number of seconds before the file should expire from caches (default 24 hours)
320 * @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
321 * @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
322 * @param array $options additional options affecting the file serving
323 */
324 public function send_file($storedfile, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) {
325 $reference = $storedfile->get_reference();
326 if ($reference{0} == '/') {
327 $file = $this->root_path.substr($reference, 1, strlen($reference)-1);
328 } else {
329 $file = $this->root_path.$reference;
330 }
0b2bfbd1
MG
331 if (is_readable($file)) {
332 $filename = $storedfile->get_filename();
333 if ($options && isset($options['filename'])) {
334 $filename = $options['filename'];
335 }
336 $dontdie = ($options && isset($options['dontdie']));
337 send_file($file, $filename, $lifetime , $filter, false, $forcedownload, '', $dontdie);
338 } else {
339 send_file_not_found();
340 }
67233725 341 }
31581ae6
FM
342
343 /**
344 * Is this repository accessing private data?
345 *
346 * @return bool
347 */
348 public function contains_private_data() {
349 return false;
350 }
520de343 351}