Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
/admin/ -> index.php (source)

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 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   * Main administration script.
  20   *
  21   * @package    core
  22   * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  // Check that config.php exists, if not then call the install script
  27  if (!file_exists('../config.php')) {
  28      header('Location: ../install.php');
  29      die();
  30  }
  31  
  32  // Check that PHP is of a sufficient version as soon as possible.
  33  require_once (__DIR__.'/../lib/phpminimumversionlib.php');
  34  moodle_require_minimum_php_version();
  35  
  36  // make sure iconv is available and actually works
  37  if (!function_exists('iconv')) {
  38      // this should not happen, this must be very borked install
  39      echo 'Moodle requires the iconv PHP extension. Please install or enable the iconv extension.';
  40      die();
  41  }
  42  
  43  // Make sure php5-json is available.
  44  if (!function_exists('json_encode') || !function_exists('json_decode')) {
  45      // This also shouldn't happen.
  46      echo 'Moodle requires the json PHP extension. Please install or enable the json extension.';
  47      die();
  48  }
  49  
  50  // Make sure xml extension is available.
  51  if (!extension_loaded('xml')) {
  52      echo 'Moodle requires the xml PHP extension. Please install or enable the xml extension.';
  53      die();
  54  }
  55  
  56  // Make sure mbstring extension is available.
  57  if (!extension_loaded('mbstring')) {
  58      echo 'Moodle requires the mbstring PHP extension. Please install or enable the mbstring extension.';
  59      die();
  60  }
  61  
  62  define('NO_OUTPUT_BUFFERING', true);
  63  
  64  if (isset($_POST['upgradekey'])) {
  65      // Before you start reporting issues about the collision attacks against
  66      // SHA-1, you should understand that we are not actually attempting to do
  67      // any cryptography here. This is hashed purely so that the key is not
  68      // that apparent in the address bar itself. Anyone who catches the HTTP
  69      // traffic can immediately use it as a valid admin key.
  70      header('Location: index.php?cache=0&upgradekeyhash='.sha1($_POST['upgradekey']));
  71      die();
  72  }
  73  
  74  if ((isset($_GET['cache']) and $_GET['cache'] === '0')
  75          or (isset($_POST['cache']) and $_POST['cache'] === '0')
  76          or (!isset($_POST['cache']) and !isset($_GET['cache']) and empty($_GET['sesskey']) and empty($_POST['sesskey']))) {
  77      // Prevent caching at all cost when visiting this page directly,
  78      // we redirect to self once we known no upgrades are necessary.
  79      // Note: $_GET and $_POST are used here intentionally because our param cleaning is not loaded yet.
  80      // Note2: the sesskey is present in all block editing hacks, we can not redirect there, so enable caching.
  81      define('CACHE_DISABLE_ALL', true);
  82  
  83      // Force OPcache reset if used, we do not want any stale caches
  84      // when detecting if upgrade necessary or when running upgrade.
  85      if (function_exists('opcache_reset')) {
  86          opcache_reset();
  87      }
  88      $cache = 0;
  89  
  90  } else {
  91      $cache = 1;
  92  }
  93  
  94  require('../config.php');
  95  
  96  // Invalidate the cache of version.php in any circumstances to help core_component
  97  // detecting if the version has changed and component cache should be reset.
  98  if (function_exists('opcache_invalidate')) {
  99      opcache_invalidate($CFG->dirroot . '/version.php', true);
 100  }
 101  // Make sure the component cache gets rebuilt if necessary, any method that
 102  // indirectly calls the protected init() method is good here.
 103  core_component::get_core_subsystems();
 104  
 105  if (is_major_upgrade_required() && isloggedin()) {
 106      // A major upgrade is required.
 107      // Terminate the session and redirect back here before anything DB-related happens.
 108      redirect_if_major_upgrade_required();
 109  }
 110  
 111  require_once($CFG->libdir.'/adminlib.php');    // various admin-only functions
 112  require_once($CFG->libdir.'/upgradelib.php');  // general upgrade/install related functions
 113  
 114  $confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL); // Core upgrade confirmed?
 115  $confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL); // Core release info and server checks confirmed?
 116  $confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL); // Plugins check page confirmed?
 117  $showallplugins = optional_param('showallplugins', 0, PARAM_BOOL); // Show all plugins on the plugins check page?
 118  $agreelicense = optional_param('agreelicense', 0, PARAM_BOOL); // GPL license confirmed for installation?
 119  $fetchupdates = optional_param('fetchupdates', 0, PARAM_BOOL); // Should check for available updates?
 120  $newaddonreq = optional_param('installaddonrequest', null, PARAM_RAW); // Plugin installation requested at moodle.org/plugins.
 121  $upgradekeyhash = optional_param('upgradekeyhash', null, PARAM_ALPHANUM); // Hash of provided upgrade key.
 122  $installdep = optional_param('installdep', null, PARAM_COMPONENT); // Install given missing dependency (required plugin).
 123  $installdepx = optional_param('installdepx', false, PARAM_BOOL); // Install all missing dependencies.
 124  $confirminstalldep = optional_param('confirminstalldep', false, PARAM_BOOL); // Installing dependencies confirmed.
 125  $abortinstall = optional_param('abortinstall', null, PARAM_COMPONENT); // Cancel installation of the given new plugin.
 126  $abortinstallx = optional_param('abortinstallx', null, PARAM_BOOL); // Cancel installation of all new plugins.
 127  $confirmabortinstall = optional_param('confirmabortinstall', false, PARAM_BOOL); // Installation cancel confirmed.
 128  $abortupgrade = optional_param('abortupgrade', null, PARAM_COMPONENT); // Cancel upgrade of the given existing plugin.
 129  $abortupgradex = optional_param('abortupgradex', null, PARAM_BOOL); // Cancel upgrade of all upgradable plugins.
 130  $confirmabortupgrade = optional_param('confirmabortupgrade', false, PARAM_BOOL); // Upgrade cancel confirmed.
 131  $installupdate = optional_param('installupdate', null, PARAM_COMPONENT); // Install given available update.
 132  $installupdateversion = optional_param('installupdateversion', null, PARAM_INT); // Version of the available update to install.
 133  $installupdatex = optional_param('installupdatex', false, PARAM_BOOL); // Install all available plugin updates.
 134  $confirminstallupdate = optional_param('confirminstallupdate', false, PARAM_BOOL); // Available update(s) install confirmed?
 135  
 136  if (!empty($CFG->disableupdateautodeploy)) {
 137      // Invalidate all requests to install plugins via the admin UI.
 138      $newaddonreq = null;
 139      $installdep = null;
 140      $installdepx = false;
 141      $abortupgrade = null;
 142      $abortupgradex = null;
 143      $installupdate = null;
 144      $installupdateversion = null;
 145      $installupdatex = false;
 146  }
 147  
 148  // Set up PAGE.
 149  $url = new moodle_url('/admin/index.php');
 150  $url->param('cache', $cache);
 151  if (isset($upgradekeyhash)) {
 152      $url->param('upgradekeyhash', $upgradekeyhash);
 153  }
 154  $PAGE->set_url($url);
 155  unset($url);
 156  
 157  // Are we returning from an add-on installation request at moodle.org/plugins?
 158  if ($newaddonreq and !$cache and empty($CFG->disableupdateautodeploy)) {
 159      $target = new moodle_url('/admin/tool/installaddon/index.php', array(
 160          'installaddonrequest' => $newaddonreq,
 161          'confirm' => 0));
 162      if (!isloggedin() or isguestuser()) {
 163          // Login and go the the add-on tool page.
 164          $SESSION->wantsurl = $target->out();
 165          redirect(get_login_url());
 166      }
 167      redirect($target);
 168  }
 169  
 170  $PAGE->set_pagelayout('admin'); // Set a default pagelayout
 171  
 172  $documentationlink = '<a href="http://docs.moodle.org/en/Installation">Installation docs</a>';
 173  
 174  // Check some PHP server settings
 175  
 176  if (ini_get_bool('session.auto_start')) {
 177      throw new \moodle_exception('phpvaroff', 'debug', '',
 178          (object)array('name' => 'session.auto_start', 'link' => $documentationlink));
 179  }
 180  
 181  if (!ini_get_bool('file_uploads')) {
 182      throw new \moodle_exception('phpvaron', 'debug', '',
 183          (object)array('name' => 'file_uploads', 'link' => $documentationlink));
 184  }
 185  
 186  if (is_float_problem()) {
 187      throw new \moodle_exception('phpfloatproblem', 'admin', '', $documentationlink);
 188  }
 189  
 190  // Set some necessary variables during set-up to avoid PHP warnings later on this page
 191  if (!isset($CFG->release)) {
 192      $CFG->release = '';
 193  }
 194  if (!isset($CFG->version)) {
 195      $CFG->version = '';
 196  }
 197  if (!isset($CFG->branch)) {
 198      $CFG->branch = '';
 199  }
 200  
 201  $version = null;
 202  $release = null;
 203  $branch = null;
 204  require("$CFG->dirroot/version.php");       // defines $version, $release, $branch and $maturity
 205  $CFG->target_release = $release;            // used during installation and upgrades
 206  
 207  if (!$version or !$release) {
 208      throw new \moodle_exception('withoutversion', 'debug'); // Without version, stop.
 209  }
 210  
 211  if (!core_tables_exist()) {
 212      $PAGE->set_pagelayout('maintenance');
 213      $PAGE->set_popup_notification_allowed(false);
 214  
 215      // fake some settings
 216      $CFG->docroot = 'http://docs.moodle.org';
 217  
 218      $strinstallation = get_string('installation', 'install');
 219  
 220      // remove current session content completely
 221      \core\session\manager::terminate_current();
 222  
 223      if (empty($agreelicense)) {
 224          $strlicense = get_string('license');
 225  
 226          $PAGE->navbar->add($strlicense);
 227          $PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . 'Moodle ' . $CFG->target_release, false);
 228          $PAGE->set_heading($strinstallation);
 229          $PAGE->set_cacheable(false);
 230  
 231          $output = $PAGE->get_renderer('core', 'admin');
 232          echo $output->install_licence_page();
 233          die();
 234      }
 235      if (empty($confirmrelease)) {
 236          require_once($CFG->libdir.'/environmentlib.php');
 237          list($envstatus, $environmentresults) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE);
 238          $strcurrentrelease = get_string('currentrelease');
 239  
 240          $PAGE->navbar->add($strcurrentrelease);
 241          $PAGE->set_title($strinstallation);
 242          $PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release);
 243          $PAGE->set_cacheable(false);
 244  
 245          $output = $PAGE->get_renderer('core', 'admin');
 246          echo $output->install_environment_page($maturity, $envstatus, $environmentresults, $release);
 247          die();
 248      }
 249  
 250      // check plugin dependencies
 251      $failed = array();
 252      if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
 253          $PAGE->navbar->add(get_string('pluginscheck', 'admin'));
 254          $PAGE->set_title($strinstallation);
 255          $PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release);
 256  
 257          $output = $PAGE->get_renderer('core', 'admin');
 258          $url = new moodle_url($PAGE->url, array('agreelicense' => 1, 'confirmrelease' => 1, 'lang' => $CFG->lang));
 259          echo $output->unsatisfied_dependencies_page($version, $failed, $url);
 260          die();
 261      }
 262      unset($failed);
 263  
 264      //TODO: add a page with list of non-standard plugins here
 265  
 266      $strdatabasesetup = get_string('databasesetup');
 267      upgrade_init_javascript();
 268  
 269      $PAGE->navbar->add($strdatabasesetup);
 270      $PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . $CFG->target_release, false);
 271      $PAGE->set_heading($strinstallation);
 272      $PAGE->set_cacheable(false);
 273  
 274      $output = $PAGE->get_renderer('core', 'admin');
 275      echo $output->header();
 276  
 277      if (!$DB->setup_is_unicodedb()) {
 278          if (!$DB->change_db_encoding()) {
 279              // If could not convert successfully, throw error, and prevent installation
 280              throw new \moodle_exception('unicoderequired', 'admin');
 281          }
 282      }
 283  
 284      install_core($version, true);
 285  }
 286  
 287  
 288  // Check version of Moodle code on disk compared with database
 289  // and upgrade if possible.
 290  
 291  if (!$cache) {
 292      // Do not try to do anything fancy in non-cached mode,
 293      // this prevents themes from fetching data from non-existent tables.
 294      $PAGE->set_pagelayout('maintenance');
 295      $PAGE->set_popup_notification_allowed(false);
 296  }
 297  
 298  $stradministration = get_string('administration');
 299  $PAGE->set_context(context_system::instance());
 300  
 301  if (empty($CFG->version)) {
 302      throw new \moodle_exception('missingconfigversion', 'debug');
 303  }
 304  
 305  // If an upgrade is running, an admin page starting a frontend upgrade could corrupt the
 306  // DB if the upgrade collided with an already running upgrade process at the wrong time.
 307  // Pull the value direct from the DB, this needs to *always* be correct.
 308  $outagelessupgrade = !empty($DB->get_field('config', 'value', ['name' => 'outagelessupgrade']));
 309  if (!$outagelessupgrade) {
 310      // Detect config cache inconsistency, this happens when you switch branches on dev servers.
 311      if ($CFG->version != $DB->get_field('config', 'value', array('name' => 'version'))) {
 312          purge_all_caches();
 313          redirect(new moodle_url($PAGE->url), 'Config cache inconsistency detected, resetting caches...');
 314      }
 315  
 316      if (!$cache && $version > $CFG->version && !$outagelessupgrade) {  // Upgrade.
 317  
 318          $PAGE->set_url(new moodle_url($PAGE->url, array(
 319              'confirmupgrade' => $confirmupgrade,
 320              'confirmrelease' => $confirmrelease,
 321              'confirmplugincheck' => $confirmplugins,
 322          )));
 323  
 324          check_upgrade_key($upgradekeyhash);
 325  
 326          // Warning about upgrading a test site.
 327          $testsite = false;
 328          if (defined('BEHAT_SITE_RUNNING')) {
 329              $testsite = 'behat';
 330          }
 331  
 332          if (isset($CFG->themerev)) {
 333              // Store the themerev to restore after purging caches.
 334              $themerev = $CFG->themerev;
 335          }
 336  
 337          // We purge all of MUC's caches here.
 338          // Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
 339          // This ensures a real config object is loaded and the stores will be purged.
 340          // This is the only way we can purge custom caches such as memcache or APC.
 341          // Note: all other calls to caches will still used the disabled API.
 342          cache_helper::purge_all(true);
 343          // We then purge the regular caches.
 344          purge_all_caches();
 345  
 346          if (isset($themerev)) {
 347              // Restore the themerev.
 348              set_config('themerev', $themerev);
 349          }
 350  
 351          $output = $PAGE->get_renderer('core', 'admin');
 352  
 353          if (upgrade_stale_php_files_present()) {
 354              $PAGE->set_title($stradministration);
 355              $PAGE->set_cacheable(false);
 356  
 357              echo $output->upgrade_stale_php_files_page();
 358              die();
 359          }
 360  
 361          if (empty($confirmupgrade)) {
 362              $a = new stdClass();
 363              $a->oldversion = "$CFG->release (".sprintf('%.2f', $CFG->version).")";
 364              $a->newversion = "$release (".sprintf('%.2f', $version).")";
 365              $strdatabasechecking = get_string('databasechecking', '', $a);
 366  
 367              $PAGE->set_title($stradministration);
 368              $PAGE->set_heading($strdatabasechecking);
 369              $PAGE->set_cacheable(false);
 370  
 371              echo $output->upgrade_confirm_page($a->newversion, $maturity, $testsite);
 372              die();
 373  
 374          } else if (empty($confirmrelease)) {
 375              require_once($CFG->libdir.'/environmentlib.php');
 376              list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
 377              $strcurrentrelease = get_string('currentrelease');
 378  
 379              $PAGE->navbar->add($strcurrentrelease);
 380              $PAGE->set_title($strcurrentrelease);
 381              $PAGE->set_heading($strcurrentrelease);
 382              $PAGE->set_cacheable(false);
 383  
 384              echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
 385              die();
 386  
 387          } else if (empty($confirmplugins)) {
 388              $strplugincheck = get_string('plugincheck');
 389  
 390              $PAGE->navbar->add($strplugincheck);
 391              $PAGE->set_title($strplugincheck);
 392              $PAGE->set_heading($strplugincheck);
 393              $PAGE->set_cacheable(false);
 394  
 395              $pluginman = core_plugin_manager::instance();
 396  
 397              // Check for available updates.
 398              if ($fetchupdates) {
 399                  // No sesskey support guaranteed here, because sessions might not work yet.
 400                  $updateschecker = \core\update\checker::instance();
 401                  if ($updateschecker->enabled()) {
 402                      $updateschecker->fetch();
 403                  }
 404                  redirect($PAGE->url);
 405              }
 406  
 407              // Cancel all plugin installations.
 408              if ($abortinstallx) {
 409                  // No sesskey support guaranteed here, because sessions might not work yet.
 410                  $abortables = $pluginman->list_cancellable_installations();
 411                  if ($abortables) {
 412                      if ($confirmabortinstall) {
 413                          foreach ($abortables as $plugin) {
 414                              $pluginman->cancel_plugin_installation($plugin->component);
 415                          }
 416                          redirect($PAGE->url);
 417                      } else {
 418                          $continue = new moodle_url($PAGE->url, ['abortinstallx' => $abortinstallx, 'confirmabortinstall' => 1]);
 419                          echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
 420                          die();
 421                      }
 422                  }
 423                  redirect($PAGE->url);
 424              }
 425  
 426              // Cancel single plugin installation.
 427              if ($abortinstall) {
 428                  // No sesskey support guaranteed here, because sessions might not work yet.
 429                  if ($confirmabortinstall) {
 430                      $pluginman->cancel_plugin_installation($abortinstall);
 431                      redirect($PAGE->url);
 432                  } else {
 433                      $continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
 434                      $abortable = $pluginman->get_plugin_info($abortinstall);
 435                      if ($pluginman->can_cancel_plugin_installation($abortable)) {
 436                          echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
 437                          die();
 438                      }
 439                      redirect($PAGE->url);
 440                  }
 441              }
 442  
 443              // Cancel all plugins upgrades (that is, restore archived versions).
 444              if ($abortupgradex) {
 445                  // No sesskey support guaranteed here, because sessions might not work yet.
 446                  $restorable = $pluginman->list_restorable_archives();
 447                  if ($restorable) {
 448                      upgrade_install_plugins($restorable, $confirmabortupgrade,
 449                          get_string('cancelupgradehead', 'core_plugin'),
 450                          new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
 451                      );
 452                  }
 453                  redirect($PAGE->url);
 454              }
 455  
 456              // Cancel single plugin upgrade (that is, install the archived version).
 457              if ($abortupgrade) {
 458                  // No sesskey support guaranteed here, because sessions might not work yet.
 459                  $restorable = $pluginman->list_restorable_archives();
 460                  if (isset($restorable[$abortupgrade])) {
 461                      $restorable = array($restorable[$abortupgrade]);
 462                      upgrade_install_plugins($restorable, $confirmabortupgrade,
 463                          get_string('cancelupgradehead', 'core_plugin'),
 464                          new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
 465                      );
 466                  }
 467                  redirect($PAGE->url);
 468              }
 469  
 470              // Install all available missing dependencies.
 471              if ($installdepx) {
 472                  // No sesskey support guaranteed here, because sessions might not work yet.
 473                  $installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
 474                  upgrade_install_plugins($installable, $confirminstalldep,
 475                      get_string('dependencyinstallhead', 'core_plugin'),
 476                      new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
 477                  );
 478              }
 479  
 480              // Install single available missing dependency.
 481              if ($installdep) {
 482                  // No sesskey support guaranteed here, because sessions might not work yet.
 483                  $installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
 484                  if (!empty($installable[$installdep])) {
 485                      $installable = array($installable[$installdep]);
 486                      upgrade_install_plugins($installable, $confirminstalldep,
 487                          get_string('dependencyinstallhead', 'core_plugin'),
 488                          new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
 489                      );
 490                  }
 491              }
 492  
 493              // Install all available updates.
 494              if ($installupdatex) {
 495                  // No sesskey support guaranteed here, because sessions might not work yet.
 496                  $installable = $pluginman->filter_installable($pluginman->available_updates());
 497                  upgrade_install_plugins($installable, $confirminstallupdate,
 498                      get_string('updateavailableinstallallhead', 'core_admin'),
 499                      new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
 500                  );
 501              }
 502  
 503              // Install single available update.
 504              if ($installupdate and $installupdateversion) {
 505                  // No sesskey support guaranteed here, because sessions might not work yet.
 506                  if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
 507                      $installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
 508                      upgrade_install_plugins($installable, $confirminstallupdate,
 509                          get_string('updateavailableinstallallhead', 'core_admin'),
 510                          new moodle_url($PAGE->url, array('installupdate' => $installupdate,
 511                              'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
 512                          )
 513                      );
 514                  }
 515              }
 516  
 517              echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
 518                      $version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
 519              die();
 520  
 521          } else {
 522              // Always verify plugin dependencies!
 523              $failed = array();
 524              if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
 525                  echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
 526                      array('confirmplugincheck' => 0)));
 527                  die();
 528              }
 529              unset($failed);
 530  
 531              // Launch main upgrade.
 532              upgrade_core($version, true);
 533          }
 534      } else if ($version < $CFG->version) {
 535          // Better stop here, we can not continue with plugin upgrades or anything else.
 536          throw new moodle_exception('downgradedcore', 'error', new moodle_url('/admin/'));
 537      }
 538  
 539      // Updated human-readable release version if necessary.
 540      if (!$cache && $release <> $CFG->release ) {  // Update the release version.
 541          set_config('release', $release);
 542      }
 543  
 544      if (!$cache && $branch <> $CFG->branch) {  // Update the branch.
 545          set_config('branch', $branch);
 546      }
 547  
 548      if (!$cache && moodle_needs_upgrading()) {
 549  
 550          $PAGE->set_url(new moodle_url($PAGE->url, array(
 551              'confirmrelease' => $confirmrelease,
 552              'confirmplugincheck' => $confirmplugins,
 553          )));
 554  
 555          check_upgrade_key($upgradekeyhash);
 556  
 557          if (!$PAGE->headerprinted) {
 558              // Means core upgrade or installation was not already done.
 559  
 560              $pluginman = core_plugin_manager::instance();
 561              $output = $PAGE->get_renderer('core', 'admin');
 562  
 563              if (empty($confirmrelease)) {
 564                  require_once($CFG->libdir . '/environmentlib.php');
 565  
 566                  list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
 567                  $strcurrentrelease = get_string('currentrelease');
 568  
 569                  $PAGE->navbar->add($strcurrentrelease);
 570                  $PAGE->set_title($strcurrentrelease);
 571                  $PAGE->set_heading($strcurrentrelease);
 572                  $PAGE->set_cacheable(false);
 573  
 574                  echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
 575                  die();
 576  
 577              } else if (!$confirmplugins) {
 578                  $strplugincheck = get_string('plugincheck');
 579  
 580                  $PAGE->navbar->add($strplugincheck);
 581                  $PAGE->set_title($strplugincheck);
 582                  $PAGE->set_heading($strplugincheck);
 583                  $PAGE->set_cacheable(false);
 584  
 585                  // Check for available updates.
 586                  if ($fetchupdates) {
 587                      require_sesskey();
 588                      $updateschecker = \core\update\checker::instance();
 589                      if ($updateschecker->enabled()) {
 590                          $updateschecker->fetch();
 591                      }
 592                      redirect($PAGE->url);
 593                  }
 594  
 595                  // Cancel all plugin installations.
 596                  if ($abortinstallx) {
 597                      require_sesskey();
 598                      $abortables = $pluginman->list_cancellable_installations();
 599                      if ($abortables) {
 600                          if ($confirmabortinstall) {
 601                              foreach ($abortables as $plugin) {
 602                                  $pluginman->cancel_plugin_installation($plugin->component);
 603                              }
 604                              redirect($PAGE->url);
 605                          } else {
 606                              $continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx,
 607                                  'confirmabortinstall' => 1));
 608                              echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
 609                              die();
 610                          }
 611                      }
 612                      redirect($PAGE->url);
 613                  }
 614  
 615                  // Cancel single plugin installation.
 616                  if ($abortinstall) {
 617                      require_sesskey();
 618                      if ($confirmabortinstall) {
 619                          $pluginman->cancel_plugin_installation($abortinstall);
 620                          redirect($PAGE->url);
 621                      } else {
 622                          $continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
 623                          $abortable = $pluginman->get_plugin_info($abortinstall);
 624                          if ($pluginman->can_cancel_plugin_installation($abortable)) {
 625                              echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
 626                              die();
 627                          }
 628                          redirect($PAGE->url);
 629                      }
 630                  }
 631  
 632                  // Cancel all plugins upgrades (that is, restore archived versions).
 633                  if ($abortupgradex) {
 634                      require_sesskey();
 635                      $restorable = $pluginman->list_restorable_archives();
 636                      if ($restorable) {
 637                          upgrade_install_plugins($restorable, $confirmabortupgrade,
 638                              get_string('cancelupgradehead', 'core_plugin'),
 639                              new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
 640                          );
 641                      }
 642                      redirect($PAGE->url);
 643                  }
 644  
 645                  // Cancel single plugin upgrade (that is, install the archived version).
 646                  if ($abortupgrade) {
 647                      require_sesskey();
 648                      $restorable = $pluginman->list_restorable_archives();
 649                      if (isset($restorable[$abortupgrade])) {
 650                          $restorable = array($restorable[$abortupgrade]);
 651                          upgrade_install_plugins($restorable, $confirmabortupgrade,
 652                              get_string('cancelupgradehead', 'core_plugin'),
 653                              new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
 654                          );
 655                      }
 656                      redirect($PAGE->url);
 657                  }
 658  
 659                  // Install all available missing dependencies.
 660                  if ($installdepx) {
 661                      require_sesskey();
 662                      $installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
 663                      upgrade_install_plugins($installable, $confirminstalldep,
 664                          get_string('dependencyinstallhead', 'core_plugin'),
 665                          new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
 666                      );
 667                  }
 668  
 669                  // Install single available missing dependency.
 670                  if ($installdep) {
 671                      require_sesskey();
 672                      $installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
 673                      if (!empty($installable[$installdep])) {
 674                          $installable = array($installable[$installdep]);
 675                          upgrade_install_plugins($installable, $confirminstalldep,
 676                              get_string('dependencyinstallhead', 'core_plugin'),
 677                              new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
 678                          );
 679                      }
 680                  }
 681  
 682                  // Install all available updates.
 683                  if ($installupdatex) {
 684                      require_sesskey();
 685                      $installable = $pluginman->filter_installable($pluginman->available_updates());
 686                      upgrade_install_plugins($installable, $confirminstallupdate,
 687                          get_string('updateavailableinstallallhead', 'core_admin'),
 688                          new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
 689                      );
 690                  }
 691  
 692                  // Install single available update.
 693                  if ($installupdate && $installupdateversion) {
 694                      require_sesskey();
 695                      if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
 696                          $installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
 697                          upgrade_install_plugins($installable, $confirminstallupdate,
 698                              get_string('updateavailableinstallallhead', 'core_admin'),
 699                              new moodle_url($PAGE->url, array('installupdate' => $installupdate,
 700                                  'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
 701                              )
 702                          );
 703                      }
 704                  }
 705  
 706                  // Show plugins info.
 707                  echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
 708                          $version, $showallplugins,
 709                          new moodle_url($PAGE->url),
 710                          new moodle_url($PAGE->url, array('confirmplugincheck' => 1, 'cache' => 0)));
 711                  die();
 712              }
 713  
 714              // Make sure plugin dependencies are always checked.
 715              $failed = array();
 716              if (!$pluginman->all_plugins_ok($version, $failed, $CFG->branch)) {
 717                  $output = $PAGE->get_renderer('core', 'admin');
 718                  echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
 719                      array('confirmplugincheck' => 0)));
 720                  die();
 721              }
 722              unset($failed);
 723          }
 724  
 725          // Install/upgrade all plugins and other parts.
 726          upgrade_noncore(true);
 727      }
 728  
 729      // If this is the first install, indicate that this site is fully configured,
 730      // Except the admin password.
 731      if (during_initial_install()) {
 732          set_config('rolesactive', 1); // After this, during_initial_install will return false.
 733          set_config('adminsetuppending', 1);
 734          set_config('registrationpending', 1); // Remind to register site after all other setup is finished.
 735  
 736          // Apply default preset, if it is defined in $CFG and has a valid value.
 737          if (!empty($CFG->setsitepresetduringinstall)) {
 738              \core_adminpresets\helper::change_default_preset($CFG->setsitepresetduringinstall);
 739          }
 740  
 741          // We need this redirect to setup proper session.
 742          upgrade_finished("index.php?sessionstarted=1&amp;lang=$CFG->lang");
 743      }
 744  
 745      // Make sure admin user is created - this is the last step,
 746      // We need session to be working properly in order to edit admin account.
 747      if (!empty($CFG->adminsetuppending)) {
 748          $sessionstarted = optional_param('sessionstarted', 0, PARAM_BOOL);
 749          if (!$sessionstarted) {
 750              redirect("index.php?sessionstarted=1&lang=$CFG->lang");
 751          } else {
 752              $sessionverify = optional_param('sessionverify', 0, PARAM_BOOL);
 753              if (!$sessionverify) {
 754                  $SESSION->sessionverify = 1;
 755                  redirect("index.php?sessionstarted=1&sessionverify=1&lang=$CFG->lang");
 756              } else {
 757                  if (empty($SESSION->sessionverify)) {
 758                      throw new \moodle_exception('installsessionerror', 'admin', "index.php?sessionstarted=1&lang=$CFG->lang");
 759                  }
 760                  unset($SESSION->sessionverify);
 761              }
 762          }
 763  
 764          // Cleanup SESSION to make sure other code does not complain in the future.
 765          unset($SESSION->has_timed_out);
 766          unset($SESSION->wantsurl);
 767  
 768          // At this stage there can be only one admin unless more were added by install,
 769          // Users may change username, so do not rely on that.
 770          $adminids = explode(',', $CFG->siteadmins);
 771          $adminuser = get_complete_user_data('id', reset($adminids));
 772  
 773          if ($adminuser->password === 'adminsetuppending') {
 774              // Prevent installation hijacking.
 775              if ($adminuser->lastip !== getremoteaddr()) {
 776                  throw new \moodle_exception('installhijacked', 'admin');
 777              }
 778              // Login user and let him set password and admin details.
 779              $adminuser->newadminuser = 1;
 780              complete_user_login($adminuser);
 781              redirect("$CFG->wwwroot/user/editadvanced.php?id=$adminuser->id"); // Edit thyself.
 782  
 783          } else {
 784              unset_config('adminsetuppending');
 785          }
 786  
 787      } else {
 788          // Just make sure upgrade logging is properly terminated.
 789          upgrade_finished('upgradesettings.php');
 790      }
 791  }
 792  
 793  if (has_capability('moodle/site:config', context_system::instance())) {
 794      if ($fetchupdates) {
 795          require_sesskey();
 796          $updateschecker = \core\update\checker::instance();
 797          if ($updateschecker->enabled()) {
 798              $updateschecker->fetch();
 799          }
 800          redirect(new moodle_url('/admin/index.php', array('cache' => 0)));
 801      }
 802  }
 803  
 804  // Now we can be sure everything was upgraded and caches work fine,
 805  // redirect if necessary to make sure caching is enabled.
 806  if (!$cache) {
 807      redirect(new moodle_url('/admin/index.php', array('cache' => 1)));
 808  }
 809  
 810  // Check for valid admin user - no guest autologin
 811  require_login(0, false);
 812  if (isguestuser()) {
 813      // Login as real user!
 814      $SESSION->wantsurl = (string)new moodle_url('/admin/index.php');
 815      redirect(get_login_url());
 816  }
 817  $context = context_system::instance();
 818  
 819  if (!has_capability('moodle/site:config', $context)) {
 820      // Do not throw exception display an empty page with administration menu if visible for current user.
 821      $PAGE->set_title(get_string('home'));
 822      $PAGE->set_heading($SITE->fullname);
 823      echo $OUTPUT->header();
 824      echo $OUTPUT->footer();
 825      exit;
 826  }
 827  
 828  // check that site is properly customized
 829  $site = get_site();
 830  if (empty($site->shortname)) {
 831      // probably new installation - lets return to frontpage after this step
 832      // remove settings that we want uninitialised
 833      unset_config('registerauth');
 834      unset_config('timezone'); // Force admin to select timezone!
 835      redirect('upgradesettings.php?return=site');
 836  }
 837  
 838  // setup critical warnings before printing admin tree block
 839  $insecuredataroot = is_dataroot_insecure(true);
 840  $SESSION->admin_critical_warning = ($insecuredataroot==INSECURE_DATAROOT_ERROR);
 841  
 842  $adminroot = admin_get_root();
 843  $PAGE->set_primary_active_tab('siteadminnode');
 844  
 845  // Check if there are any new admin settings which have still yet to be set
 846  if (any_new_admin_settings($adminroot)) {
 847      redirect('upgradesettings.php');
 848  }
 849  
 850  // Return to original page that started the plugin uninstallation if necessary.
 851  if (isset($SESSION->pluginuninstallreturn)) {
 852      $return = $SESSION->pluginuninstallreturn;
 853      unset($SESSION->pluginuninstallreturn);
 854      if ($return) {
 855          redirect($return);
 856      }
 857  }
 858  
 859  // If site registration needs updating, redirect.
 860  \core\hub\registration::registration_reminder('/admin/index.php');
 861  
 862  // Everything should now be set up, and the user is an admin
 863  
 864  // Print default admin page with notifications.
 865  $errorsdisplayed = defined('WARN_DISPLAY_ERRORS_ENABLED');
 866  
 867  $lastcron = get_config('tool_task', 'lastcronstart');
 868  $cronoverdue = ($lastcron < time() - 3600 * 24);
 869  $lastcroninterval = get_config('tool_task', 'lastcroninterval');
 870  
 871  $expectedfrequency = $CFG->expectedcronfrequency ?? MINSECS;
 872  $croninfrequent = !$cronoverdue && ($lastcroninterval > ($expectedfrequency + MINSECS) || $lastcron < time() - $expectedfrequency);
 873  $dbproblems = $DB->diagnose();
 874  $maintenancemode = !empty($CFG->maintenance_enabled);
 875  
 876  // Available updates for Moodle core.
 877  $updateschecker = \core\update\checker::instance();
 878  $availableupdates = array();
 879  $availableupdatesfetch = null;
 880  
 881  if ($updateschecker->enabled()) {
 882      // Only compute the update information when it is going to be displayed to the user.
 883      $availableupdates['core'] = $updateschecker->get_update_info('core',
 884          array('minmaturity' => $CFG->updateminmaturity, 'notifybuilds' => $CFG->updatenotifybuilds));
 885  
 886      // Available updates for contributed plugins
 887      $pluginman = core_plugin_manager::instance();
 888      foreach ($pluginman->get_plugins() as $plugintype => $plugintypeinstances) {
 889          foreach ($plugintypeinstances as $pluginname => $plugininfo) {
 890              $pluginavailableupdates = $plugininfo->available_updates();
 891              if (!empty($pluginavailableupdates)) {
 892                  foreach ($pluginavailableupdates as $pluginavailableupdate) {
 893                      if (!isset($availableupdates[$plugintype.'_'.$pluginname])) {
 894                          $availableupdates[$plugintype.'_'.$pluginname] = array();
 895                      }
 896                      $availableupdates[$plugintype.'_'.$pluginname][] = $pluginavailableupdate;
 897                  }
 898              }
 899          }
 900      }
 901  
 902      // The timestamp of the most recent check for available updates
 903      $availableupdatesfetch = $updateschecker->get_last_timefetched();
 904  }
 905  
 906  $buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
 907  //check if the site is registered on Moodle.org
 908  $registered = \core\hub\registration::is_registered();
 909  // Check if there are any cache warnings.
 910  $cachewarnings = cache_helper::warnings();
 911  // Check if there are events 1 API handlers.
 912  $eventshandlers = $DB->get_records_sql('SELECT DISTINCT component FROM {events_handlers}');
 913  $themedesignermode = !empty($CFG->themedesignermode);
 914  $mobileconfigured = !empty($CFG->enablemobilewebservice);
 915  $invalidforgottenpasswordurl = !empty($CFG->forgottenpasswordurl) && empty(clean_param($CFG->forgottenpasswordurl, PARAM_URL));
 916  
 917  // Check if a directory with development libraries exists.
 918  if (empty($CFG->disabledevlibdirscheck) && (is_dir($CFG->dirroot.'/vendor') || is_dir($CFG->dirroot.'/node_modules'))) {
 919      $devlibdir = true;
 920  } else {
 921      $devlibdir = false;
 922  }
 923  // Check if the site is being foced onto ssl.
 924  $overridetossl = !empty($CFG->overridetossl);
 925  
 926  // Check if moodle campaign content setting is enabled or not.
 927  $showcampaigncontent = !isset($CFG->showcampaigncontent) || $CFG->showcampaigncontent;
 928  
 929  // Encourage admins to enable the user feedback feature if it is not enabled already.
 930  $showfeedbackencouragement = empty($CFG->enableuserfeedback);
 931  
 932  // Check if the service and support content setting is enabled or not.
 933  $servicesandsupportcontent = !isset($CFG->showservicesandsupportcontent) || $CFG->showservicesandsupportcontent;
 934  
 935  // Check whether the XML-RPC protocol is enabled or not.
 936  require_once($CFG->libdir . '/environmentlib.php');
 937  $result = new environment_results('custom_checks');
 938  $result = check_xmlrpc_usage($result);
 939  $xmlrpcwarning = !is_null($result) ? get_string($result->getFeedbackStr(), 'admin') : '';
 940  
 941  admin_externalpage_setup('adminnotifications');
 942  
 943  $output = $PAGE->get_renderer('core', 'admin');
 944  
 945  echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
 946                                         $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
 947                                         $registered, $cachewarnings, $eventshandlers, $themedesignermode, $devlibdir,
 948                                         $mobileconfigured, $overridetossl, $invalidforgottenpasswordurl, $croninfrequent,
 949                                         $showcampaigncontent, $showfeedbackencouragement, $servicesandsupportcontent,
 950                                         $xmlrpcwarning);