Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 39 and 401]

   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   * Export db content to file.
  19   *
  20   * @package    tool_dbtransfer
  21   * @copyright  2008 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  TODO:
  29    - exporting to server file >2GB fails in 32bit operating systems - needs warning
  30    - we may run out of disk space exporting to server file - we must verify the file is not truncated; read from the end of file?
  31    - when sending file >4GB - FAT32 limit, Apache limit, browser limit - needs warning
  32    - there must be some form of progress bar during export, transfer - new tracking class could be passed around
  33    - command line operation - could work around some 2G/4G limits in PHP; useful for cron full backups
  34    - by default allow exporting into empty database only (no tables with the same prefix yet)
  35    - all dangerous operation (like deleting of all data) should be confirmed by key found in special file in dataroot
  36      (user would need file access to dataroot which might prevent various "accidents")
  37    - implement "Export/import running" notification in lib/setup.php (similar to new upgrade flag in config table)
  38    - gzip compression when storing xml file - the xml is very verbose and full of repeated tags (zip is not suitable here at all)
  39      this could help us keep the files below 2G (expected ratio is > 10:1)
  40  
  41  */
  42  
  43  require_once($CFG->libdir.'/adminlib.php');
  44  require_once($CFG->libdir.'/dtllib.php');
  45  
  46  /**
  47   * Initiate database export.
  48   * @param string $description
  49   * @param moodle_database $mdb
  50   * @return does not return, calls die()
  51   */
  52  function tool_dbtransfer_export_xml_database($description, $mdb) {
  53      core_php_time_limit::raise();
  54  
  55      \core\session\manager::write_close(); // Release session.
  56  
  57      header('Content-Type: application/xhtml+xml; charset=utf-8');
  58      header('Content-Disposition: attachment; filename=database.xml');
  59      header('Expires: 0');
  60      header('Cache-Control: must-revalidate,post-check=0,pre-check=0');
  61      header('Pragma: public');
  62  
  63      while(@ob_flush());
  64  
  65      $var = new file_xml_database_exporter('php://output', $mdb);
  66      $var->export_database($description);
  67  
  68      // No more output.
  69      die;
  70  }
  71  
  72  /**
  73   * Initiate database transfer.
  74   * @param moodle_database $sourcedb
  75   * @param moodle_database $targetdb
  76   * @param progress_trace $feedback
  77   * @return void
  78   */
  79  function tool_dbtransfer_transfer_database(moodle_database $sourcedb, moodle_database $targetdb, progress_trace $feedback = null) {
  80      core_php_time_limit::raise();
  81  
  82      \core\session\manager::write_close(); // Release session.
  83  
  84      $var = new database_mover($sourcedb, $targetdb, true, $feedback);
  85      $var->export_database(null);
  86  
  87      tool_dbtransfer_rebuild_target_log_actions($targetdb, $feedback);
  88  }
  89  
  90  /**
  91   * Very hacky function for rebuilding of log actions in target database.
  92   * @param moodle_database $target
  93   * @param progress_trace $feedback
  94   * @return void
  95   * @throws Exception on conversion error
  96   */
  97  function tool_dbtransfer_rebuild_target_log_actions(moodle_database $target, progress_trace $feedback = null) {
  98      global $DB, $CFG;
  99      require_once("$CFG->libdir/upgradelib.php");
 100  
 101      $feedback->output(get_string('convertinglogdisplay', 'tool_dbtransfer'));
 102  
 103      $olddb = $DB;
 104      $DB = $target;
 105      try {
 106          $DB->delete_records('log_display', array('component'=>'moodle'));
 107          log_update_descriptions('moodle');
 108          $plugintypes = core_component::get_plugin_types();
 109          foreach ($plugintypes as $type => $location) {
 110              $plugs = core_component::get_plugin_list($type);
 111              foreach ($plugs as $plug => $fullplug) {
 112                  $component = $type.'_'.$plug;
 113                  $DB->delete_records('log_display', array('component'=>$component));
 114                  log_update_descriptions($component);
 115              }
 116          }
 117      } catch (Exception $e) {
 118          $DB = $olddb;
 119          throw $e;
 120      }
 121      $DB = $olddb;
 122      $feedback->output(get_string('done', 'core_dbtransfer', null), 1);
 123  }
 124  
 125  /**
 126   * Returns list of fully working database drivers present in system.
 127   * @return array
 128   */
 129  function tool_dbtransfer_get_drivers() {
 130      global $CFG;
 131  
 132      $files = new RegexIterator(new DirectoryIterator("$CFG->libdir/dml"), '|^.*_moodle_database\.php$|');
 133      $drivers = array();
 134  
 135      foreach ($files as $file) {
 136          $matches = null;
 137          preg_match('|^([a-z0-9]+)_([a-z]+)_moodle_database\.php$|', $file->getFilename(), $matches);
 138          if (!$matches) {
 139              continue;
 140          }
 141          $dbtype = $matches[1];
 142          $dblibrary = $matches[2];
 143  
 144          if ($dbtype === 'sqlite3') {
 145              // The sqlite3 driver is not fully working yet and should not be returned.
 146              continue;
 147          }
 148  
 149          $targetdb = moodle_database::get_driver_instance($dbtype, $dblibrary, false);
 150          if ($targetdb->driver_installed() !== true) {
 151              continue;
 152          }
 153  
 154          $driver = $dbtype.'/'.$dblibrary;
 155  
 156          $drivers[$driver] = $targetdb->get_name();
 157      };
 158  
 159      return $drivers;
 160  }
 161  
 162  /**
 163   * Create CLI maintenance file to prevent all access.
 164   */
 165  function tool_dbtransfer_create_maintenance_file() {
 166      global $CFG;
 167  
 168      core_shutdown_manager::register_function('tool_dbtransfer_maintenance_callback');
 169  
 170      $options = new stdClass();
 171      $options->trusted = false;
 172      $options->noclean = false;
 173      $options->smiley = false;
 174      $options->filter = false;
 175      $options->para = true;
 176      $options->newlines = false;
 177  
 178      $message = format_text(get_string('climigrationnotice', 'tool_dbtransfer'), FORMAT_MARKDOWN, $options);
 179      $message = bootstrap_renderer::early_error_content($message, '', '', array());
 180      $html = <<<OET
 181  <!DOCTYPE html>
 182  <html>
 183  <header><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><header/>
 184  <body>$message</body>
 185  </html>
 186  OET;
 187  
 188      file_put_contents("$CFG->dataroot/climaintenance.html", $html);
 189      @chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions);
 190  }
 191  
 192  /**
 193   * This callback is responsible for unsetting maintenance mode
 194   * if the migration is interrupted.
 195   */
 196  function tool_dbtransfer_maintenance_callback() {
 197      global $CFG;
 198  
 199      if (empty($CFG->tool_dbransfer_migration_running)) {
 200          // Migration was finished properly - keep the maintenance file in place.
 201          return;
 202      }
 203  
 204      if (file_exists("$CFG->dataroot/climaintenance.html")) {
 205          // Failed migration, revert to normal site operation.
 206          unlink("$CFG->dataroot/climaintenance.html");
 207          error_log('tool_dbtransfer: Interrupted database migration detected, switching off CLI maintenance mode.');
 208      }
 209  }