MDL-73098 install: Detect stale bootstrap.php files and disable them

It's important to say that this bug apparently (till now) only happens
when an *incorrect* instalation of a site happens, reusing the dataroot
from another existing site.

When that happens, the localcache/bootstrap.php file from the old
site is reused, setting siteidentifier and SYSCONTEXTID when it's not
time for them to be defined yet.

Their existenece leads to reusing some other structures from the old
dataroot (that, again, should have been changed or wiped!), ultimately
leading to all sort of errors about non-existent tables (course,
context...).

With this change we ensure that:

1) Whenever any change to the database configuration (prefix, user,
   type..) happens, it's detected and immediately the information
   in the localcache/bootstrap.php is discarded and the file removed.
   This should fix problems like MDL-73098 itself.

2) We only set SYSCONTEXTID if the file is not stale. Main reason
   for doing that check within the localcache/bootstrap.php file
   itself is that we cannot "undefine" it @ setup.php. This should
   prevent errros like MDL-72888 to happen.

3) Finally, little detail, we only define SYSCONTEXTID if it has
   not been defined earlier. In the past, it was recommended to
   define it in config.php (exactly to save one DB read) and, sites
   having them will face "already defined" warnings.
This commit is contained in:
Eloy Lafuente (stronk7) 2021-11-17 19:30:42 +01:00
parent eab63d2cfe
commit 4c0ae3e138
2 changed files with 30 additions and 1 deletions

View File

@ -666,6 +666,12 @@ $bootstrapcachefile = $CFG->localcachedir . '/bootstrap.php';
if (is_readable($bootstrapcachefile)) {
try {
require_once($bootstrapcachefile);
// Verify the file is not stale.
if (!isset($CFG->bootstraphash) || $CFG->bootstraphash !== hash_local_config_cache()) {
// Something has changed, the bootstrap.php file is stale.
unset($CFG->siteidentifier);
@unlink($bootstrapcachefile);
}
} catch (Throwable $e) {
// If it is corrupted then attempt to delete it and it will be rebuilt.
@unlink($bootstrapcachefile);

View File

@ -809,7 +809,11 @@ function initialise_local_config_cache() {
$contents = "<?php
// ********** This file is generated DO NOT EDIT **********
\$CFG->siteidentifier = '" . addslashes($CFG->siteidentifier) . "';
define('SYSCONTEXTID', ".SYSCONTEXTID.");
\$CFG->bootstraphash = '" . hash_local_config_cache() . "';
// Only if the file is not stale and has not been defined.
if (\$CFG->bootstraphash === hash_local_config_cache() && !defined('SYSCONTEXTID')) {
define('SYSCONTEXTID', ".SYSCONTEXTID.");
}
";
$temp = $bootstrapcachefile . '.tmp' . uniqid();
@ -819,6 +823,25 @@ define('SYSCONTEXTID', ".SYSCONTEXTID.");
}
}
/**
* Calculate a proper hash to be able to invalidate stale cached configs.
*
* Only to be used to verify bootstrap.php status.
*
* @return string md5 hash of all the sensible bits deciding if cached config is stale or no.
*/
function hash_local_config_cache() {
global $CFG;
// This is pretty much {@see moodle_database::get_settings_hash()} that is used
// as identifier for the database meta information MUC cache. Should be enough to
// react against any of the normal changes (new prefix, change of DB type) while
// *incorrectly* keeping the old dataroot directory unmodified with stale data.
// This may need more stuff to be considered if it's discovered that there are
// more variables making the file stale.
return md5($CFG->dbtype . $CFG->dbhost . $CFG->dbuser . $CFG->dbname . $CFG->prefix);
}
/**
* Initialises $FULLME and friends. Private function. Should only be called from
* setup.php.