MDL-79381 core: Refactor MoodleNet controller
[moodle.git] / files / externallib.php
blobf1b174bfef05fdbf0cd835780fdc3536cd6abad3
1 <?php
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.
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/>.
18 /**
19 * External files API
21 * @package core_files
22 * @category external
23 * @copyright 2010 Dongsheng Cai
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 use core_external\external_api;
28 use core_external\external_function_parameters;
29 use core_external\external_multiple_structure;
30 use core_external\external_single_structure;
31 use core_external\external_value;
33 defined('MOODLE_INTERNAL') || die();
35 require_once("{$CFG->libdir}/filelib.php");
37 /**
38 * Files external functions
40 * @package core_files
41 * @category external
42 * @copyright 2011 Jerome Mouneyrac
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 * @since Moodle 2.2
46 class core_files_external extends external_api {
48 /**
49 * Returns description of get_files parameters
51 * @return external_function_parameters
52 * @since Moodle 2.2
54 public static function get_files_parameters() {
55 return new external_function_parameters([
56 'contextid' => new external_value(PARAM_INT, 'context id Set to -1 to use contextlevel and instanceid.'),
57 'component' => new external_value(PARAM_TEXT, 'component'),
58 'filearea' => new external_value(PARAM_TEXT, 'file area'),
59 'itemid' => new external_value(PARAM_INT, 'associated id'),
60 'filepath' => new external_value(PARAM_PATH, 'file path'),
61 'filename' => new external_value(PARAM_TEXT, 'file name'),
62 'modified' => new external_value(
63 PARAM_INT,
64 'timestamp to return files changed after this time.',
65 VALUE_DEFAULT,
66 null
68 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level for the file location.', VALUE_DEFAULT, null),
69 'instanceid' => new external_value(PARAM_INT, 'The instance id for where the file is located.', VALUE_DEFAULT, null),
70 ]);
73 /**
74 * Return moodle files listing
76 * @param int $contextid context id
77 * @param int $component component
78 * @param int $filearea file area
79 * @param int $itemid item id
80 * @param string $filepath file path
81 * @param string $filename file name
82 * @param int $modified timestamp to return files changed after this time.
83 * @param string $contextlevel The context level for the file location.
84 * @param int $instanceid The instance id for where the file is located.
85 * @return array
86 * @since Moodle 2.9 Returns additional fields (timecreated, filesize, author, license)
87 * @since Moodle 2.2
89 public static function get_files($contextid, $component, $filearea, $itemid, $filepath, $filename, $modified = null,
90 $contextlevel = null, $instanceid = null) {
92 $parameters = [
93 'contextid' => $contextid,
94 'component' => $component,
95 'filearea' => $filearea,
96 'itemid' => $itemid,
97 'filepath' => $filepath,
98 'filename' => $filename,
99 'modified' => $modified,
100 'contextlevel' => $contextlevel,
101 'instanceid' => $instanceid,
103 $fileinfo = self::validate_parameters(self::get_files_parameters(), $parameters);
105 $browser = get_file_browser();
107 // We need to preserve backwards compatibility. Zero will use the system context and minus one will
108 // use the addtional parameters to determine the context.
109 // TODO MDL-40489 get_context_from_params should handle this logic.
110 if ($fileinfo['contextid'] == 0) {
111 $context = context_system::instance();
112 } else {
113 if ($fileinfo['contextid'] == -1) {
114 $fileinfo['contextid'] = null;
116 $context = self::get_context_from_params($fileinfo);
118 self::validate_context($context);
120 if (empty($fileinfo['component'])) {
121 $fileinfo['component'] = null;
123 if (empty($fileinfo['filearea'])) {
124 $fileinfo['filearea'] = null;
126 if (empty($fileinfo['filename'])) {
127 $fileinfo['filename'] = null;
129 if (empty($fileinfo['filepath'])) {
130 $fileinfo['filepath'] = null;
133 $return = array();
134 $return['parents'] = array();
135 $return['files'] = array();
136 $list = array();
138 if ($file = $browser->get_file_info(
139 $context, $fileinfo['component'], $fileinfo['filearea'], $fileinfo['itemid'],
140 $fileinfo['filepath'], $fileinfo['filename'])) {
141 $level = $file->get_parent();
142 while ($level) {
143 $params = $level->get_params();
144 $params['filename'] = $level->get_visible_name();
145 array_unshift($return['parents'], $params);
146 $level = $level->get_parent();
148 $children = $file->get_children();
149 foreach ($children as $child) {
151 $params = $child->get_params();
152 $timemodified = $child->get_timemodified();
153 $timecreated = $child->get_timecreated();
155 if ($child->is_directory()) {
156 if ((is_null($modified)) or ($modified < $timemodified)) {
157 $node = [
158 'contextid' => $params['contextid'],
159 'component' => $params['component'],
160 'filearea' => $params['filearea'],
161 'itemid' => $params['itemid'],
162 'filepath' => $params['filepath'],
163 'filename' => $child->get_visible_name(),
164 'url' => null,
165 'isdir' => true,
166 'timemodified' => $timemodified,
167 'timecreated' => $timecreated,
168 'filesize' => 0,
169 'author' => null,
170 'license' => null,
172 $list[] = $node;
174 } else {
175 if ((is_null($modified)) or ($modified < $timemodified)) {
176 $node = [
177 'contextid' => $params['contextid'],
178 'component' => $params['component'],
179 'filearea' => $params['filearea'],
180 'itemid' => $params['itemid'],
181 'filepath' => $params['filepath'],
182 'filename' => $child->get_visible_name(),
183 'url' => $child->get_url(),
184 'isdir' => false,
185 'timemodified' => $timemodified,
186 'timecreated' => $timecreated,
187 'filesize' => $child->get_filesize(),
188 'author' => $child->get_author(),
189 'license' => $child->get_license(),
191 $list[] = $node;
196 $return['files'] = $list;
197 return $return;
201 * Returns description of get_files returns
203 * @return external_single_structure
204 * @since Moodle 2.9 Returns additional fields for files (timecreated, filesize, author, license)
205 * @since Moodle 2.2
207 public static function get_files_returns() {
208 return new external_single_structure([
209 'parents' => new external_multiple_structure(
210 new external_single_structure([
211 'contextid' => new external_value(PARAM_INT, ''),
212 'component' => new external_value(PARAM_COMPONENT, ''),
213 'filearea' => new external_value(PARAM_AREA, ''),
214 'itemid' => new external_value(PARAM_INT, ''),
215 'filepath' => new external_value(PARAM_TEXT, ''),
216 'filename' => new external_value(PARAM_TEXT, ''),
219 'files' => new external_multiple_structure(
220 new external_single_structure([
221 'contextid' => new external_value(PARAM_INT, ''),
222 'component' => new external_value(PARAM_COMPONENT, ''),
223 'filearea' => new external_value(PARAM_AREA, ''),
224 'itemid' => new external_value(PARAM_INT, ''),
225 'filepath' => new external_value(PARAM_TEXT, ''),
226 'filename' => new external_value(PARAM_TEXT, ''),
227 'isdir' => new external_value(PARAM_BOOL, ''),
228 'url' => new external_value(PARAM_TEXT, ''),
229 'timemodified' => new external_value(PARAM_INT, ''),
230 'timecreated' => new external_value(PARAM_INT, 'Time created', VALUE_OPTIONAL),
231 'filesize' => new external_value(PARAM_INT, 'File size', VALUE_OPTIONAL),
232 'author' => new external_value(PARAM_TEXT, 'File owner', VALUE_OPTIONAL),
233 'license' => new external_value(PARAM_TEXT, 'File license', VALUE_OPTIONAL),
240 * Returns description of upload parameters
242 * @return external_function_parameters
243 * @since Moodle 2.2
245 public static function upload_parameters() {
246 return new external_function_parameters([
247 'contextid' => new external_value(PARAM_INT, 'context id', VALUE_DEFAULT, null),
248 'component' => new external_value(PARAM_COMPONENT, 'component'),
249 'filearea' => new external_value(PARAM_AREA, 'file area'),
250 'itemid' => new external_value(PARAM_INT, 'associated id'),
251 'filepath' => new external_value(PARAM_PATH, 'file path'),
252 'filename' => new external_value(PARAM_FILE, 'file name'),
253 'filecontent' => new external_value(PARAM_TEXT, 'file content'),
254 'contextlevel' => new external_value(
255 PARAM_ALPHA,
256 'The context level to put the file in,
257 (block, course, coursecat, system, user, module)',
258 VALUE_DEFAULT,
259 null
261 'instanceid' => new external_value(PARAM_INT, 'The Instance id of item associated
262 with the context level', VALUE_DEFAULT, null),
267 * Uploading a file to moodle
269 * @param int $contextid context id
270 * @param string $component component
271 * @param string $filearea file area
272 * @param int $itemid item id
273 * @param string $filepath file path
274 * @param string $filename file name
275 * @param string $filecontent file content
276 * @param string $contextlevel Context level (block, course, coursecat, system, user or module)
277 * @param int $instanceid Instance id of the item associated with the context level
278 * @return array
279 * @since Moodle 2.2
281 public static function upload(
282 $contextid,
283 $component,
284 $filearea,
285 $itemid,
286 $filepath,
287 $filename,
288 $filecontent,
289 $contextlevel,
290 $instanceid
292 global $USER, $CFG;
294 $fileinfo = self::validate_parameters(self::upload_parameters(), [
295 'contextid' => $contextid, 'component' => $component, 'filearea' => $filearea, 'itemid' => $itemid,
296 'filepath' => $filepath, 'filename' => $filename, 'filecontent' => $filecontent, 'contextlevel' => $contextlevel,
297 'instanceid' => $instanceid,
300 if (!isset($fileinfo['filecontent'])) {
301 throw new moodle_exception('nofile');
303 // Saving file.
304 $dir = make_temp_directory('wsupload');
306 if (empty($fileinfo['filename'])) {
307 $filename = uniqid('wsupload', true).'_'.time().'.tmp';
308 } else {
309 $filename = $fileinfo['filename'];
312 if (file_exists($dir.$filename)) {
313 $savedfilepath = $dir.uniqid('m').$filename;
314 } else {
315 $savedfilepath = $dir.$filename;
318 file_put_contents($savedfilepath, base64_decode($fileinfo['filecontent']));
319 @chmod($savedfilepath, $CFG->filepermissions);
320 unset($fileinfo['filecontent']);
322 if (!empty($fileinfo['filepath'])) {
323 $filepath = $fileinfo['filepath'];
324 } else {
325 $filepath = '/';
328 // Only allow uploads to draft area.
329 if (!($fileinfo['component'] == 'user' and $fileinfo['filearea'] == 'draft')) {
330 throw new coding_exception('File can be uploaded to user draft area only');
331 } else {
332 $component = 'user';
333 $filearea = $fileinfo['filearea'];
336 $itemid = 0;
337 if (isset($fileinfo['itemid'])) {
338 $itemid = $fileinfo['itemid'];
340 if ($filearea == 'draft' && $itemid <= 0) {
341 // Generate a draft area for the files.
342 $itemid = file_get_unused_draft_itemid();
343 } else if ($filearea == 'private') {
344 // TODO MDL-31116 in user private area, itemid is always 0.
345 $itemid = 0;
348 // We need to preserve backword compatibility. Context id is no more a required.
349 if (empty($fileinfo['contextid'])) {
350 unset($fileinfo['contextid']);
353 // Get and validate context.
354 $context = self::get_context_from_params($fileinfo);
355 self::validate_context($context);
356 if (($fileinfo['component'] == 'user' and $fileinfo['filearea'] == 'private')) {
357 throw new moodle_exception('privatefilesupload');
360 $browser = get_file_browser();
362 // Check existing file.
363 if ($file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename)) {
364 throw new moodle_exception('fileexist');
367 // Move file to filepool.
368 if ($dir = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, '.')) {
369 $info = $dir->create_file_from_pathname($filename, $savedfilepath);
370 $params = $info->get_params();
371 unlink($savedfilepath);
372 return [
373 'contextid' => $params['contextid'],
374 'component' => $params['component'],
375 'filearea' => $params['filearea'],
376 'itemid' => $params['itemid'],
377 'filepath' => $params['filepath'],
378 'filename' => $params['filename'],
379 'url' => $info->get_url(),
381 } else {
382 throw new moodle_exception('nofile');
387 * Returns description of upload returns
389 * @return external_single_structure
390 * @since Moodle 2.2
392 public static function upload_returns() {
393 return new external_single_structure([
394 'contextid' => new external_value(PARAM_INT, ''),
395 'component' => new external_value(PARAM_COMPONENT, ''),
396 'filearea' => new external_value(PARAM_AREA, ''),
397 'itemid' => new external_value(PARAM_INT, ''),
398 'filepath' => new external_value(PARAM_TEXT, ''),
399 'filename' => new external_value(PARAM_FILE, ''),
400 'url' => new external_value(PARAM_TEXT, ''),