From ee88d7a7114d410ee0a951b9fab06e67e67e09a9 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 5 Oct 2022 22:14:53 +0100
Subject: [PATCH] Issue #3116611 by mondrake, andypost, cilefen, xeM8VfDh,
 alexpott, rkoller, benjifisher: Add a requirements check for GD support of
 allowed image types

(cherry picked from commit 00d6bd97a73d637641ce9bad2c212da5176521e2)
---
 .../src/Plugin/ImageToolkit/GDToolkit.php     | 47 ++++++++++++++++++-
 .../Image/ToolkitSetupFormTest.php            | 12 ++++-
 .../KernelTests/Core/Image/ToolkitGdTest.php  | 15 ++++++
 3 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
index 259210d514b2..2753273a4132 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
@@ -380,10 +380,55 @@ public function getRequirements() {
       'value' => $info['GD Version'],
     ];
 
+    // Check if toolkit supported image formats can be actually processed by the
+    // GD library installed with PHP.
+    $check_formats = [
+      IMG_GIF => 'GIF',
+      IMG_JPG => 'JPEG',
+      IMG_PNG => 'PNG',
+      IMG_WEBP => 'WEBP',
+    ];
+    $supported_formats = array_filter($check_formats, fn($type) => imagetypes() & $type, ARRAY_FILTER_USE_KEY);
+    $unsupported_formats = array_diff_key($check_formats, $supported_formats);
+
+    $descriptions = [];
+    if ($supported_formats) {
+      $descriptions[] = $this->formatPlural(
+        count($supported_formats),
+        'Supported image file format: %formats.',
+        'Supported image file formats: %formats.',
+        ['%formats' => implode(', ', $supported_formats)]
+      );
+    }
+    if ($unsupported_formats) {
+      $requirements['version']['severity'] = REQUIREMENT_WARNING;
+      $unsupported = $this->formatPlural(
+        count($unsupported_formats),
+        'Unsupported image file format: %formats.',
+        'Unsupported image file formats: %formats.',
+        ['%formats' => implode(', ', $unsupported_formats)]
+      );
+      $fix_info = $this->t('Check the <a href="https://www.php.net/manual/en/image.installation.php">PHP GD installation documentation</a> if you want to add support.');
+      $descriptions[] = $this->t('@unsupported<br>@ref', [
+        '@unsupported' => $unsupported,
+        '@ref' => $fix_info,
+      ]);
+    }
+
     // Check for filter and rotate support.
     if (!function_exists('imagefilter') || !function_exists('imagerotate')) {
       $requirements['version']['severity'] = REQUIREMENT_WARNING;
-      $requirements['version']['description'] = $this->t('The GD Library for PHP is enabled, but was compiled without support for functions used by the rotate and desaturate effects. It was probably compiled using the official GD libraries from http://www.libgd.org instead of the GD library bundled with PHP. You should recompile PHP --with-gd using the bundled GD library. See <a href="http://php.net/manual/book.image.php">the PHP manual</a>.');
+      $descriptions[] = $this->t('The GD Library for PHP is enabled, but was compiled without support for functions used by the rotate and desaturate effects. It was probably compiled using the official GD libraries from the <a href="https://libgd.github.io/">gdLibrary site</a> instead of the GD library bundled with PHP. You should recompile PHP --with-gd using the bundled GD library. See <a href="https://www.php.net/manual/book.image.php">the PHP manual</a>.');
+    }
+
+    if (count($descriptions) > 1) {
+      $requirements['version']['description'] = [
+        '#theme' => 'item_list',
+        '#items' => $descriptions,
+      ];
+    }
+    else {
+      $requirements['version']['description'] = $descriptions[0];
     }
 
     return $requirements;
diff --git a/core/tests/Drupal/FunctionalTests/Image/ToolkitSetupFormTest.php b/core/tests/Drupal/FunctionalTests/Image/ToolkitSetupFormTest.php
index 2ee6b7a6349f..ab95bb96d9e2 100644
--- a/core/tests/Drupal/FunctionalTests/Image/ToolkitSetupFormTest.php
+++ b/core/tests/Drupal/FunctionalTests/Image/ToolkitSetupFormTest.php
@@ -23,7 +23,7 @@ class ToolkitSetupFormTest extends BrowserTestBase {
    *
    * @var array
    */
-  protected static $modules = ['system', 'image_test'];
+  protected static $modules = ['system', 'image', 'image_test'];
 
   /**
    * {@inheritdoc}
@@ -76,4 +76,14 @@ public function testToolkitSetupForm() {
     $this->assertSession()->statusCodeEquals(403);
   }
 
+  /**
+   * Tests GD toolkit requirements on the Status Report.
+   */
+  public function testGdToolkitRequirements(): void {
+    // Get Status Report.
+    $this->drupalGet('admin/reports/status');
+    $this->assertSession()->pageTextContains('GD2 image manipulation toolkit');
+    $this->assertSession()->pageTextContains('Supported image file formats: GIF, JPEG, PNG, WEBP.');
+  }
+
 }
diff --git a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
index 2bb159dd77fe..e4c44674f9a2 100644
--- a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
@@ -517,4 +517,19 @@ public function testMissingOperation(): void {
     $this->assertFalse($image->apply('missing_op', []), 'Calling a missing image toolkit operation plugin should fail, but it did not.');
   }
 
+  /**
+   * @covers ::getRequirements
+   */
+  public function testGetRequirements(): void {
+    $this->assertEquals([
+      'version' => [
+        'title' => t('GD library'),
+        'value' => gd_info()['GD Version'],
+        'description' => t("Supported image file formats: %formats.", [
+          '%formats' => implode(', ', ['GIF', 'JPEG', 'PNG', 'WEBP']),
+        ]),
+      ],
+    ], $this->imageFactory->get()->getToolkit()->getRequirements());
+  }
+
 }
-- 
GitLab