Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
/backup/ -> import.php (source)

Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   1  <?php
   2  
   3  // This file is part of Moodle - http://moodle.org/
   4  //
   5  // Moodle is free software: you can redistribute it and/or modify
   6  // it under the terms of the GNU General Public License as published by
   7  // the Free Software Foundation, either version 3 of the License, or
   8  // (at your option) any later version.
   9  //
  10  // Moodle is distributed in the hope that it will be useful,
  11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  // GNU General Public License for more details.
  14  //
  15  // You should have received a copy of the GNU General Public License
  16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  17  
  18  /**
  19   * This script is used to configure and execute the import proccess.
  20   *
  21   * @package    core
  22   * @subpackage backup
  23   * @copyright  Moodle
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  define('NO_OUTPUT_BUFFERING', true);
  28  
  29  // Require both the backup and restore libs
  30  require_once('../config.php');
  31  require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
  32  require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
  33  require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
  34  require_once($CFG->dirroot . '/backup/util/ui/import_extensions.php');
  35  
  36  // The courseid we are importing to
  37  $courseid = required_param('id', PARAM_INT);
  38  // The id of the course we are importing FROM (will only be set if past first stage
  39  $importcourseid = optional_param('importid', false, PARAM_INT);
  40  // We just want to check if a search has been run. True if anything is there.
  41  $searchcourses = optional_param('searchcourses', false, PARAM_BOOL);
  42  // The target method for the restore (adding or deleting)
  43  $restoretarget = optional_param('target', backup::TARGET_CURRENT_ADDING, PARAM_INT);
  44  
  45  // Load the course and context
  46  $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
  47  $context = context_course::instance($courseid);
  48  
  49  // Must pass login
  50  require_login($course);
  51  // Must hold restoretargetimport in the current course
  52  require_capability('moodle/restore:restoretargetimport', $context);
  53  
  54  // Set up the page
  55  $PAGE->set_title($course->shortname . ': ' . get_string('import'));
  56  $PAGE->set_heading($course->fullname);
  57  $PAGE->set_url(new moodle_url('/backup/import.php', array('id'=>$courseid)));
  58  $PAGE->set_context($context);
  59  $PAGE->set_pagelayout('incourse');
  60  
  61  // Prepare the backup renderer
  62  $renderer = $PAGE->get_renderer('core','backup');
  63  
  64  // Check if we already have a import course id
  65  if ($importcourseid === false || $searchcourses) {
  66      // Obviously not... show the selector so one can be chosen
  67      $url = new moodle_url('/backup/import.php', array('id'=>$courseid));
  68      $search = new import_course_search(array('url'=>$url));
  69  
  70      // show the course selector
  71      echo $OUTPUT->header();
  72      $backup = new import_ui(false, array());
  73      echo $renderer->progress_bar($backup->get_progress_bar());
  74      $html = $renderer->import_course_selector($url, $search);
  75      echo $html;
  76      echo $OUTPUT->footer();
  77      die();
  78  }
  79  
  80  // Load the course +context to import from
  81  $importcourse = $DB->get_record('course', array('id'=>$importcourseid), '*', MUST_EXIST);
  82  $importcontext = context_course::instance($importcourseid);
  83  
  84  // Make sure the user can backup from that course
  85  require_capability('moodle/backup:backuptargetimport', $importcontext);
  86  
  87  // Attempt to load the existing backup controller (backupid will be false if there isn't one)
  88  $backupid = optional_param('backup', false, PARAM_ALPHANUM);
  89  if (!($bc = backup_ui::load_controller($backupid))) {
  90      $bc = new backup_controller(backup::TYPE_1COURSE, $importcourse->id, backup::FORMAT_MOODLE,
  91                              backup::INTERACTIVE_YES, backup::MODE_IMPORT, $USER->id);
  92      $bc->get_plan()->get_setting('users')->set_status(backup_setting::LOCKED_BY_CONFIG);
  93      $settings = $bc->get_plan()->get_settings();
  94  
  95      // For the initial stage we want to hide all locked settings and if there are
  96      // no visible settings move to the next stage
  97      $visiblesettings = false;
  98      foreach ($settings as $setting) {
  99          if ($setting->get_status() !== backup_setting::NOT_LOCKED) {
 100              $setting->set_visibility(backup_setting::HIDDEN);
 101          } else {
 102              $visiblesettings = true;
 103          }
 104      }
 105      import_ui::skip_current_stage(!$visiblesettings);
 106  }
 107  
 108  // Prepare the import UI
 109  $backup = new import_ui($bc, array('importid'=>$importcourse->id, 'target'=>$restoretarget));
 110  // Process the current stage
 111  $backup->process();
 112  
 113  // If this is the confirmation stage remove the filename setting
 114  if ($backup->get_stage() == backup_ui::STAGE_CONFIRMATION) {
 115      $backup->get_setting('filename')->set_visibility(backup_setting::HIDDEN);
 116  }
 117  
 118  // If it's the final stage process the import
 119  if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
 120      echo $OUTPUT->header();
 121  
 122      // Display an extra progress bar so that we can show the current stage.
 123      echo html_writer::start_div('', array('id' => 'executionprogress'));
 124      echo $renderer->progress_bar($backup->get_progress_bar());
 125  
 126      // Start the progress display - we split into 2 chunks for backup and restore.
 127      $progress = new \core\progress\display();
 128      $progress->start_progress('', 2);
 129      $backup->get_controller()->set_progress($progress);
 130  
 131      // Prepare logger for backup.
 132      $logger = new core_backup_html_logger($CFG->debugdeveloper ? backup::LOG_DEBUG : backup::LOG_INFO);
 133      $backup->get_controller()->add_logger($logger);
 134  
 135      // First execute the backup
 136      $backup->execute();
 137      // Before destroying the backup object, we still need to generate the progress bar.
 138      $progressbar = $renderer->progress_bar($backup->get_progress_bar());
 139      $backup->destroy();
 140      unset($backup);
 141  
 142      // Note that we've done that progress.
 143      $progress->progress(1);
 144  
 145      // Check whether the backup directory still exists. If missing, something
 146      // went really wrong in backup, throw error. Note that backup::MODE_IMPORT
 147      // backups don't store resulting files ever
 148      $tempdestination = make_backup_temp_directory($backupid, false);
 149      if (!file_exists($tempdestination) || !is_dir($tempdestination)) {
 150          print_error('unknownbackupexporterror'); // shouldn't happen ever
 151      }
 152  
 153      // Prepare the restore controller. We don't need a UI here as we will just use what
 154      // ever the restore has (the user has just chosen).
 155      $rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_YES, backup::MODE_IMPORT, $USER->id, $restoretarget);
 156  
 157      // Start a progress section for the restore, which will consist of 2 steps
 158      // (the precheck and then the actual restore).
 159      $progress->start_progress('Restore process', 2);
 160      $rc->set_progress($progress);
 161  
 162      // Set logger for restore.
 163      $rc->add_logger($logger);
 164  
 165      // Convert the backup if required.... it should NEVER happed
 166      if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
 167          $rc->convert();
 168      }
 169      // Mark the UI finished.
 170      $rc->finish_ui();
 171      // Execute prechecks
 172      $warnings = false;
 173      if (!$rc->execute_precheck()) {
 174          $precheckresults = $rc->get_precheck_results();
 175          if (is_array($precheckresults)) {
 176              if (!empty($precheckresults['errors'])) { // If errors are found, terminate the import.
 177                  fulldelete($tempdestination);
 178  
 179                  echo $renderer->precheck_notices($precheckresults);
 180                  echo $OUTPUT->continue_button(new moodle_url('/course/view.php', array('id'=>$course->id)));
 181                  echo $OUTPUT->footer();
 182                  die();
 183              }
 184              if (!empty($precheckresults['warnings'])) { // If warnings are found, go ahead but display warnings later.
 185                  $warnings = $precheckresults['warnings'];
 186              }
 187          }
 188      }
 189      if ($restoretarget == backup::TARGET_CURRENT_DELETING || $restoretarget == backup::TARGET_EXISTING_DELETING) {
 190          restore_dbops::delete_course_content($course->id);
 191      }
 192      // Execute the restore.
 193      $rc->execute_plan();
 194  
 195      // Delete the temp directory now
 196      fulldelete($tempdestination);
 197  
 198      // End restore section of progress tracking (restore/precheck).
 199      $progress->end_progress();
 200  
 201      // All progress complete. Hide progress area.
 202      $progress->end_progress();
 203      echo html_writer::end_div();
 204      echo html_writer::script('document.getElementById("executionprogress").style.display = "none";');
 205  
 206      // Display a notification and a continue button
 207      if ($warnings) {
 208          echo $OUTPUT->box_start();
 209          echo $OUTPUT->notification(get_string('warning'), 'notifyproblem');
 210          echo html_writer::start_tag('ul', array('class'=>'list'));
 211          foreach ($warnings as $warning) {
 212              echo html_writer::tag('li', $warning);
 213          }
 214          echo html_writer::end_tag('ul');
 215          echo $OUTPUT->box_end();
 216      }
 217      echo $progressbar;
 218      echo $OUTPUT->notification(get_string('importsuccess', 'backup'), 'notifysuccess');
 219      echo $OUTPUT->continue_button(new moodle_url('/course/view.php', array('id'=>$course->id)));
 220  
 221      // Get and display log data if there was any.
 222      $loghtml = $logger->get_html();
 223      if ($loghtml != '') {
 224          echo $renderer->log_display($loghtml);
 225      }
 226  
 227      echo $OUTPUT->footer();
 228  
 229      die();
 230  
 231  } else {
 232      // Otherwise save the controller and progress
 233      $backup->save_controller();
 234  }
 235  
 236  // Display the current stage
 237  echo $OUTPUT->header();
 238  if ($backup->enforce_changed_dependencies()) {
 239      debugging('Your settings have been altered due to unmet dependencies', DEBUG_DEVELOPER);
 240  }
 241  echo $renderer->progress_bar($backup->get_progress_bar());
 242  echo $backup->display($renderer);
 243  $backup->destroy();
 244  unset($backup);
 245  echo $OUTPUT->footer();