Search moodle.org's
Developer Documentation

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