diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 6c8ee5e5f2..c78540a486 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -19,9 +19,19 @@
 
 /**
  * Minimum supported version of PHP.
+ *
+ * Drupal cannot be installed on versions of PHP older than this version.
  */
 const DRUPAL_MINIMUM_PHP = '5.5.9';
 
+/**
+ * Minimum recommended version of PHP.
+ *
+ * Sites installing Drupal on PHP versions lower than this will see a warning
+ * message, but Drupal can still be installed.
+ */
+const DRUPAL_RECOMMENDED_PHP = '7.1.3';
+
 /**
  * Minimum recommended value of PHP memory_limit.
  *
diff --git a/core/modules/simpletest/src/InstallerTestBase.php b/core/modules/simpletest/src/InstallerTestBase.php
index 92f33dcf5f..57ca485fdb 100644
--- a/core/modules/simpletest/src/InstallerTestBase.php
+++ b/core/modules/simpletest/src/InstallerTestBase.php
@@ -122,6 +122,9 @@ protected function setUp() {
     // Select profile.
     $this->setUpProfile();
 
+    // Address the requirements problem screen, if any.
+    $this->setUpRequirementsProblem();
+
     // Configure settings.
     $this->setUpSettings();
 
@@ -195,6 +198,23 @@ protected function setUpSettings() {
     $this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
   }
 
+  /**
+   * Installer step: Requirements problem.
+   *
+   * Override this method to test specific requirements warnings or errors
+   * during the installer.
+   *
+   * @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(), DRUPAL_RECOMMENDED_PHP) < 0) {
+      $this->continueOnExpectedWarnings(['PHP']);
+    }
+  }
+
   /**
    * Final installer step: Configure site.
    */
@@ -218,4 +238,38 @@ protected function refreshVariables() {
     }
   }
 
+  /**
+   * Continues installation when an expected warning is found.
+   *
+   * @param string[] $allowed_warnings
+   *   A list of warning summaries to ignore (e.g. 'PHP', 'PHP OPcode caching',
+   *   etc.).
+   */
+  protected function continueOnExpectedWarnings($allowed_warnings = []) {
+    // Don't try to continue if there are errors.
+    if (strpos($this->getTextContent(), 'Errors found')) {
+      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.
+    $selectors = [];
+    for ($i = 0; $i <= count($allowed_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((string) $warning);
+    }
+    $this->assertEqual($allowed_warnings, $warnings);
+    $this->clickLink('continue anyway');
+  }
+
 }
diff --git a/core/modules/system/src/Tests/Installer/DistributionProfileTranslationQueryTest.php b/core/modules/system/src/Tests/Installer/DistributionProfileTranslationQueryTest.php
index 1b6868351d..85b1e44ec4 100644
--- a/core/modules/system/src/Tests/Installer/DistributionProfileTranslationQueryTest.php
+++ b/core/modules/system/src/Tests/Installer/DistributionProfileTranslationQueryTest.php
@@ -64,6 +64,27 @@ protected function visitInstaller() {
     // The unrouted URL assembler does not exist at this point, so we build the
     // URL ourselves.
     $this->drupalGet($GLOBALS['base_url'] . '/core/install.php' . '?langcode=fr');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpLanguage() {
+    // This step is skipped, because the distribution profile uses a fixed
+    // language.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpProfile() {
+    // This step is skipped, because there is a distribution profile.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpSettings() {
     // The language should have been automatically detected, all following
     // screens should be translated already.
     $elements = $this->xpath('//input[@type="submit"]/@value');
@@ -80,21 +101,8 @@ protected function visitInstaller() {
     $this->assertRaw($this->info['distribution']['install']['theme']);
     // Verify that the "Choose profile" step does not appear.
     $this->assertNoText('profile');
-  }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUpLanguage() {
-    // This step is skipped, because the distribution profile uses a fixed
-    // language.
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUpProfile() {
-    // This step is skipped, because there is a distribution profile.
+    parent::setUpSettings();
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Installer/DistributionProfileTranslationTest.php b/core/modules/system/src/Tests/Installer/DistributionProfileTranslationTest.php
index 799affe37b..a4c8091ecd 100644
--- a/core/modules/system/src/Tests/Installer/DistributionProfileTranslationTest.php
+++ b/core/modules/system/src/Tests/Installer/DistributionProfileTranslationTest.php
@@ -59,7 +59,27 @@ protected function visitInstaller() {
     file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
 
     parent::visitInstaller();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpLanguage() {
+    // This step is skipped, because the distribution profile uses a fixed
+    // language.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpProfile() {
+    // This step is skipped, because there is a distribution profile.
+  }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpSettings() {
     // The language should have been automatically detected, all following
     // screens should be translated already.
     $elements = $this->xpath('//input[@type="submit"]/@value');
@@ -76,22 +96,10 @@ protected function visitInstaller() {
     $this->assertRaw($this->info['distribution']['install']['theme']);
     // Verify that the "Choose profile" step does not appear.
     $this->assertNoText('profile');
-  }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUpLanguage() {
-    // This step is skipped, because the distribution profile uses a fixed
-    // language.
+    parent::setUpSettings();
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUpProfile() {
-    // This step is skipped, because there is a distribution profile.
-  }
 
   /**
    * Confirms that the installation succeeded.
diff --git a/core/modules/system/src/Tests/Installer/InstallerExistingInstallationTest.php b/core/modules/system/src/Tests/Installer/InstallerExistingInstallationTest.php
index 3ba045a0ad..442de6c107 100644
--- a/core/modules/system/src/Tests/Installer/InstallerExistingInstallationTest.php
+++ b/core/modules/system/src/Tests/Installer/InstallerExistingInstallationTest.php
@@ -32,6 +32,7 @@ public function testInstaller() {
     $this->visitInstaller();
     $this->setUpLanguage();
     $this->setUpProfile();
+    $this->setUpRequirementsProblem();
     $this->setUpSettings();
     $this->assertRaw('Drupal already installed');
   }
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index ce48afe725..bde16bd347 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -183,11 +183,15 @@ function system_requirements($phase) {
     // If PHP is old, it's not safe to continue with the requirements check.
     return $requirements;
   }
+  elseif ((version_compare($phpversion, DRUPAL_RECOMMENDED_PHP) < 0) && ($phase === 'install' || $phase === 'runtime')) {
+    $requirements['php']['description'] = t('Your PHP installation is running version %version. It is recommended to upgrade to version %recommended or higher to ensure your site remains secure and continues to receive updates. See the <a href="http://php.net/supported-versions.php">PHP version support documentation</a> and the <a href=":php_requirements">PHP requirements handbook page</a> for more information.', ['%version' => $phpversion, '%recommended' => DRUPAL_RECOMMENDED_PHP, ':php_requirements' => 'https://www.drupal.org/docs/8/system-requirements/php']);
+    $requirements['php']['severity'] = REQUIREMENT_WARNING;
+  }
 
   // Suggest to update to at least 5.5.21 or 5.6.5 for disabling multiple
   // statements.
   if (($phase === 'install' || \Drupal::database()->driver() === 'mysql') && !SystemRequirements::phpVersionWithPdoDisallowMultipleStatements($phpversion)) {
-    $requirements['php'] = [
+    $requirements['php_multiple_statement'] = [
       'title' => t('PHP (multiple statement disabling)'),
       'value' => $phpversion_label,
       'description' => t('PHP versions higher than 5.6.5 or 5.5.21 provide built-in SQL injection protection for mysql databases. It is recommended to update.'),
