/** * Initialise caches, always call before accessing self:: caches. */ protected static function init() { global $CFG; // Init only once per request/CLI execution, we ignore changes done afterwards. if (isset(self::$plugintypes)) { return; } if (defined('IGNORE_COMPONENT_CACHE') and IGNORE_COMPONENT_CACHE) { self::fill_all_caches(); return; } if (!empty($CFG->alternative_component_cache)) { // Hack for heavily clustered sites that want to manage component cache invalidation manually. $cachefile = $CFG->alternative_component_cache; if (file_exists($cachefile)) { if (CACHE_DISABLE_ALL) { // Verify the cache state only on upgrade pages. $content = self::get_cache_content(); if (sha1_file($cachefile) !== sha1($content)) { die('Outdated component cache file defined in $CFG->alternative_component_cache, can not continue'); } return; } $cache = array(); include $cachefile; self::$plugintypes = $cache['plugintypes']; self::$plugins = $cache['plugins']; self::$subsystems = $cache['subsystems']; self::$parents = $cache['parents']; self::$subplugins = $cache['subplugins']; self::$classmap = $cache['classmap']; self::$filemap = $cache['filemap']; return; } if (!is_writable(dirname($cachefile))) { die('Can not create alternative component cache file defined in $CFG->alternative_component_cache, can not continue'); } // Lets try to create the file, it might be in some writable directory or a local cache dir. } else { // Note: $CFG->cachedir MUST be shared by all servers in a cluster, // use $CFG->alternative_component_cache if you do not like it. $cachefile = "{$CFG->cachedir}/core_component.php"; } if (!CACHE_DISABLE_ALL and !self::is_developer()) { // 1/ Use the cache only outside of install and upgrade. // 2/ Let developers add/remove classes in developer mode. if (is_readable($cachefile)) { $cache = false; include $cachefile; if (!is_array($cache)) { // Something is very wrong. } else { if (!isset($cache['version'])) { // Something is very wrong. } else { if ((double) $cache['version'] !== (double) self::fetch_core_version()) { // Outdated cache. We trigger an error log to track an eventual repetitive failure of float comparison. error_log('Resetting core_component cache after core upgrade to version ' . self::fetch_core_version()); } else { if ($cache['plugintypes']['mod'] !== "{$CFG->dirroot}/mod") { // $CFG->dirroot was changed. } else { // The cache looks ok, let's use it. self::$plugintypes = $cache['plugintypes']; self::$plugins = $cache['plugins']; self::$subsystems = $cache['subsystems']; self::$parents = $cache['parents']; self::$subplugins = $cache['subplugins']; self::$classmap = $cache['classmap']; self::$filemap = $cache['filemap']; return; } } } } // Note: we do not verify $CFG->admin here intentionally, // they must visit admin/index.php after any change. } } if (!isset(self::$plugintypes)) { // This needs to be atomic and self-fixing as much as possible. $content = self::get_cache_content(); if (file_exists($cachefile)) { if (sha1_file($cachefile) === sha1($content)) { return; } // Stale cache detected! unlink($cachefile); } // Permissions might not be setup properly in installers. $dirpermissions = !isset($CFG->directorypermissions) ? 02777 : $CFG->directorypermissions; $filepermissions = !isset($CFG->filepermissions) ? $dirpermissions & 0666 : $CFG->filepermissions; clearstatcache(); $cachedir = dirname($cachefile); if (!is_dir($cachedir)) { mkdir($cachedir, $dirpermissions, true); } if ($fp = @fopen($cachefile . '.tmp', 'xb')) { fwrite($fp, $content); fclose($fp); @rename($cachefile . '.tmp', $cachefile); @chmod($cachefile, $filepermissions); } @unlink($cachefile . '.tmp'); // Just in case anything fails (race condition). self::invalidate_opcode_php_cache($cachefile); } }