From 52d3b49336bead3666ed749197ce25a06f294097 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Tue, 10 Dec 2013 13:50:21 +0000
Subject: [PATCH] Issue #2097189 by damiankloip, sun, Albert Volkman, chx: Add
 a rebuild script.

---
 .htaccess                                |  3 ++-
 core/includes/utility.inc                | 28 ++++++++++++++++++++
 core/modules/system/system.install       |  9 +++++++
 core/rebuild.php                         | 33 ++++++++++++++++++++++++
 core/scripts/rebuild_token_calculator.sh | 24 +++++++++++++++++
 index.php                                |  7 ++++-
 sites/default/default.settings.php       | 10 +++++++
 7 files changed, 112 insertions(+), 2 deletions(-)
 create mode 100644 core/rebuild.php
 create mode 100644 core/scripts/rebuild_token_calculator.sh

diff --git a/.htaccess b/.htaccess
index ce89e172cec4..526c60be3ef6 100644
--- a/.htaccess
+++ b/.htaccess
@@ -111,7 +111,8 @@ DirectoryIndex index.php index.html index.htm
 
   # Redirect common PHP files to their new locations.
   RewriteCond %{REQUEST_URI} ^(.*)?/(update.php) [OR]
-  RewriteCond %{REQUEST_URI} ^(.*)?/(install.php)
+  RewriteCond %{REQUEST_URI} ^(.*)?/(install.php) [OR]
+  RewriteCond %{REQUEST_URI} ^(.*)?/(rebuild.php)
   RewriteCond %{REQUEST_URI} !core
   RewriteRule ^ %1/core/%2 [L,QSA,R=301]
 
diff --git a/core/includes/utility.inc b/core/includes/utility.inc
index 5b2719d34d86..a9002620db15 100644
--- a/core/includes/utility.inc
+++ b/core/includes/utility.inc
@@ -6,6 +6,8 @@
  */
 
 use Drupal\Component\Utility\Variable;
+use Drupal\Component\PhpStorage\PhpStorageFactory;
+use Drupal\Core\Cache\Cache;
 
 /**
  * Drupal-friendly var_export().
@@ -23,3 +25,29 @@
 function drupal_var_export($var, $prefix = '') {
   return Variable::export($var, $prefix);
 }
+
+/**
+ * Rebuilds all caches even when Drupal itself does not work.
+ *
+ * Requires DRUPAL_BOOTSTRAP_CONFIGURATION.
+ *
+ * @see rebuild.php
+ */
+function drupal_rebuild() {
+  // drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL) will build a new kernel. This
+  // comes before DRUPAL_BOOTSTRAP_PAGE_CACHE.
+  PhpStorageFactory::get('service_container')->deleteAll();
+  PhpStorageFactory::get('twig')->deleteAll();
+
+  // Disable the page cache.
+  drupal_page_is_cacheable(FALSE);
+
+  // Bootstrap up to where caches exist and clear them.
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
+  foreach (Cache::getBins() as $bin) {
+    $bin->deleteAll();
+  }
+
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+  drupal_flush_all_caches();
+}
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index af38deefc325..56b547e0f471 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -518,6 +518,15 @@ function system_requirements($phase) {
       );
     }
     $requirements['update status']['title'] = t('Update notifications');
+
+    if (settings()->get('rebuild_access')) {
+      $requirements['rebuild access'] = array(
+        'title' => t('Rebuild access'),
+        'value' => t('Enabled'),
+        'severity' => REQUIREMENT_ERROR,
+        'description' => t('The rebuild_access setting is enabled in settings.php. It is recommended to have this setting disabled unless you are performing a rebuild.'),
+      );
+    }
   }
 
   // Ensure that if upgrading from 7 to 8 we have no disabled modules.
diff --git a/core/rebuild.php b/core/rebuild.php
new file mode 100644
index 000000000000..1b9460182568
--- /dev/null
+++ b/core/rebuild.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Rebuilds all Drupal caches even when Drupal itself does not work.
+ *
+ * Needs a token query argument which can be calculated using the
+ * scripts/rebuild_token_calculator.sh script.
+ *
+ * @see drupal_rebuild()
+ */
+
+use Drupal\Component\Utility\Crypt;
+
+// Change the directory to the Drupal root.
+chdir('..');
+
+require_once dirname(__DIR__) . '/core/includes/bootstrap.inc';
+require_once dirname(__DIR__) . '/core/includes/utility.inc';
+
+drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+
+if (settings()->get('rebuild_access', FALSE) ||
+  (isset($_GET['token'], $_GET['timestamp']) &&
+    ((REQUEST_TIME - $_GET['timestamp']) < 300) &&
+    ($_GET['token'] === Crypt::hmacBase64($_GET['timestamp'], $GLOBALS['drupal_hash_salt']))
+  )) {
+
+  drupal_rebuild();
+  drupal_set_message('Cache rebuild complete.');
+}
+
+header('Location: ' . $GLOBALS['base_url']);
diff --git a/core/scripts/rebuild_token_calculator.sh b/core/scripts/rebuild_token_calculator.sh
new file mode 100644
index 000000000000..9b948b48ed12
--- /dev/null
+++ b/core/scripts/rebuild_token_calculator.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env php
+
+<?php
+
+/**
+ * @file
+ * Command line token calculator for rebuild.php.
+ */
+
+require_once __DIR__ . '/../vendor/autoload.php';
+require_once dirname(__DIR__) . '/includes/bootstrap.inc';
+
+use Drupal\Component\Utility\Crypt;
+
+drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+
+if (!drupal_is_cli()) {
+  exit;
+}
+
+$timestamp = time();
+$token = Crypt::hmacBase64($timestamp, $drupal_hash_salt);
+
+print "timestamp=$timestamp&token=$token\n";
diff --git a/index.php b/index.php
index 426aa225bbdb..2181fb3d8d04 100644
--- a/index.php
+++ b/index.php
@@ -15,6 +15,11 @@
   drupal_handle_request();
 }
 catch (Exception $e) {
-  print 'If you have just changed code (for example deployed a new module or moved an existing one) read http://drupal.org/documentation/rebuild';
+  $message = 'If you have just changed code (for example deployed a new module or moved an existing one) read <a href="http://drupal.org/documentation/rebuild">http://drupal.org/documentation/rebuild</a>';
+  if (settings()->get('rebuild_access', FALSE)) {
+    $rebuild_path = $GLOBALS['base_url'] . '/rebuild.php';
+    $message .= " or run the <a href=\"$rebuild_path\">rebuild script</a>";
+  }
+  print $message;
   throw $e;
 }
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index 0574b23bea01..b3c54b329b8f 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -501,6 +501,16 @@
  */
 # $settings['maintenance_theme'] = 'bartik';
 
+/**
+ * Enable access to rebuild.php.
+ *
+ * This setting can be enabled to allow Drupal's php and database cached
+ * storage to be cleared via the rebuild.php page. Access to this page can also
+ * be gained by generating a query string from rebuild_token_calculator.sh and
+ * using these parameters in a request to rebuild.php.
+ */
+# $settings['rebuild_access'] = TRUE;
+
 /**
  * Base URL (optional).
  *
-- 
GitLab