externallib.php 16 KB

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