Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
/mod/imscp/ -> lib.php (source)

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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   * Mandatory public API of imscp module
  19   *
  20   * @package mod_imscp
  21   * @copyright  2009 Petr Skoda  {@link http://skodak.org}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  /**
  28   * List of features supported in IMS CP module
  29   * @param string $feature FEATURE_xx constant for requested feature
  30   * @return mixed True if module supports feature, false if not, null if doesn't know
  31   */
  32  function imscp_supports($feature) {
  33      switch($feature) {
  34          case FEATURE_MOD_ARCHETYPE:           return MOD_ARCHETYPE_RESOURCE;
  35          case FEATURE_GROUPS:                  return false;
  36          case FEATURE_GROUPINGS:               return false;
  37          case FEATURE_MOD_INTRO:               return true;
  38          case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
  39          case FEATURE_GRADE_HAS_GRADE:         return false;
  40          case FEATURE_GRADE_OUTCOMES:          return false;
  41          case FEATURE_BACKUP_MOODLE2:          return true;
  42          case FEATURE_SHOW_DESCRIPTION:        return true;
  43  
  44          default: return null;
  45      }
  46  }
  47  
  48  /**
  49   * This function is used by the reset_course_userdata function in moodlelib.
  50   *
  51   * @param stdClass $data the data submitted from the reset course.
  52   * @return array status array
  53   */
  54  function imscp_reset_userdata($data) {
  55  
  56      // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
  57      // See MDL-9367.
  58  
  59      return array();
  60  }
  61  
  62  /**
  63   * List the actions that correspond to a view of this module.
  64   * This is used by the participation report.
  65   *
  66   * Note: This is not used by new logging system. Event with
  67   *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
  68   *       be considered as view action.
  69   *
  70   * @return array
  71   */
  72  function imscp_get_view_actions() {
  73      return array('view', 'view all');
  74  }
  75  
  76  /**
  77   * List the actions that correspond to a post of this module.
  78   * This is used by the participation report.
  79   *
  80   * Note: This is not used by new logging system. Event with
  81   *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
  82   *       will be considered as post action.
  83   *
  84   * @return array
  85   */
  86  function imscp_get_post_actions() {
  87      return array('update', 'add');
  88  }
  89  
  90  /**
  91   * Add imscp instance.
  92   * @param object $data
  93   * @param object $mform
  94   * @return int new imscp instance id
  95   */
  96  function imscp_add_instance($data, $mform) {
  97      global $CFG, $DB;
  98      require_once("$CFG->dirroot/mod/imscp/locallib.php");
  99  
 100      $cmid = $data->coursemodule;
 101  
 102      $data->timemodified = time();
 103      $data->revision     = 1;
 104      $data->structure    = null;
 105  
 106      $data->id = $DB->insert_record('imscp', $data);
 107  
 108      // We need to use context now, so we need to make sure all needed info is already in db.
 109      $DB->set_field('course_modules', 'instance', $data->id, array('id' => $cmid));
 110      $context = context_module::instance($cmid);
 111      $imscp = $DB->get_record('imscp', array('id' => $data->id), '*', MUST_EXIST);
 112  
 113      if (!empty($data->package)) {
 114          // Save uploaded files to 'backup' filearea.
 115          $fs = get_file_storage();
 116          $fs->delete_area_files($context->id, 'mod_imscp', 'backup', 1);
 117          file_save_draft_area_files($data->package, $context->id, 'mod_imscp', 'backup',
 118              1, array('subdirs' => 0, 'maxfiles' => 1));
 119          // Get filename of zip that was uploaded.
 120          $files = $fs->get_area_files($context->id, 'mod_imscp', 'backup', 1, '', false);
 121          if ($files) {
 122              // Extract package content to 'content' filearea.
 123              $package = reset($files);
 124              $packer = get_file_packer('application/zip');
 125              $package->extract_to_storage($packer, $context->id, 'mod_imscp', 'content', 1, '/');
 126              $structure = imscp_parse_structure($imscp, $context);
 127              $imscp->structure = is_array($structure) ? serialize($structure) : null;
 128              $DB->update_record('imscp', $imscp);
 129          }
 130      }
 131  
 132      $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null;
 133      \core_completion\api::update_completion_date_event($cmid, 'imscp', $data->id, $completiontimeexpected);
 134  
 135      return $data->id;
 136  }
 137  
 138  /**
 139   * Update imscp instance.
 140   * @param object $data
 141   * @param object $mform
 142   * @return bool true
 143   */
 144  function imscp_update_instance($data, $mform) {
 145      global $CFG, $DB;
 146      require_once("$CFG->dirroot/mod/imscp/locallib.php");
 147  
 148      $cmid = $data->coursemodule;
 149  
 150      $data->timemodified = time();
 151      $data->id           = $data->instance;
 152      $data->structure   = null; // Better reparse structure after each update.
 153  
 154      $DB->update_record('imscp', $data);
 155  
 156      $context = context_module::instance($cmid);
 157      $imscp = $DB->get_record('imscp', array('id' => $data->id), '*', MUST_EXIST);
 158  
 159      if (!empty($data->package) && ($draftareainfo = file_get_draft_area_info($data->package)) &&
 160              $draftareainfo['filecount']) {
 161          $fs = get_file_storage();
 162  
 163          $imscp->revision++;
 164          $DB->update_record('imscp', $imscp);
 165  
 166          // Get a list of existing packages before adding new package.
 167          if ($imscp->keepold > -1) {
 168              $packages = $fs->get_area_files($context->id, 'mod_imscp', 'backup', false, "itemid ASC", false);
 169          } else {
 170              $packages = array();
 171          }
 172  
 173          file_save_draft_area_files($data->package, $context->id, 'mod_imscp', 'backup',
 174              $imscp->revision, array('subdirs' => 0, 'maxfiles' => 1));
 175          $files = $fs->get_area_files($context->id, 'mod_imscp', 'backup', $imscp->revision, '', false);
 176          $package = reset($files);
 177  
 178          // Purge all extracted content.
 179          $fs->delete_area_files($context->id, 'mod_imscp', 'content');
 180  
 181          // Extract package content.
 182          if ($package) {
 183              $packer = get_file_packer('application/zip');
 184              $package->extract_to_storage($packer, $context->id, 'mod_imscp', 'content', $imscp->revision, '/');
 185          }
 186  
 187          // Cleanup old package files, keep current + keep old.
 188          while ($packages and (count($packages) > $imscp->keepold)) {
 189              $package = array_shift($packages);
 190              $fs->delete_area_files($context->id, 'mod_imscp', 'backup', $package->get_itemid());
 191          }
 192      }
 193  
 194      $structure = imscp_parse_structure($imscp, $context);
 195      $imscp->structure = is_array($structure) ? serialize($structure) : null;
 196      $DB->update_record('imscp', $imscp);
 197  
 198      $completiontimeexpected = !empty($data->completionexpected) ? $data->completionexpected : null;
 199      \core_completion\api::update_completion_date_event($cmid, 'imscp', $imscp->id, $completiontimeexpected);
 200  
 201      return true;
 202  }
 203  
 204  /**
 205   * Delete imscp instance.
 206   * @param int $id
 207   * @return bool true
 208   */
 209  function imscp_delete_instance($id) {
 210      global $DB;
 211  
 212      if (!$imscp = $DB->get_record('imscp', array('id' => $id))) {
 213          return false;
 214      }
 215  
 216      $cm = get_coursemodule_from_instance('imscp', $id);
 217      \core_completion\api::update_completion_date_event($cm->id, 'imscp', $id, null);
 218  
 219      // Note: all context files are deleted automatically.
 220  
 221      $DB->delete_records('imscp', array('id' => $imscp->id));
 222  
 223      return true;
 224  }
 225  
 226  /**
 227   * Lists all browsable file areas
 228   *
 229   * @package  mod_imscp
 230   * @category files
 231   * @param stdClass $course course object
 232   * @param stdClass $cm course module object
 233   * @param stdClass $context context object
 234   * @return array
 235   */
 236  function imscp_get_file_areas($course, $cm, $context) {
 237      $areas = array();
 238  
 239      $areas['content'] = get_string('areacontent', 'imscp');
 240      $areas['backup']  = get_string('areabackup', 'imscp');
 241  
 242      return $areas;
 243  }
 244  
 245  /**
 246   * File browsing support for imscp module ontent area.
 247   *
 248   * @package  mod_imscp
 249   * @category files
 250   * @param stdClass $browser file browser
 251   * @param stdClass $areas file areas
 252   * @param stdClass $course course object
 253   * @param stdClass $cm course module object
 254   * @param stdClass $context context object
 255   * @param string $filearea file area
 256   * @param int $itemid item ID
 257   * @param string $filepath file path
 258   * @param string $filename file name
 259   * @return file_info instance or null if not found
 260   */
 261  function imscp_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
 262      global $CFG, $DB;
 263  
 264      // Note: imscp_intro handled in file_browser automatically.
 265  
 266      if (!has_capability('moodle/course:managefiles', $context)) {
 267          // No peeking here for students!
 268          return null;
 269      }
 270  
 271      if ($filearea !== 'content' and $filearea !== 'backup') {
 272          return null;
 273      }
 274  
 275      require_once("$CFG->dirroot/mod/imscp/locallib.php");
 276  
 277      if (is_null($itemid)) {
 278          return new imscp_file_info($browser, $course, $cm, $context, $areas, $filearea, $itemid);
 279      }
 280  
 281      $fs = get_file_storage();
 282      $filepath = is_null($filepath) ? '/' : $filepath;
 283      $filename = is_null($filename) ? '.' : $filename;
 284      if (!$storedfile = $fs->get_file($context->id, 'mod_imscp', $filearea, $itemid, $filepath, $filename)) {
 285          return null;
 286      }
 287  
 288      // Do not allow manual modification of any files!
 289      $urlbase = $CFG->wwwroot.'/pluginfile.php';
 290      return new file_info_stored($browser, $context, $storedfile, $urlbase, $itemid, true, true, false, false); // No writing here!
 291  }
 292  
 293  /**
 294   * Serves the imscp files.
 295   *
 296   * @package  mod_imscp
 297   * @category files
 298   * @param stdClass $course course object
 299   * @param stdClass $cm course module object
 300   * @param stdClass $context context object
 301   * @param string $filearea file area
 302   * @param array $args extra arguments
 303   * @param bool $forcedownload whether or not force download
 304   * @param array $options additional options affecting the file serving
 305   * @return bool false if file not found, does not return if found - justsend the file
 306   */
 307  function imscp_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
 308      global $CFG, $DB;
 309  
 310      if ($context->contextlevel != CONTEXT_MODULE) {
 311          return false;
 312      }
 313  
 314      require_login($course, true, $cm);
 315  
 316      if ($filearea === 'content') {
 317          if (!has_capability('mod/imscp:view', $context)) {
 318              return false;
 319          }
 320          $revision = array_shift($args);
 321          $fs = get_file_storage();
 322          $relativepath = implode('/', $args);
 323          if ($relativepath === 'imsmanifest.xml') {
 324              if (!has_capability('moodle/course:managefiles', $context)) {
 325                  // No stealing of detailed package info.
 326                  return false;
 327              }
 328          }
 329          $fullpath = "/$context->id/mod_imscp/$filearea/$revision/$relativepath";
 330          if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
 331              return false;
 332          }
 333  
 334          // Finally send the file.
 335          send_stored_file($file, null, 0, $forcedownload, $options);
 336  
 337      } else if ($filearea === 'backup') {
 338          if (!has_capability('moodle/course:managefiles', $context)) {
 339              // No stealing of package backups.
 340              return false;
 341          }
 342          $revision = array_shift($args);
 343          $fs = get_file_storage();
 344          $relativepath = implode('/', $args);
 345          $fullpath = "/$context->id/mod_imscp/$filearea/$revision/$relativepath";
 346          if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
 347              return false;
 348          }
 349  
 350          // Finally send the file.
 351          send_stored_file($file, null, 0, $forcedownload, $options);
 352  
 353      } else {
 354          return false;
 355      }
 356  }
 357  
 358  /**
 359   * Return a list of page types
 360   * @param string $pagetype current page type
 361   * @param stdClass $parentcontext Block's parent context
 362   * @param stdClass $currentcontext Current context of block
 363   * @return array $modulepagetype list
 364   */
 365  function imscp_page_type_list($pagetype, $parentcontext, $currentcontext) {
 366      $modulepagetype = array('mod-imscp-*' => get_string('page-mod-imscp-x', 'imscp'));
 367      return $modulepagetype;
 368  }
 369  
 370  /**
 371   * Export imscp resource contents
 372   *
 373   * @param  stdClass $cm     Course module object
 374   * @param  string $baseurl  Base URL for file downloads
 375   * @return array of file content
 376   */
 377  function imscp_export_contents($cm, $baseurl) {
 378      global $DB;
 379  
 380      $contents = array();
 381      $context = context_module::instance($cm->id);
 382  
 383      $imscp = $DB->get_record('imscp', array('id' => $cm->instance), '*', MUST_EXIST);
 384  
 385      // We export the IMSCP structure as json encoded string.
 386      $structure = array();
 387      $structure['type']         = 'content';
 388      $structure['filename']     = 'structure';
 389      $structure['filepath']     = '/';
 390      $structure['filesize']     = 0;
 391      $structure['fileurl']      = null;
 392      $structure['timecreated']  = $imscp->timemodified;
 393      $structure['timemodified'] = $imscp->timemodified;
 394      $structure['content']      = json_encode(unserialize($imscp->structure));
 395      $structure['sortorder']    = 0;
 396      $structure['userid']       = null;
 397      $structure['author']       = null;
 398      $structure['license']      = null;
 399      $contents[] = $structure;
 400  
 401      // Area files.
 402      $fs = get_file_storage();
 403      $files = $fs->get_area_files($context->id, 'mod_imscp', 'content', $imscp->revision, 'id ASC', false);
 404      foreach ($files as $fileinfo) {
 405          $file = array();
 406          $file['type']         = 'file';
 407          $file['filename']     = $fileinfo->get_filename();
 408          $file['filepath']     = $fileinfo->get_filepath();
 409          $file['filesize']     = $fileinfo->get_filesize();
 410          $file['fileurl']      = moodle_url::make_webservice_pluginfile_url(
 411                                      $context->id, 'mod_imscp', 'content', $imscp->revision,
 412                                      $fileinfo->get_filepath(), $fileinfo->get_filename())->out(false);
 413          $file['timecreated']  = $fileinfo->get_timecreated();
 414          $file['timemodified'] = $fileinfo->get_timemodified();
 415          $file['sortorder']    = $fileinfo->get_sortorder();
 416          $file['userid']       = $fileinfo->get_userid();
 417          $file['author']       = $fileinfo->get_author();
 418          $file['license']      = $fileinfo->get_license();
 419          $file['mimetype']     = $fileinfo->get_mimetype();
 420          $file['isexternalfile'] = $fileinfo->is_external_file();
 421          if ($file['isexternalfile']) {
 422              $file['repositorytype'] = $fileinfo->get_repository_type();
 423          }
 424          $contents[] = $file;
 425      }
 426  
 427      return $contents;
 428  }
 429  
 430  /**
 431   * Mark the activity completed (if required) and trigger the course_module_viewed event.
 432   *
 433   * @param  stdClass $imscp   imscp object
 434   * @param  stdClass $course     course object
 435   * @param  stdClass $cm         course module object
 436   * @param  stdClass $context    context object
 437   * @since Moodle 3.0
 438   */
 439  function imscp_view($imscp, $course, $cm, $context) {
 440  
 441      // Trigger course_module_viewed event.
 442      $params = array(
 443          'context' => $context,
 444          'objectid' => $imscp->id
 445      );
 446  
 447      $event = \mod_imscp\event\course_module_viewed::create($params);
 448      $event->add_record_snapshot('course_modules', $cm);
 449      $event->add_record_snapshot('course', $course);
 450      $event->add_record_snapshot('imscp', $imscp);
 451      $event->trigger();
 452  
 453      // Completion.
 454      $completion = new completion_info($course);
 455      $completion->set_module_viewed($cm);
 456  }
 457  
 458  /**
 459   * Check if the module has any update that affects the current user since a given time.
 460   *
 461   * @param  cm_info $cm course module data
 462   * @param  int $from the time to check updates from
 463   * @param  array $filter  if we need to check only specific updates
 464   * @return stdClass an object with the different type of areas indicating if they were updated or not
 465   * @since Moodle 3.2
 466   */
 467  function imscp_check_updates_since(cm_info $cm, $from, $filter = array()) {
 468      $updates = course_check_module_updates_since($cm, $from, array('content'), $filter);
 469      return $updates;
 470  }
 471  
 472  /**
 473   * This function receives a calendar event and returns the action associated with it, or null if there is none.
 474   *
 475   * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event
 476   * is not displayed on the block.
 477   *
 478   * @param calendar_event $event
 479   * @param \core_calendar\action_factory $factory
 480   * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
 481   * @return \core_calendar\local\event\entities\action_interface|null
 482   */
 483  function mod_imscp_core_calendar_provide_event_action(calendar_event $event,
 484                                                        \core_calendar\action_factory $factory,
 485                                                        int $userid = 0) {
 486      $cm = get_fast_modinfo($event->courseid, $userid)->instances['imscp'][$event->instance];
 487  
 488      if (!$cm->uservisible) {
 489          // The module is not visible to the user for any reason.
 490          return null;
 491      }
 492  
 493      $completion = new \completion_info($cm->get_course());
 494  
 495      $completiondata = $completion->get_data($cm, false, $userid);
 496  
 497      if ($completiondata->completionstate != COMPLETION_INCOMPLETE) {
 498          return null;
 499      }
 500  
 501      return $factory->create_instance(
 502          get_string('view'),
 503          new \moodle_url('/mod/imscp/view.php', ['id' => $cm->id]),
 504          1,
 505          true
 506      );
 507  }