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.
/lib/db/ -> install.php (source)

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

   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   * This file is executed right after the install.xml
  19   *
  20   * For more information, take a look to the documentation available:
  21   *     - Upgrade API: {@link https://moodledev.io/docs/guides/upgrade}
  22   *
  23   * @package   core_install
  24   * @category  upgrade
  25   * @copyright 2009 Petr Skoda (http://skodak.org)
  26   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   */
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  /**
  32   * Main post-install tasks to be executed after the BD schema is available
  33   *
  34   * This function is automatically executed after Moodle core DB has been
  35   * created at initial install. It's in charge of perform the initial tasks
  36   * not covered by the {@link install.xml} file, like create initial users,
  37   * roles, templates, moving stuff from other plugins...
  38   *
  39   * Note that the function is only invoked once, at install time, so if new tasks
  40   * are needed in the future, they will need to be added both here (for new sites)
  41   * and in the corresponding {@link upgrade.php} file (for existing sites).
  42   *
  43   * All plugins within Moodle (modules, blocks, reports...) support the existence of
  44   * their own install.php file, using the "Frankenstyle" component name as
  45   * defined at {@link https://moodledev.io/general/development/policies/codingstyle/frankenstyle}, for example:
  46   *     - {@link xmldb_page_install()}. (modules don't require the plugintype ("mod_") to be used.
  47   *     - {@link xmldb_enrol_meta_install()}.
  48   *     - {@link xmldb_workshopform_accumulative_install()}.
  49   *     - ....
  50   *
  51   * Finally, note that it's also supported to have one uninstall.php file that is
  52   * executed also once, each time one plugin is uninstalled (before the DB schema is
  53   * deleted). Those uninstall files will contain one function, using the "Frankenstyle"
  54   * naming conventions, like {@link xmldb_enrol_meta_uninstall()} or {@link xmldb_workshop_uninstall()}.
  55   */
  56  function xmldb_main_install() {
  57      global $CFG, $DB, $SITE, $OUTPUT;
  58  
  59      // Make sure system context exists
  60      $syscontext = context_system::instance(0, MUST_EXIST, false);
  61      if ($syscontext->id != SYSCONTEXTID) {
  62          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Unexpected new system context id!');
  63      }
  64  
  65  
  66      // Create site course
  67      if ($DB->record_exists('course', array())) {
  68          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Can not create frontpage course, courses already exist.');
  69      }
  70      $newsite = new stdClass();
  71      $newsite->fullname     = '';
  72      $newsite->shortname    = '';
  73      $newsite->summary      = NULL;
  74      $newsite->newsitems    = 3;
  75      $newsite->numsections  = 1;
  76      $newsite->category     = 0;
  77      $newsite->format       = 'site';  // Only for this course
  78      $newsite->timecreated  = time();
  79      $newsite->timemodified = $newsite->timecreated;
  80  
  81      if (defined('SITEID')) {
  82          $newsite->id = SITEID;
  83          $DB->import_record('course', $newsite);
  84          $DB->get_manager()->reset_sequence('course');
  85      } else {
  86          $newsite->id = $DB->insert_record('course', $newsite);
  87          define('SITEID', $newsite->id);
  88      }
  89      // set the field 'numsections'. We can not use format_site::update_format_options() because
  90      // the file is not loaded
  91      $DB->insert_record('course_format_options', array('courseid' => SITEID, 'format' => 'site',
  92          'sectionid' => 0, 'name' => 'numsections', 'value' => $newsite->numsections));
  93      $SITE = get_site();
  94      if ($newsite->id != $SITE->id) {
  95          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Unexpected new site course id!');
  96      }
  97      // Make sure site course context exists
  98      context_course::instance($SITE->id);
  99      // Update the global frontpage cache
 100      $SITE = $DB->get_record('course', array('id'=>$newsite->id), '*', MUST_EXIST);
 101  
 102  
 103      // Create default course category
 104      if ($DB->record_exists('course_categories', array())) {
 105          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Can not create default course category, categories already exist.');
 106      }
 107      $cat = new stdClass();
 108      $cat->name         = get_string('defaultcategoryname');
 109      $cat->descriptionformat = FORMAT_HTML;
 110      $cat->depth        = 1;
 111      $cat->sortorder    = get_max_courses_in_category();
 112      $cat->timemodified = time();
 113      $catid = $DB->insert_record('course_categories', $cat);
 114      $DB->set_field('course_categories', 'path', '/'.$catid, array('id'=>$catid));
 115      // Make sure category context exists
 116      context_coursecat::instance($catid);
 117  
 118  
 119      $defaults = array(
 120          'rolesactive'           => '0', // marks fully set up system
 121          'auth'                  => 'email',
 122          'enrol_plugins_enabled' => 'manual,guest,self,cohort',
 123          'theme'                 => theme_config::DEFAULT_THEME,
 124          'filter_multilang_converted' => 1,
 125          'siteidentifier'        => random_string(32).get_host_from_url($CFG->wwwroot),
 126          'backup_version'        => 2008111700,
 127          'backup_release'        => '2.0 dev',
 128          'mnet_dispatcher_mode'  => 'off',
 129          'sessiontimeout'        => 8 * 60 * 60, // Must be present during roles installation.
 130          'stringfilters'         => '', // These two are managed in a strange way by the filters.
 131          'filterall'             => 0, // setting page, so have to be initialised here.
 132          'texteditors'           => 'atto,tinymce,textarea',
 133          'antiviruses'           => '',
 134          'media_plugins_sortorder' => 'videojs,youtube',
 135          'upgrade_extracreditweightsstepignored' => 1, // New installs should not run this upgrade step.
 136          'upgrade_calculatedgradeitemsignored' => 1, // New installs should not run this upgrade step.
 137          'upgrade_letterboundarycourses' => 1, // New installs should not run this upgrade step.
 138      );
 139      foreach($defaults as $key => $value) {
 140          set_config($key, $value);
 141      }
 142  
 143  
 144      // Bootstrap mnet
 145      $mnethost = new stdClass();
 146      $mnethost->wwwroot    = $CFG->wwwroot;
 147      $mnethost->name       = '';
 148      $mnethost->name       = '';
 149      $mnethost->public_key = '';
 150  
 151      if (empty($_SERVER['SERVER_ADDR'])) {
 152          // SERVER_ADDR is only returned by Apache-like webservers
 153          preg_match("@^(?:http[s]?://)?([A-Z0-9\-\.]+).*@i", $CFG->wwwroot, $matches);
 154          $my_hostname = $matches[1];
 155          $my_ip       = gethostbyname($my_hostname);  // Returns unmodified hostname on failure. DOH!
 156          if ($my_ip == $my_hostname) {
 157              $mnethost->ip_address = 'UNKNOWN';
 158          } else {
 159              $mnethost->ip_address = $my_ip;
 160          }
 161      } else {
 162          $mnethost->ip_address = $_SERVER['SERVER_ADDR'];
 163      }
 164  
 165      $mnetid = $DB->insert_record('mnet_host', $mnethost);
 166      set_config('mnet_localhost_id', $mnetid);
 167  
 168      // Initial insert of mnet applications info
 169      $mnet_app = new stdClass();
 170      $mnet_app->name              = 'moodle';
 171      $mnet_app->display_name      = 'Moodle';
 172      $mnet_app->xmlrpc_server_url = '/mnet/xmlrpc/server.php';
 173      $mnet_app->sso_land_url      = '/auth/mnet/land.php';
 174      $mnet_app->sso_jump_url      = '/auth/mnet/jump.php';
 175      $moodleapplicationid = $DB->insert_record('mnet_application', $mnet_app);
 176  
 177      $mnet_app = new stdClass();
 178      $mnet_app->name              = 'mahara';
 179      $mnet_app->display_name      = 'Mahara';
 180      $mnet_app->xmlrpc_server_url = '/api/xmlrpc/server.php';
 181      $mnet_app->sso_land_url      = '/auth/xmlrpc/land.php';
 182      $mnet_app->sso_jump_url      = '/auth/xmlrpc/jump.php';
 183      $DB->insert_record('mnet_application', $mnet_app);
 184  
 185      // Set up the probably-to-be-removed-soon 'All hosts' record
 186      $mnetallhosts                     = new stdClass();
 187      $mnetallhosts->wwwroot            = '';
 188      $mnetallhosts->ip_address         = '';
 189      $mnetallhosts->public_key         = '';
 190      $mnetallhosts->public_key_expires = 0;
 191      $mnetallhosts->last_connect_time  = 0;
 192      $mnetallhosts->last_log_id        = 0;
 193      $mnetallhosts->deleted            = 0;
 194      $mnetallhosts->name               = 'All Hosts';
 195      $mnetallhosts->applicationid      = $moodleapplicationid;
 196      $mnetallhosts->id                 = $DB->insert_record('mnet_host', $mnetallhosts, true);
 197      set_config('mnet_all_hosts_id', $mnetallhosts->id);
 198  
 199      // Create guest record - do not assign any role, guest user gets the default guest role automatically on the fly
 200      if ($DB->record_exists('user', array())) {
 201          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Can not create default users, users already exist.');
 202      }
 203      $guest = new stdClass();
 204      $guest->auth        = 'manual';
 205      $guest->username    = 'guest';
 206      $guest->password    = hash_internal_user_password('guest');
 207      $guest->firstname   = get_string('guestuser');
 208      $guest->lastname    = ' ';
 209      $guest->email       = 'root@localhost';
 210      $guest->description = get_string('guestuserinfo');
 211      $guest->mnethostid  = $CFG->mnet_localhost_id;
 212      $guest->confirmed   = 1;
 213      $guest->lang        = $CFG->lang;
 214      $guest->timemodified= time();
 215      $guest->id = $DB->insert_record('user', $guest);
 216      if ($guest->id != 1) {
 217          echo $OUTPUT->notification('Unexpected id generated for the Guest account. Your database configuration or clustering setup may not be fully supported', 'notifyproblem');
 218      }
 219      // Store guest id
 220      set_config('siteguest', $guest->id);
 221      // Make sure user context exists
 222      context_user::instance($guest->id);
 223  
 224  
 225      // Now create admin user
 226      $admin = new stdClass();
 227      $admin->auth         = 'manual';
 228      $admin->firstname    = get_string('admin');
 229      $admin->lastname     = get_string('user');
 230      $admin->username     = 'admin';
 231      $admin->password     = 'adminsetuppending';
 232      $admin->email        = '';
 233      $admin->confirmed    = 1;
 234      $admin->mnethostid   = $CFG->mnet_localhost_id;
 235      $admin->lang         = $CFG->lang;
 236      $admin->maildisplay  = 1;
 237      $admin->timemodified = time();
 238      $admin->lastip       = CLI_SCRIPT ? '0.0.0.0' : getremoteaddr(); // installation hijacking prevention
 239      $admin->id = $DB->insert_record('user', $admin);
 240  
 241      if ($admin->id != 2) {
 242          echo $OUTPUT->notification('Unexpected id generated for the Admin account. Your database configuration or clustering setup may not be fully supported', 'notifyproblem');
 243      }
 244      if ($admin->id != ($guest->id + 1)) {
 245          echo $OUTPUT->notification('Nonconsecutive id generated for the Admin account. Your database configuration or clustering setup may not be fully supported.', 'notifyproblem');
 246      }
 247  
 248      // Store list of admins
 249      set_config('siteadmins', $admin->id);
 250      // Make sure user context exists
 251      context_user::instance($admin->id);
 252  
 253  
 254      // Install the roles system.
 255      $managerrole        = create_role('', 'manager', '', 'manager');
 256      $coursecreatorrole  = create_role('', 'coursecreator', '', 'coursecreator');
 257      $editteacherrole    = create_role('', 'editingteacher', '', 'editingteacher');
 258      $noneditteacherrole = create_role('', 'teacher', '', 'teacher');
 259      $studentrole        = create_role('', 'student', '', 'student');
 260      $guestrole          = create_role('', 'guest', '', 'guest');
 261      $userrole           = create_role('', 'user', '', 'user');
 262      $frontpagerole      = create_role('', 'frontpage', '', 'frontpage');
 263  
 264      // Now is the correct moment to install capabilities - after creation of legacy roles, but before assigning of roles
 265      update_capabilities('moodle');
 266  
 267  
 268      // Default allow role matrices.
 269      foreach ($DB->get_records('role') as $role) {
 270          foreach (array('assign', 'override', 'switch', 'view') as $type) {
 271              $function = "core_role_set_{$type}_allowed";
 272              $allows = get_default_role_archetype_allows($type, $role->archetype);
 273              foreach ($allows as $allowid) {
 274                  $function($role->id, $allowid);
 275              }
 276          }
 277      }
 278  
 279      // Set up the context levels where you can assign each role.
 280      set_role_contextlevels($managerrole,        get_default_contextlevels('manager'));
 281      set_role_contextlevels($coursecreatorrole,  get_default_contextlevels('coursecreator'));
 282      set_role_contextlevels($editteacherrole,    get_default_contextlevels('editingteacher'));
 283      set_role_contextlevels($noneditteacherrole, get_default_contextlevels('teacher'));
 284      set_role_contextlevels($studentrole,        get_default_contextlevels('student'));
 285      set_role_contextlevels($guestrole,          get_default_contextlevels('guest'));
 286      set_role_contextlevels($userrole,           get_default_contextlevels('user'));
 287  
 288      // Init theme, JS and template revisions.
 289      set_config('themerev', time());
 290      set_config('jsrev', time());
 291      set_config('templaterev', time());
 292  
 293      // No admin setting for this any more, GD is now required, remove in Moodle 2.6.
 294      set_config('gdversion', 2);
 295  
 296      // Install licenses
 297      require_once($CFG->libdir . '/licenselib.php');
 298      license_manager::install_licenses();
 299  
 300      // Init profile pages defaults
 301      if ($DB->record_exists('my_pages', array())) {
 302          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Can not create default profile pages, records already exist.');
 303      }
 304      $mypage = new stdClass();
 305      $mypage->userid = NULL;
 306      $mypage->name = '__default';
 307      $mypage->private = 0;
 308      $mypage->sortorder  = 0;
 309      $DB->insert_record('my_pages', $mypage);
 310      $mypage->private = 1;
 311      $DB->insert_record('my_pages', $mypage);
 312  
 313      $mycoursespage = new stdClass();
 314      $mycoursespage->userid = null;
 315      $mycoursespage->name = '__courses';
 316      $mycoursespage->private = 0;
 317      $mycoursespage->sortorder  = 0;
 318      $DB->insert_record('my_pages', $mycoursespage);
 319  
 320      // Set a sensible default sort order for the most-used question types.
 321      set_config('multichoice_sortorder', 1, 'question');
 322      set_config('truefalse_sortorder', 2, 'question');
 323      set_config('match_sortorder', 3, 'question');
 324      set_config('shortanswer_sortorder', 4, 'question');
 325      set_config('numerical_sortorder', 5, 'question');
 326      set_config('essay_sortorder', 6, 'question');
 327  
 328      require_once($CFG->libdir . '/db/upgradelib.php');
 329      make_default_scale();
 330      make_competence_scale();
 331  
 332      require_once($CFG->dirroot . '/badges/upgradelib.php'); // Core install and upgrade related functions only for badges.
 333      badges_install_default_backpacks();
 334  
 335      // Create default core site admin presets.
 336      require_once($CFG->dirroot . '/admin/presets/classes/helper.php');
 337      \core_adminpresets\helper::create_default_presets();
 338  }