Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 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.
/lib/db/ -> install.php (source)

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 http://docs.moodle.org/dev/Upgrade_API}
  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 http://docs.moodle.org/dev/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('miscellaneous');
 109      $cat->depth        = 1;
 110      $cat->sortorder    = MAX_COURSES_IN_CATEGORY;
 111      $cat->timemodified = time();
 112      $catid = $DB->insert_record('course_categories', $cat);
 113      $DB->set_field('course_categories', 'path', '/'.$catid, array('id'=>$catid));
 114      // Make sure category context exists
 115      context_coursecat::instance($catid);
 116  
 117  
 118      $defaults = array(
 119          'rolesactive'           => '0', // marks fully set up system
 120          'auth'                  => 'email',
 121          'enrol_plugins_enabled' => 'manual,guest,self,cohort',
 122          'theme'                 => theme_config::DEFAULT_THEME,
 123          'filter_multilang_converted' => 1,
 124          'siteidentifier'        => random_string(32).get_host_from_url($CFG->wwwroot),
 125          'backup_version'        => 2008111700,
 126          'backup_release'        => '2.0 dev',
 127          'mnet_dispatcher_mode'  => 'off',
 128          'sessiontimeout'        => 8 * 60 * 60, // Must be present during roles installation.
 129          'stringfilters'         => '', // These two are managed in a strange way by the filters.
 130          'filterall'             => 0, // setting page, so have to be initialised here.
 131          'texteditors'           => 'atto,tinymce,textarea',
 132          'antiviruses'           => '',
 133          'media_plugins_sortorder' => 'videojs,youtube,swf',
 134          'upgrade_extracreditweightsstepignored' => 1, // New installs should not run this upgrade step.
 135          'upgrade_calculatedgradeitemsignored' => 1, // New installs should not run this upgrade step.
 136          'upgrade_letterboundarycourses' => 1, // New installs should not run this upgrade step.
 137      );
 138      foreach($defaults as $key => $value) {
 139          set_config($key, $value);
 140      }
 141  
 142  
 143      // Bootstrap mnet
 144      $mnethost = new stdClass();
 145      $mnethost->wwwroot    = $CFG->wwwroot;
 146      $mnethost->name       = '';
 147      $mnethost->name       = '';
 148      $mnethost->public_key = '';
 149  
 150      if (empty($_SERVER['SERVER_ADDR'])) {
 151          // SERVER_ADDR is only returned by Apache-like webservers
 152          preg_match("@^(?:http[s]?://)?([A-Z0-9\-\.]+).*@i", $CFG->wwwroot, $matches);
 153          $my_hostname = $matches[1];
 154          $my_ip       = gethostbyname($my_hostname);  // Returns unmodified hostname on failure. DOH!
 155          if ($my_ip == $my_hostname) {
 156              $mnethost->ip_address = 'UNKNOWN';
 157          } else {
 158              $mnethost->ip_address = $my_ip;
 159          }
 160      } else {
 161          $mnethost->ip_address = $_SERVER['SERVER_ADDR'];
 162      }
 163  
 164      $mnetid = $DB->insert_record('mnet_host', $mnethost);
 165      set_config('mnet_localhost_id', $mnetid);
 166  
 167      // Initial insert of mnet applications info
 168      $mnet_app = new stdClass();
 169      $mnet_app->name              = 'moodle';
 170      $mnet_app->display_name      = 'Moodle';
 171      $mnet_app->xmlrpc_server_url = '/mnet/xmlrpc/server.php';
 172      $mnet_app->sso_land_url      = '/auth/mnet/land.php';
 173      $mnet_app->sso_jump_url      = '/auth/mnet/jump.php';
 174      $moodleapplicationid = $DB->insert_record('mnet_application', $mnet_app);
 175  
 176      $mnet_app = new stdClass();
 177      $mnet_app->name              = 'mahara';
 178      $mnet_app->display_name      = 'Mahara';
 179      $mnet_app->xmlrpc_server_url = '/api/xmlrpc/server.php';
 180      $mnet_app->sso_land_url      = '/auth/xmlrpc/land.php';
 181      $mnet_app->sso_jump_url      = '/auth/xmlrpc/jump.php';
 182      $DB->insert_record('mnet_application', $mnet_app);
 183  
 184      // Set up the probably-to-be-removed-soon 'All hosts' record
 185      $mnetallhosts                     = new stdClass();
 186      $mnetallhosts->wwwroot            = '';
 187      $mnetallhosts->ip_address         = '';
 188      $mnetallhosts->public_key         = '';
 189      $mnetallhosts->public_key_expires = 0;
 190      $mnetallhosts->last_connect_time  = 0;
 191      $mnetallhosts->last_log_id        = 0;
 192      $mnetallhosts->deleted            = 0;
 193      $mnetallhosts->name               = 'All Hosts';
 194      $mnetallhosts->applicationid      = $moodleapplicationid;
 195      $mnetallhosts->id                 = $DB->insert_record('mnet_host', $mnetallhosts, true);
 196      set_config('mnet_all_hosts_id', $mnetallhosts->id);
 197  
 198      // Create guest record - do not assign any role, guest user gets the default guest role automatically on the fly
 199      if ($DB->record_exists('user', array())) {
 200          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Can not create default users, users already exist.');
 201      }
 202      $guest = new stdClass();
 203      $guest->auth        = 'manual';
 204      $guest->username    = 'guest';
 205      $guest->password    = hash_internal_user_password('guest');
 206      $guest->firstname   = get_string('guestuser');
 207      $guest->lastname    = ' ';
 208      $guest->email       = 'root@localhost';
 209      $guest->description = get_string('guestuserinfo');
 210      $guest->mnethostid  = $CFG->mnet_localhost_id;
 211      $guest->confirmed   = 1;
 212      $guest->lang        = $CFG->lang;
 213      $guest->timemodified= time();
 214      $guest->id = $DB->insert_record('user', $guest);
 215      if ($guest->id != 1) {
 216          echo $OUTPUT->notification('Unexpected id generated for the Guest account. Your database configuration or clustering setup may not be fully supported', 'notifyproblem');
 217      }
 218      // Store guest id
 219      set_config('siteguest', $guest->id);
 220      // Make sure user context exists
 221      context_user::instance($guest->id);
 222  
 223  
 224      // Now create admin user
 225      $admin = new stdClass();
 226      $admin->auth         = 'manual';
 227      $admin->firstname    = get_string('admin');
 228      $admin->lastname     = get_string('user');
 229      $admin->username     = 'admin';
 230      $admin->password     = 'adminsetuppending';
 231      $admin->email        = '';
 232      $admin->confirmed    = 1;
 233      $admin->mnethostid   = $CFG->mnet_localhost_id;
 234      $admin->lang         = $CFG->lang;
 235      $admin->maildisplay  = 1;
 236      $admin->timemodified = time();
 237      $admin->lastip       = CLI_SCRIPT ? '0.0.0.0' : getremoteaddr(); // installation hijacking prevention
 238      $admin->id = $DB->insert_record('user', $admin);
 239  
 240      if ($admin->id != 2) {
 241          echo $OUTPUT->notification('Unexpected id generated for the Admin account. Your database configuration or clustering setup may not be fully supported', 'notifyproblem');
 242      }
 243      if ($admin->id != ($guest->id + 1)) {
 244          echo $OUTPUT->notification('Nonconsecutive id generated for the Admin account. Your database configuration or clustering setup may not be fully supported.', 'notifyproblem');
 245      }
 246  
 247      // Store list of admins
 248      set_config('siteadmins', $admin->id);
 249      // Make sure user context exists
 250      context_user::instance($admin->id);
 251  
 252  
 253      // Install the roles system.
 254      $managerrole        = create_role('', 'manager', '', 'manager');
 255      $coursecreatorrole  = create_role('', 'coursecreator', '', 'coursecreator');
 256      $editteacherrole    = create_role('', 'editingteacher', '', 'editingteacher');
 257      $noneditteacherrole = create_role('', 'teacher', '', 'teacher');
 258      $studentrole        = create_role('', 'student', '', 'student');
 259      $guestrole          = create_role('', 'guest', '', 'guest');
 260      $userrole           = create_role('', 'user', '', 'user');
 261      $frontpagerole      = create_role('', 'frontpage', '', 'frontpage');
 262  
 263      // Now is the correct moment to install capabilities - after creation of legacy roles, but before assigning of roles
 264      update_capabilities('moodle');
 265  
 266  
 267      // Default allow role matrices.
 268      foreach ($DB->get_records('role') as $role) {
 269          foreach (array('assign', 'override', 'switch', 'view') as $type) {
 270              $function = "core_role_set_{$type}_allowed";
 271              $allows = get_default_role_archetype_allows($type, $role->archetype);
 272              foreach ($allows as $allowid) {
 273                  $function($role->id, $allowid);
 274              }
 275          }
 276      }
 277  
 278      // Set up the context levels where you can assign each role.
 279      set_role_contextlevels($managerrole,        get_default_contextlevels('manager'));
 280      set_role_contextlevels($coursecreatorrole,  get_default_contextlevels('coursecreator'));
 281      set_role_contextlevels($editteacherrole,    get_default_contextlevels('editingteacher'));
 282      set_role_contextlevels($noneditteacherrole, get_default_contextlevels('teacher'));
 283      set_role_contextlevels($studentrole,        get_default_contextlevels('student'));
 284      set_role_contextlevels($guestrole,          get_default_contextlevels('guest'));
 285      set_role_contextlevels($userrole,           get_default_contextlevels('user'));
 286  
 287      // Init theme, JS and template revisions.
 288      set_config('themerev', time());
 289      set_config('jsrev', time());
 290      set_config('templaterev', time());
 291  
 292      // No admin setting for this any more, GD is now required, remove in Moodle 2.6.
 293      set_config('gdversion', 2);
 294  
 295      // Install licenses
 296      require_once($CFG->libdir . '/licenselib.php');
 297      license_manager::install_licenses();
 298  
 299      // Init profile pages defaults
 300      if ($DB->record_exists('my_pages', array())) {
 301          throw new moodle_exception('generalexceptionmessage', 'error', '', 'Can not create default profile pages, records already exist.');
 302      }
 303      $mypage = new stdClass();
 304      $mypage->userid = NULL;
 305      $mypage->name = '__default';
 306      $mypage->private = 0;
 307      $mypage->sortorder  = 0;
 308      $DB->insert_record('my_pages', $mypage);
 309      $mypage->private = 1;
 310      $DB->insert_record('my_pages', $mypage);
 311  
 312      // Set a sensible default sort order for the most-used question types.
 313      set_config('multichoice_sortorder', 1, 'question');
 314      set_config('truefalse_sortorder', 2, 'question');
 315      set_config('match_sortorder', 3, 'question');
 316      set_config('shortanswer_sortorder', 4, 'question');
 317      set_config('numerical_sortorder', 5, 'question');
 318      set_config('essay_sortorder', 6, 'question');
 319  
 320      require_once($CFG->libdir . '/db/upgradelib.php');
 321      make_default_scale();
 322      make_competence_scale();
 323  
 324      require_once($CFG->dirroot . '/badges/upgradelib.php'); // Core install and upgrade related functions only for badges.
 325      badges_install_default_backpacks();
 326  }