diff -u b/includes/bootstrap.inc b/includes/bootstrap.inc --- b/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -845,4 +845,8 @@ static $files = array(); + // This flag may hold a string that indicates where the filename was retrieved + // from. + $filename_retrieved_from = ''; + // Profiles are a special case: they have a fixed location and naming. if ($type == 'profile') { @@ -856,6 +860,7 @@ if (!empty($filename) && file_exists($filename)) { // Prime the static cache with the provided filename. $files[$type][$name] = $filename; + $filename_retrieved_from = 'priming'; } elseif (isset($files[$type][$name])) { // This item had already been found earlier in the request, either through @@ -864,34 +869,40 @@ // Do nothing. } else { - $system_filepaths = &drupal_static('system_filepaths'); - if (!isset($system_filepaths[$type][$name])) { - // Look for the filename listed in the {system} table. - // Verify that we have an active database connection, before querying - // the database. This is required because this function is called both - // before we have a database connection (i.e. during installation) and - // when a database connection fails. - try { - if (function_exists('db_query')) { - $file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array( - ':name' => $name, - ':type' => $type - ))->fetchField(); - if ($file !== FALSE) { - $system_filepaths[$type][$name] = $file; - if (file_exists(DRUPAL_ROOT . '/' . $file)) { - $files[$type][$name] = $file; - } + // Look for the filename listed in the {system} table. + // Verify that we have an active database connection, before querying + // the database. This is required because this function is called both + // before we have a database connection (i.e. during installation) and + // when a database connection fails. + try { + $system_query_success = FALSE; + if (function_exists('db_query')) { + $file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array( + ':name' => $name, + ':type' => $type + ))->fetchField(); + if ($file !== FALSE) { + if (file_exists(DRUPAL_ROOT . '/' . $file)) { + $files[$type][$name] = $file; + $filename_retrieved_from = 'system_table'; } } + $system_query_success = TRUE; } - catch (Exception $e) { - // The database table may not exist because Drupal is not yet installed, - // the database might be down, or we may have done a non-database cache - // flush while $conf['page_cache_without_database'] = TRUE and - // $conf['page_cache_invoke_hooks'] = TRUE. We have a fallback for these - // cases so we hide the error completely. - } + } + catch (Exception $e) { + // The database table may not exist because Drupal is not yet installed, + // the database might be down, or we may have done a non-database cache + // flush while $conf['page_cache_without_database'] = TRUE and + // $conf['page_cache_invoke_hooks'] = TRUE. We have a fallback for these + // cases so we hide the error completely. + // We also hide the trigger_error() "moved or newly introduced" warning + // in this case as we can't be sure if it's correct. + } + if (!$system_query_success) { + // We can't tell if the error message will be valid if the query to the + // {system} table failed, so skip triggering of errors. + $trigger_error = FALSE; } // Fall back to searching the filesystem if the database could not find the // file or the file does not exist at the path returned by the database. @@ -902,10 +913,19 @@ if (isset($files[$type][$name])) { // We found a file. + // Get the static file scan list. This list may be incomplete as there + // may be further files listed in persistent cache, but we skip loading that + // as a performance optimization, as the persistent cache record will + // be cleared on every system_rebuild_module_data() anyway. $file_scans = &drupal_static('_drupal_get_filename_fallback'); // If this file had previously been marked as missing, clean up the entry // from the file scan cache. - if (isset($file_scans[$type][$name]) && $file_scans[$type][$name] === FALSE) { + $missing_reappeared = isset($file_scans[$type][$name]) && $file_scans[$type][$name] === FALSE; + // If this file had previously been marked as moved, and reappeared + // at the location listed in the system table or in the primed static, + // clean up the entry from the file scan cache. + $moved_reappeared = isset($file_scans[$type][$name]) && is_string($file_scans[$type][$name]) && ($filename_retrieved_from == 'system_table' || $filename_retrieved_from == 'priming'); + if ($missing_reappeared || $moved_reappeared) { $file_scans[$type][$name] = NULL; $file_scans['#write_cache'] = TRUE; } @@ -937,7 +957,7 @@ // keys the type and name of the item, and as value: // - the boolean FALSE if the item is missing // - a string with location found in a file scan if the module/theme has moved - // from the location listed in the {system} table. + // from the location listed in the {system} table. $file_scans = &drupal_static('_drupal_get_filename_fallback'); if (!isset($file_scans)) { $file_scans = array(); @@ -964,8 +984,8 @@ } } - // Check whether this file had previously moved from the path listed in the - // {system} table. + // Check whether this file had moved from the path listed in the {system} + // table during a previous file scan. if (isset($file_scans[$type][$name]) && is_string($file_scans[$type][$name]) && file_exists($file_scans[$type][$name])) { // The file exists at the location cached in a previous file scan. $filename_from_file_scan = $file_scans[$type][$name]; @@ -976,22 +996,22 @@ } if (isset($filename_from_file_scan)) { - // Check whether the file we found was listed as being in another - // location in the {system} table. - $system_filepaths = &drupal_static('system_filepaths'); - if (isset($system_filepaths[$type][$name]) && $system_filepaths[$type][$name] != $filename_from_file_scan) { - // Make sure our change to the file scan cache will be written to - // the persistent cache. - if (!isset($file_scans[$type][$name]) || isset($file_scans[$type][$name]) && $file_scans[$type][$name] != $filename_from_file_scan) { - $file_scans['#write_cache'] = TRUE; - } - // This file has moved. Store its new location in the file scan cache. + // The file has either moved from the location in the {system} table + // or is not yet listed in the {system} table. + // Make sure our change to the file scan cache will be written to the + // persistent cache. + if (!isset($file_scans[$type][$name]) || isset($file_scans[$type][$name]) && $file_scans[$type][$name] != $filename_from_file_scan) { $file_scans[$type][$name] = $filename_from_file_scan; - // Create a user-level warning about the moved file. - if ($trigger_error) { - _drupal_get_filename_fallback_trigger_error($type, $name, 'moved'); + if (!$trigger_error) { + // If we skip error triggering, do not write the found file location to + // persistent cache. + $file_scans['#write_cache'] = TRUE; } } + // Create a user-level warning about the moved / recently introduced file. + if ($trigger_error) { + _drupal_get_filename_fallback_trigger_error($type, $name, 'moved'); + } return $filename_from_file_scan; } else { @@ -1023,14 +1043,15 @@ * The type of the error ('missing' or 'moved'). */ function _drupal_get_filename_fallback_trigger_error($type, $name, $error_type) { - // Make sure we only show any missing/moved file error only once per request. + // Make sure we only show any missing / moved file error only once per + // request. static $errors_triggered = array(); if (empty($errors_triggered[$type][$name][$error_type])) { if ($error_type == 'missing') { - trigger_error(format_string('The following %type is missing from the file system: %name. In order to fix this, put the file back in its original location or uninstall the module. For more information, see the documentation page.', array('%type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING); + trigger_error(format_string('The following @type is missing from the file system: %name. In order to fix this, put the file back in its original location or uninstall the module. For more information, see the documentation page.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING); } elseif ($error_type == 'moved') { - trigger_error(format_string('The following %type has moved within the file system: %name. In order to fix this, clear caches or put the file back in its original location. For more information, see the documentation page.', array('%type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING); + trigger_error(format_string('The following @type has moved or has recently appeared within the file system: %name. In order to fix this, clear caches or put the file back in its original location. For more information, see the documentation page.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING); } $errors_triggered[$type][$name][$error_type] = TRUE; } @@ -1105,8 +1126,8 @@ } $file_scans = &drupal_static('_drupal_get_filename_fallback'); if (isset($file_scans['#write_cache'])) { - // Merge the newly found out missing and moved file data with - // the previously existing data, if we had not done so yet. + // Merge the newly found out missing and moved file data with the previously + // existing data, if we had not done so yet. if (!isset($file_scans['#cache_merge_done'])) { $cache = cache_get('_drupal_get_filename_fallback', 'cache_bootstrap'); if (isset($cache->data)) { diff -u b/includes/module.inc b/includes/module.inc --- b/includes/module.inc +++ b/includes/module.inc @@ -121,7 +121,6 @@ */ function system_list($type) { $lists = &drupal_static(__FUNCTION__); - $system_filepaths = &drupal_static('system_filepaths'); // For bootstrap modules, attempt to fetch the list from cache if possible. // if not fetch only the required information to fire bootstrap hooks @@ -210,10 +209,7 @@ cache_set('system_list', $lists, 'cache_bootstrap'); } foreach ($lists['filepaths'] as $item) { - // Save the file paths from the database into a static variable so we - // can determine later if the files have moved. - $system_filepaths[$item['type']][$item['name']] = $item['filepath']; - // To avoid a separate database lookup for the filepath, prime the + // To avoid a separate database lookup for the file path, prime the // drupal_get_filename() static cache with all enabled modules and all // themes. drupal_get_filename($item['type'], $item['name'], $item['filepath']); diff -u b/includes/update.inc b/includes/update.inc --- b/includes/update.inc +++ b/includes/update.inc @@ -797,7 +797,7 @@ // 'Default' profile has been renamed to 'Standard' in D7. // We change the profile here to prevent a broken record in the system table. - // @see system_update_7049() + // See system_update_7049() if ($profile == 'default') { $profile = 'standard'; variable_set('install_profile', $profile);