diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 499f552..5dee0a0 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -25,7 +25,15 @@
* @todo Move this to an appropriate autoloadable class. See
* https://www.drupal.org/project/drupal/issues/2908079
*/
-const DRUPAL_MINIMUM_PHP = '5.5.9';
+const DRUPAL_MINIMUM_PHP = '7.0.0';
+
+/**
+ * Updates cannot be run on versions of PHP older than this version.
+ *
+ * @todo Move this to an appropriate autoloadable class. See
+ * https://www.drupal.org/project/drupal/issues/2908079
+ */
+const DRUPAL_MINIMUM_UPDATE_PHP = '5.5.9';
/**
* Minimum recommended version of PHP.
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 70c82b4..13f0372 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -1116,7 +1116,7 @@ function install_profile_info($profile, $langcode = 'en') {
'description' => '',
'version' => NULL,
'hidden' => FALSE,
- 'php' => DRUPAL_MINIMUM_PHP,
+ 'php' => DRUPAL_MINIMUM_UPDATE_PHP,
'config_install_path' => NULL,
];
$profile_path = drupal_get_path('profile', $profile);
diff --git a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php
index c8f492b..07a1d83 100644
--- a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php
@@ -28,7 +28,7 @@ class ModuleExtensionList extends ExtensionList {
'description' => '',
'package' => 'Other',
'version' => NULL,
- 'php' => DRUPAL_MINIMUM_PHP,
+ 'php' => DRUPAL_MINIMUM_UPDATE_PHP,
];
/**
diff --git a/core/lib/Drupal/Core/Extension/ProfileExtensionList.php b/core/lib/Drupal/Core/Extension/ProfileExtensionList.php
index 7c41516..bb054d0 100644
--- a/core/lib/Drupal/Core/Extension/ProfileExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ProfileExtensionList.php
@@ -22,7 +22,7 @@ class ProfileExtensionList extends ExtensionList {
'description' => '',
'package' => 'Other',
'version' => NULL,
- 'php' => DRUPAL_MINIMUM_PHP,
+ 'php' => DRUPAL_MINIMUM_UPDATE_PHP,
];
/**
diff --git a/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php b/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php
index c4d39ef..aef0d4e 100644
--- a/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ThemeEngineExtensionList.php
@@ -21,7 +21,7 @@ class ThemeEngineExtensionList extends ExtensionList {
'description' => '',
'package' => 'Other',
'version' => NULL,
- 'php' => DRUPAL_MINIMUM_PHP,
+ 'php' => DRUPAL_MINIMUM_UPDATE_PHP,
];
/**
diff --git a/core/lib/Drupal/Core/Extension/ThemeExtensionList.php b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
index 07a2f3f..5468c3f 100644
--- a/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
+++ b/core/lib/Drupal/Core/Extension/ThemeExtensionList.php
@@ -48,7 +48,7 @@ class ThemeExtensionList extends ExtensionList {
'comment_user_verification',
],
'screenshot' => 'screenshot.png',
- 'php' => DRUPAL_MINIMUM_PHP,
+ 'php' => DRUPAL_MINIMUM_UPDATE_PHP,
'libraries' => [],
'libraries_extend' => [],
'libraries_override' => [],
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 960bb7d..d7bef10 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -186,24 +186,29 @@ function system_requirements($phase) {
];
}
- if (version_compare($phpversion, DRUPAL_MINIMUM_PHP) < 0) {
- $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_PHP]);
+ $is_test_site = drupal_valid_test_ua() || getenv('DRUPAL_DEV_SITE_PATH');
+ if (version_compare($phpversion, DRUPAL_MINIMUM_UPDATE_PHP) < 0) {
+ $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_UPDATE_PHP]);
$requirements['php']['severity'] = REQUIREMENT_ERROR;
- // If PHP is old, it's not safe to continue with the requirements check.
return $requirements;
}
- if ((version_compare($phpversion, DRUPAL_RECOMMENDED_PHP) < 0) && ($phase === 'install' || $phase === 'runtime')) {
- // Warn if still on PHP 5. If at least PHP 7.0, relax from "warning" to
- // "info", and show it at runtime only, to not scare users while installing.
- if (version_compare($phpversion, '7.0') < 0) {
- $requirements['php']['description'] = t('Drupal will drop support for this version on March 6, 2019. Upgrade to PHP version %recommended or higher to ensure your site can receive updates and remain secure. See PHP\'s version support documentation and the Drupal 8 PHP requirements handbook page for more information.', ['%recommended' => DRUPAL_RECOMMENDED_PHP, ':php_requirements' => 'https://www.drupal.org/docs/8/system-requirements/php']);
+ if (version_compare($phpversion, DRUPAL_MINIMUM_PHP) < 0) {
+ // Allow test installations of Drupal on the minimum update PHP.
+ if ($phase === 'update') {
+ $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_PHP]);
$requirements['php']['severity'] = REQUIREMENT_WARNING;
}
- else {
- if ($phase === 'runtime') {
- $requirements['php']['description'] = t('It is recommended to upgrade to PHP version %recommended or higher for the best ongoing support. See PHP\'s version support documentation and the Drupal 8 PHP requirements handbook page for more information.', ['%recommended' => DRUPAL_RECOMMENDED_PHP, ':php_requirements' => 'https://www.drupal.org/docs/8/system-requirements/php']);
- $requirements['php']['severity'] = REQUIREMENT_INFO;
- }
+ elseif (!$is_test_site) {
+ $requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => DRUPAL_MINIMUM_PHP]);
+ $requirements['php']['severity'] = REQUIREMENT_ERROR;
+ // If PHP is old, it's not safe to continue with the requirements check.
+ return $requirements;
+ }
+ }
+ if (version_compare($phpversion, DRUPAL_RECOMMENDED_PHP) < 0) {
+ if ($phase === 'runtime') {
+ $requirements['php']['description'] = t('It is recommended to upgrade to PHP version %recommended or higher for the best ongoing support. See PHP\'s version support documentation and the Drupal 8 PHP requirements handbook page for more information.', ['%recommended' => DRUPAL_RECOMMENDED_PHP, ':php_requirements' => 'https://www.drupal.org/docs/8/system-requirements/php']);
+ $requirements['php']['severity'] = REQUIREMENT_INFO;
}
}
diff --git a/core/modules/system/tests/src/Functional/Update/SystemRequirementsTest.php b/core/modules/system/tests/src/Functional/Update/SystemRequirementsTest.php
new file mode 100644
index 0000000..c9ad3b6
--- /dev/null
+++ b/core/modules/system/tests/src/Functional/Update/SystemRequirementsTest.php
@@ -0,0 +1,42 @@
+drupalCreateUser(['administer software updates']);
+ $this->drupalLogin($user);
+ $url = Url::fromRoute('system.db_update');
+ $this->drupalGet($url);
+ $warning = sprintf('Your PHP installation is too old. Drupal requires at least PHP %s.', DRUPAL_MINIMUM_PHP);
+
+ if (version_compare(phpversion(), DRUPAL_MINIMUM_PHP) < 0) {
+ $this->assertText('Warnings found');
+ $this->assertText($warning);
+ }
+ else {
+ $this->assertNoText('Warnings found');
+ $this->assertNoText($warning);
+ }
+ }
+
+}
diff --git a/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php b/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
index da215d4..a52274e 100644
--- a/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
+++ b/core/modules/system/tests/src/Functional/Update/UpdateScriptTest.php
@@ -5,6 +5,7 @@
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\UpdateUiTrait;
/**
* Tests the update script access and functionality.
@@ -13,6 +14,8 @@
*/
class UpdateScriptTest extends BrowserTestBase {
+ use UpdateUiTrait;
+
/**
* Modules to enable.
*
@@ -99,6 +102,7 @@ public function testRequirements() {
// If there are no requirements warnings or errors, we expect to be able to
// go through the update process uninterrupted.
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
+ $this->updateRequirementsProblem();
$this->clickLink(t('Continue'));
$this->assertText(t('No pending updates.'), 'End of update process was reached.');
// Confirm that all caches were cleared.
@@ -110,6 +114,7 @@ public function testRequirements() {
// First, run this test with pending updates to make sure they can be run
// successfully.
+ $this->drupalLogin($this->updateUser);
$update_script_test_config->set('requirement_type', REQUIREMENT_WARNING)->save();
drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1);
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
@@ -177,6 +182,7 @@ public function testNoUpdateFunctionality() {
// Click through update.php with 'administer software updates' permission.
$this->drupalLogin($this->updateUser);
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
+ $this->updateRequirementsProblem();
$this->clickLink(t('Continue'));
$this->assertText(t('No pending updates.'));
$this->assertNoLink('Administration pages');
@@ -188,6 +194,7 @@ public function testNoUpdateFunctionality() {
$admin_user = $this->drupalCreateUser(['administer software updates', 'access administration pages']);
$this->drupalLogin($admin_user);
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
+ $this->updateRequirementsProblem();
$this->clickLink(t('Continue'));
$this->assertText(t('No pending updates.'));
$this->assertLink('Administration pages');
@@ -220,6 +227,7 @@ public function testSuccessfulUpdateFunctionality() {
$admin_user = $this->drupalCreateUser(['administer software updates', 'access administration pages', 'access site reports', 'access site in maintenance mode']);
$this->drupalLogin($admin_user);
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
+ $this->updateRequirementsProblem();
$this->clickLink(t('Continue'));
$this->clickLink(t('Apply pending updates'));
$this->checkForMetaRefresh();
@@ -287,6 +295,7 @@ public function testSuccessfulMultilingualUpdateFunctionality() {
// Click through update.php with 'access administration pages' and
// 'access site reports' permissions.
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
+ $this->updateRequirementsProblem();
$this->clickLink(t('Continue'));
$this->clickLink(t('Apply pending updates'));
$this->checkForMetaRefresh();
@@ -319,6 +328,7 @@ protected function runUpdates($maintenance_mode) {
$this->assertNoText('Operating in maintenance mode.');
}
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
+ $this->updateRequirementsProblem();
$this->clickLink(t('Continue'));
$this->clickLink(t('Apply pending updates'));
$this->checkForMetaRefresh();
diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
index 9810f34..5ea1e58 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
@@ -244,12 +244,7 @@ protected function setUpSettings() {
* @see system_requirements()
*/
protected function setUpRequirementsProblem() {
- // By default, skip the "recommended PHP version" warning on older test
- // environments. This allows the installer to be tested consistently on
- // both recommended PHP versions and older (but still supported) versions.
- if (version_compare(phpversion(), '7.0') < 0) {
- $this->continueOnExpectedWarnings(['PHP']);
- }
+ // Do nothing.
}
/**
diff --git a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
index a127ab4..d795f6b 100644
--- a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
@@ -10,6 +10,7 @@
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Language\Language;
use Drupal\Core\Url;
+use Drupal\Tests\UpdateUiTrait;
use Drupal\user\Entity\User;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpFoundation\Request;
@@ -42,6 +43,7 @@
abstract class UpdatePathTestBase extends BrowserTestBase {
use SchemaCheckTestTrait;
+ use UpdateUiTrait;
/**
* Modules to enable after the database is loaded.
@@ -295,6 +297,7 @@ protected function runUpdates() {
]);
$this->drupalGet($this->updateUrl);
+ $this->updateRequirementsProblem();
$this->clickLink(t('Continue'));
$this->doSelectionTest();
diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php
index 9c5fd58..cba97b8 100644
--- a/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php
+++ b/core/tests/Drupal/Tests/Core/Extension/ThemeExtensionListTest.php
@@ -259,6 +259,6 @@ class TestThemeEngineExtensionList extends ThemeEngineExtensionList {
}
-if (!defined('DRUPAL_MINIMUM_PHP')) {
- define('DRUPAL_MINIMUM_PHP', '5.5.9');
+if (!defined('DRUPAL_MINIMUM_UPDATE_PHP')) {
+ define('DRUPAL_MINIMUM_UPDATE_PHP', '5.5.9');
}
diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
index 97a5e93..841073b 100644
--- a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
+++ b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
@@ -146,6 +146,6 @@ protected function themeRegistryRebuild() {
}
-if (!defined('DRUPAL_MINIMUM_PHP')) {
- define('DRUPAL_MINIMUM_PHP', '5.5.9');
+if (!defined('DRUPAL_MINIMUM_UPDATE_PHP')) {
+ define('DRUPAL_MINIMUM_UPDATE_PHP', '5.5.9');
}
diff --git a/core/tests/Drupal/Tests/UpdateUiTrait.php b/core/tests/Drupal/Tests/UpdateUiTrait.php
new file mode 100644
index 0000000..1736ab0
--- /dev/null
+++ b/core/tests/Drupal/Tests/UpdateUiTrait.php
@@ -0,0 +1,61 @@
+continueOnExpectedWarnings(['PHP']);
+ }
+ }
+
+ /**
+ * Continues installation when an expected warning is found.
+ *
+ * @param string[] $expected_warnings
+ * A list of warning summaries to expect on the requirements screen (e.g.
+ * 'PHP', 'PHP OPcode caching', etc.). If only the expected warnings
+ * are found, the test will click the "try again" link to go to the
+ * next screen of the update. If an expected warning is not found, or if
+ * a warning not in the list is present, a fail is raised.
+ */
+ protected function continueOnExpectedWarnings($expected_warnings = []) {
+ // Don't try to continue if there are errors.
+ if (strpos($this->getTextContent(), 'Errors found') !== FALSE) {
+ return;
+ }
+ // Allow only details elements that are directly after the warning header
+ // or each other. There is no guaranteed wrapper we can rely on across
+ // distributions. When there are multiple warnings, the selectors will be:
+ // - h3#warning+details summary
+ // - h3#warning+details+details summary
+ // - etc.
+ // We add one more selector than expected warnings to confirm that there
+ // isn't any other warning before clicking the link.
+ // @todo Make this more reliable in
+ // https://www.drupal.org/project/drupal/issues/2927345.
+ $selectors = [];
+ for ($i = 0; $i <= count($expected_warnings); $i++) {
+ $selectors[] = 'h3#warning' . implode('', array_fill(0, $i + 1, '+details')) . ' summary';
+ }
+ $warning_elements = $this->cssSelect(implode(', ', $selectors));
+
+ // Confirm that there are only the expected warnings.
+ $warnings = [];
+ foreach ($warning_elements as $warning) {
+ $warnings[] = trim($warning->getText());
+ }
+ $this->assertEquals($expected_warnings, $warnings);
+ $this->clickLink('try again');
+ $this->checkForMetaRefresh();
+ }
+
+}