diff --git a/web/registry_rebuild.php b/web/registry_rebuild.php
new file mode 100644
index 000000000..7f1fa1894
--- /dev/null
+++ b/web/registry_rebuild.php
@@ -0,0 +1,247 @@
+\n";
+define('MAINTENANCE_MODE', 'update');
+
+global $_SERVER;
+$_SERVER['REMOTE_ADDR'] = 'nothing';
+
+global $include_dir;
+$include_dir = DRUPAL_ROOT . '/includes';
+$module_dir = DRUPAL_ROOT . '/modules';
+// Use core directory if it exists.
+if (file_exists(DRUPAL_ROOT . '/core/includes/bootstrap.inc')) {
+ $include_dir = DRUPAL_ROOT . '/core/includes';
+ $module_dir = DRUPAL_ROOT . '/core/modules';
+}
+
+require_once($include_dir . '/bootstrap.inc');
+drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+
+$includes = array(
+ $include_dir . '/common.inc',
+ $include_dir . '/database.inc',
+ $include_dir . '/schema.inc',
+ $include_dir . '/actions.inc',
+ $include_dir . '/entity.inc',
+ $module_dir . '/system/system.module',
+ $include_dir . '/database/database.inc',
+ $include_dir . '/database/query.inc',
+ $include_dir . '/database/select.inc',
+ $include_dir . '/registry.inc',
+ $include_dir . '/module.inc',
+ $include_dir . '/menu.inc',
+ $include_dir . '/file.inc',
+ $include_dir . '/theme.inc',
+ $include_dir . '/locale.inc',
+);
+
+if (function_exists('registry_rebuild')) { // == D7
+ $cache_lock_path_absolute = variable_get('lock_inc');
+ if (!empty($cache_lock_path_absolute)) {
+ $cache_lock_path_relative = DRUPAL_ROOT . '/'. variable_get('lock_inc');
+ // Ensure that the configured lock.inc really exists at that location and
+ // is accessible. Otherwise we use the core lock.inc as fallback.
+ if (is_readable($cache_lock_path_relative) && is_file($cache_lock_path_relative)) {
+ $includes[] = $cache_lock_path_relative;
+ print "We will use relative variant of lock.inc.
\n";
+ }
+ elseif (is_readable($cache_lock_path_absolute) && is_file($cache_lock_path_absolute)) {
+ $includes[] = $cache_lock_path_absolute;
+ print "We will use absolute variant of lock.inc.
\n";
+ }
+ else {
+ print "We will use core implementation of lock.inc as fallback.
\n";
+ $includes[] = DRUPAL_ROOT . '/includes/lock.inc';
+ }
+ }
+ else {
+ $includes[] = DRUPAL_ROOT . '/includes/lock.inc';
+ }
+}
+elseif (!function_exists('cache_clear_all')) { // D8+
+ // TODO
+ // http://api.drupal.org/api/drupal/namespace/Drupal!Core!Lock/8
+ $includes[] = $module_dir . '/entity/entity.module';
+ $includes[] = $module_dir . '/entity/entity.controller.inc';
+}
+// In Drupal 6 the configured lock.inc is already loaded during
+// DRUSH_BOOTSTRAP_DRUPAL_DATABASE
+
+foreach ($includes as $include) {
+ if (file_exists($include)) {
+ require_once($include);
+ }
+}
+
+if (!function_exists('module_list')) {
+ print "ERROR! Registry Rebuild requires a working Drupal site to operate on.
\n";
+ print "Please run this script from the correct Drupal site directory,
\n";
+ print "or specify Drupal root path on command line, for example:
\n";
+ print "php registry_rebuild.php --root=/path/to/drupal/root
\n";
+ print "BYE!
\n";
+ exit;
+}
+
+print "Bootstrapping to DRUPAL_BOOTSTRAP_SESSION
\n";
+drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
+
+registry_rebuild_rebuild();
+
+/**
+ * Find the drupal root directory by looking in parent directories.
+ * If unable to discover it, fail and exit.
+ */
+function define_drupal_root() {
+ $args = getopt(NULL, array('root::'));
+ if (!empty($args['root'])) {
+ return $args['root'];
+ }
+
+ // This is the smallest number of directories to go up: from /sites/all/modules/registry_rebuild.
+ $parent_count = 4;
+ // 8 seems reasonably far to go looking up.
+ while ($parent_count < 8) {
+ $dir = realpath(getcwd() . str_repeat('/..', $parent_count));
+ if (file_exists($dir . '/index.php')) {
+ return $dir;
+ }
+ $parent_count++;
+ }
+ print "Failure: Unable to discover DRUPAL_ROOT. You may want to explicitly define it near the top of registry_rebuild.php";
+ exit(1);
+}
+
+/**
+ * Before calling this we need to be bootstrapped to DRUPAL_BOOTSTRAP_SESSION.
+ */
+function registry_rebuild_rebuild() {
+ // This section is not functionally important. It's just using the
+ // registry_get_parsed_files() so that it can report the change. Drupal 7 only.
+ if (function_exists('registry_rebuild')) {
+ $connection_info = Database::getConnectionInfo();
+ $driver = $connection_info['default']['driver'];
+ global $include_dir;
+ require_once $include_dir . '/database/' . $driver . '/query.inc';
+ $parsed_before = registry_get_parsed_files();
+ }
+
+ // Separate bootstrap cache exists only in Drupal 7 or newer.
+ // They are cleared later again via drupal_flush_all_caches().
+ if (function_exists('registry_rebuild')) { // D7
+ cache_clear_all('lookup_cache', 'cache_bootstrap');
+ cache_clear_all('variables', 'cache_bootstrap');
+ cache_clear_all('module_implements', 'cache_bootstrap');
+ print "Bootstrap caches have been cleared in DRUPAL_BOOTSTRAP_SESSION
\n";
+ }
+ elseif (!function_exists('cache_clear_all')) { // D8+
+ cache('bootstrap')->deleteAll();
+ print "Bootstrap caches have been cleared in DRUPAL_BOOTSTRAP_SESSION
\n";
+ }
+
+ // We later run system_rebuild_module_data() and registry_update() on Drupal 7 via
+ // D7-only registry_rebuild() wrapper, which is run inside drupal_flush_all_caches().
+ // It is an equivalent of module_rebuild_cache() in D5-D6 and is normally run via
+ // our universal wrapper registry_rebuild_cc_all() -- see further below.
+ // However, we are still on the DRUPAL_BOOTSTRAP_SESSION level here,
+ // and we want to make the initial rebuild as atomic as possible, so we can't
+ // run everything from registry_rebuild_cc_all() yet, so we run an absolute
+ // minimum we can at this stage, core specific.
+ if (function_exists('registry_rebuild')) { // D7 only
+ print "Doing registry_rebuild() in DRUPAL_BOOTSTRAP_SESSION
\n";
+ registry_rebuild();
+ }
+ elseif (!function_exists('registry_rebuild') && function_exists('system_rebuild_module_data')) { // D8+
+ print "Doing system_rebuild_module_data() in DRUPAL_BOOTSTRAP_SESSION
\n";
+ system_rebuild_module_data();
+ }
+ else { // D5-D6
+ print "Doing module_rebuild_cache() in DRUPAL_BOOTSTRAP_SESSION
\n";
+ module_list(TRUE, FALSE);
+ module_rebuild_cache();
+ }
+
+ print "Bootstrapping to DRUPAL_BOOTSTRAP_FULL
\n";
+ drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+ // We can run our wrapper now, since we are in a full bootstrap already.
+ print "Rebuilding registry via registry_rebuild_cc_all in DRUPAL_BOOTSTRAP_FULL
\n";
+ registry_rebuild_cc_all();
+
+ // Extra cleanup available for D7 only.
+ if (function_exists('registry_rebuild')) {
+ $parsed_after = registry_get_parsed_files();
+ // Remove files which don't exist anymore.
+ $filenames = array();
+ foreach ($parsed_after as $filename => $file) {
+ if (!file_exists($filename)) {
+ $filenames[] = $filename;
+ }
+ }
+ if (!empty($filenames)) {
+ db_delete('registry_file')
+ ->condition('filename', $filenames)
+ ->execute();
+ db_delete('registry')
+ ->condition('filename', $filenames)
+ ->execute();
+ print("Deleted " . count($filenames) . ' stale files from registry manually.');
+ }
+ $parsed_after = registry_get_parsed_files();
+ print "There were " . count($parsed_before) . " files in the registry before and " . count($parsed_after) . " files now.
\n";
+ registry_rebuild_cc_all();
+ }
+ print "If you don't see any crazy fatal errors, your registry has been rebuilt.
\n";
+}
+
+/**
+ * Registry Rebuild needs to aggressively clear all caches,
+ * not just some bins (at least to attempt it) also *before*
+ * attempting to rebuild registry, or it may not be able
+ * to fix the problem at all, if it relies on some cached
+ * and no longer valid data/paths etc. This problem has been
+ * confirmed and reproduced many times with option --fire-bazooka
+ * which is available only in the Drush variant, but it confirms
+ * the importance of starting with real, raw and not cached
+ * in any way site state. While the --no-cache-clear option
+ * still disables this procedure, --fire-bazooka takes precedence
+ * and forces all caches clear action. All caches are cleared
+ * by default in the PHP script variant.
+ */
+function registry_rebuild_cc_all() {
+ module_invoke_all('pre_flush_all_caches');
+ if (function_exists('cache_clear_all')) {
+ cache_clear_all('*', 'cache', TRUE);
+ cache_clear_all('*', 'cache_form', TRUE);
+ }
+ else {
+ cache('cache')->deleteAll();
+ cache('cache_form')->deleteAll();
+ }
+
+ module_invoke_all('pre_flush_all_caches');
+
+ if (function_exists('module_rebuild_cache')) { // D5-D6
+ module_list(TRUE, FALSE);
+ module_rebuild_cache();
+ }
+
+ if (function_exists('drupal_flush_all_caches')) { // D6+
+ drupal_flush_all_caches();
+ }
+ else { // D5
+ cache_clear_all();
+ system_theme_data();
+ node_types_rebuild();
+ menu_rebuild();
+ }
+ print "All caches have been cleared with registry_rebuild_cc_all.
\n";
+}