From 56b0c50f31a68959bdbf7154f09fc44148dae3ec Mon Sep 17 00:00:00 2001
From: Susanne Moog <look@susi.dev>
Date: Fri, 7 Jul 2023 10:50:54 +0200
Subject: [PATCH] [BUGFIX] Fix command detection with open_basedir in effect

When `open_basedir` is set (often the case on shared hosting), TYPO3
fails to find executables as it does a check for file existence first,
which fails due to the restriction.

Instead of checking file existence in all cases, a fallback has been
added on *nix systems that will try execution of a given command
and use the return code to decide whether the path is valid.

This itself uses the command `which` which is not available on Windows.
As nowadays `open_basedir` is mostly used on shared hosting
environments based on *nix, this will not be fixed for Windows.

Resolves: #70869
Resolves: #85174
Releases: main, 12.4
Change-Id: Ic01e822ae16b9ef1fa80be745a9de51e527ba059
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/79865
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: core-ci <typo3@b13.com>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../core/Classes/Utility/CommandUtility.php   |  7 +++--
 .../Image/GraphicsMagickPreset.php            | 22 +++++++-------
 .../Image/ImageMagick6Preset.php              | 30 +++++++++----------
 3 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/typo3/sysext/core/Classes/Utility/CommandUtility.php b/typo3/sysext/core/Classes/Utility/CommandUtility.php
index bb8972504087..fee329decc28 100644
--- a/typo3/sysext/core/Classes/Utility/CommandUtility.php
+++ b/typo3/sysext/core/Classes/Utility/CommandUtility.php
@@ -213,8 +213,11 @@ class CommandUtility
         // Try to get the executable with the command 'which'.
         // It does the same like already done, but maybe on other paths
         if (!Environment::isWindows()) {
-            $cmd = @self::exec('which ' . self::escapeShellArgument($cmd));
-            if (@is_executable($cmd)) {
+            $output = null;
+            $returnValue = 0;
+            $cmd = @self::exec('which ' . self::escapeShellArgument($cmd), $output, $returnValue);
+
+            if ($returnValue === 0) {
                 self::$applications[$cmd]['app'] = $cmd;
                 self::$applications[$cmd]['path'] = PathUtility::dirname($cmd) . '/';
                 self::$applications[$cmd]['valid'] = true;
diff --git a/typo3/sysext/install/Classes/Configuration/Image/GraphicsMagickPreset.php b/typo3/sysext/install/Classes/Configuration/Image/GraphicsMagickPreset.php
index b1bc93ae034a..c060d4c9e105 100644
--- a/typo3/sysext/install/Classes/Configuration/Image/GraphicsMagickPreset.php
+++ b/typo3/sysext/install/Classes/Configuration/Image/GraphicsMagickPreset.php
@@ -72,19 +72,19 @@ class GraphicsMagickPreset extends AbstractImagePreset
             } else {
                 $executable = 'gm';
             }
-            if (@is_file($path . $executable)) {
-                $command = escapeshellarg($path . $executable) . ' -version';
-                $executingResult = [];
-                CommandUtility::exec($command, $executingResult);
-                // First line of exec command should contain string GraphicsMagick
-                $firstResultLine = array_shift($executingResult);
-                if (str_contains($firstResultLine, 'GraphicsMagick')) {
-                    $this->foundPath = $path;
-                    $result = true;
-                    break;
-                }
+
+            $command = escapeshellarg($path . $executable) . ' -version';
+            $executingResult = [];
+            @CommandUtility::exec($command, $executingResult);
+            // First line of exec command should contain string GraphicsMagick
+            $firstResultLine = (string)array_shift($executingResult);
+            if (str_contains($firstResultLine, 'GraphicsMagick')) {
+                $this->foundPath = $path;
+                $result = true;
+                break;
             }
         }
+
         return $result;
     }
 }
diff --git a/typo3/sysext/install/Classes/Configuration/Image/ImageMagick6Preset.php b/typo3/sysext/install/Classes/Configuration/Image/ImageMagick6Preset.php
index fb5b51977f31..3e7e3a1fe602 100644
--- a/typo3/sysext/install/Classes/Configuration/Image/ImageMagick6Preset.php
+++ b/typo3/sysext/install/Classes/Configuration/Image/ImageMagick6Preset.php
@@ -76,22 +76,20 @@ class ImageMagick6Preset extends AbstractImagePreset
             } else {
                 $executable = 'identify';
             }
-            if (@is_file($path . $executable)) {
-                $command = escapeshellarg($path . $executable) . ' -version';
-                $executingResult = [];
-                CommandUtility::exec($command, $executingResult);
-                // First line of exec command should contain string GraphicsMagick
-                $firstResultLine = array_shift($executingResult);
-                // Example: "Version: ImageMagick 6.6.0-4 2012-05-02 Q16 http://www.imagemagick.org"
-                if (str_contains($firstResultLine, 'ImageMagick')) {
-                    [, $version] = explode('ImageMagick', $firstResultLine);
-                    // Example: "6.6.0-4"
-                    [$version] = explode(' ', trim($version));
-                    if (version_compare($version, '6.0.0') >= 0) {
-                        $this->foundPath = $path;
-                        $result = true;
-                        break;
-                    }
+            $command = escapeshellarg($path . $executable) . ' -version';
+            $executingResult = [];
+            CommandUtility::exec($command, $executingResult);
+            // First line of exec command should contain string GraphicsMagick
+            $firstResultLine = array_shift($executingResult);
+            // Example: "Version: ImageMagick 6.6.0-4 2012-05-02 Q16 http://www.imagemagick.org"
+            if (str_contains($firstResultLine, 'ImageMagick')) {
+                [, $version] = explode('ImageMagick', $firstResultLine);
+                // Example: "6.6.0-4"
+                [$version] = explode(' ', trim($version));
+                if (version_compare($version, '6.0.0') >= 0) {
+                    $this->foundPath = $path;
+                    $result = true;
+                    break;
                 }
             }
         }
-- 
GitLab