[BUGFIX] Unify PATH_thisScript with PATH_site 95/52295/13
authorHelmut Hummel <typo3@helhum.io>
Fri, 31 Mar 2017 13:16:47 +0000 (15:16 +0200)
committerHelmut Hummel <typo3@helhum.io>
Mon, 3 Apr 2017 12:37:42 +0000 (14:37 +0200)
In case we accept TYPO3_PATH_ROOT from the environment,
we must ensure that all paths (in particular the entry script path)
are based on this base path.

We do so, by removing the calculated path prefix with
the base path injected from the environment.

We cannot rely on paths using DIRECTORY_SEPARATOR as this depends on how
the Apache and the DocumentRoot are configured. This patch converts all
paths using forward slashes before any calculation is done.

Resolves: #80634
Releases: master
Change-Id: I3edecadb2f82e763ad414cf23a7048bac7c85556
Reviewed-on: https://review.typo3.org/52295
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
Tested-by: Benjamin Franzke <bfr@qbus.de>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Reviewed-by: Steffen Frese <steffenf14@gmail.com>
Tested-by: Steffen Frese <steffenf14@gmail.com>
Reviewed-by: Frans Saris <franssaris@gmail.com>
Tested-by: Frans Saris <franssaris@gmail.com>
Reviewed-by: Tobi Kretschmann <tobi@tobishome.de>
Tested-by: Tobi Kretschmann <tobi@tobishome.de>
Reviewed-by: Thomas Maroschik <tmaroschik@dfau.de>
Tested-by: Thomas Maroschik <tmaroschik@dfau.de>
Reviewed-by: Kai Ole Hartwig <mail@ole-hartwig.eu>
Tested-by: Kai Ole Hartwig <mail@ole-hartwig.eu>
Reviewed-by: Helmut Hummel <typo3@helhum.io>
Tested-by: Helmut Hummel <typo3@helhum.io>
typo3/sysext/core/Classes/Core/SystemEnvironmentBuilder.php
typo3/sysext/core/Tests/Unit/Core/SystemEnvironmentBuilderTest.php

index 5e9dd31..9ae3a9d 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Core\Core;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
 
 /**
  * Class to encapsulate base setup of bootstrap.
@@ -147,27 +148,40 @@ class SystemEnvironmentBuilder
      */
     protected static function definePaths($entryPointLevel = 0)
     {
-        // Relative path from document root to typo3/ directory
-        // Hardcoded to "typo3/"
-        define('TYPO3_mainDir', 'typo3/');
         // Absolute path of the entry script that was called
-        // All paths are unified between Windows and Unix, so the \ of Windows is substituted to a /
-        // Example "/var/www/instance-name/htdocs/typo3conf/ext/wec_map/mod1/index.php"
-        // Example "c:/var/www/instance-name/htdocs/typo3/index.php?M=main" for a path in Windows
+        $scriptPath = GeneralUtility::fixWindowsFilePath(self::getPathThisScript());
+        $rootPath = self::getRootPathFromScriptPath($scriptPath, $entryPointLevel);
+        // Check if the root path has been set in the environment (e.g. by the composer installer)
+        if (getenv('TYPO3_PATH_ROOT')) {
+            if ((TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI)
+                && Bootstrap::usesComposerClassLoading()
+                && StringUtility::endsWith($scriptPath, 'typo3')
+            ) {
+                // PATH_thisScript is used for various path calculations based on the document root
+                // Therefore we assume it is always a subdirectory of the document root, which is not the case
+                // in composer mode on cli, as the binary is in the composer bin directory.
+                // Because of that, we enforce the document root path of this binary to be set
+                $scriptName = '/typo3/sysext/core/bin/typo3';
+            } else {
+                // Base the script path on the path taken from the environment
+                // to make relative path calculations work in case only one of both is symlinked
+                // or has the real path
+                $scriptName =  substr($scriptPath, strlen($rootPath));
+            }
+            $rootPath = GeneralUtility::fixWindowsFilePath(getenv('TYPO3_PATH_ROOT'));
+            $scriptPath = $rootPath . $scriptName;
+        }
+
         if (!defined('PATH_thisScript')) {
-            define('PATH_thisScript', self::getPathThisScript());
+            define('PATH_thisScript', $scriptPath);
         }
         // Absolute path of the document root of the instance with trailing slash
-        // Example "/var/www/instance-name/htdocs/"
         if (!defined('PATH_site')) {
-            // Check if the site path has been set by the outside (e.g. dotenv or the composer installer)
-            if (getenv('TYPO3_PATH_ROOT')) {
-                $rootPath = getenv('TYPO3_PATH_ROOT');
-                define('PATH_site', $rootPath . '/');
-            } else {
-                define('PATH_site', self::getPathSite($entryPointLevel));
-            }
+            define('PATH_site', $rootPath . '/');
         }
+        // Relative path from document root to typo3/ directory
+        // Hardcoded to "typo3/"
+        define('TYPO3_mainDir', 'typo3/');
         // Absolute path of the typo3 directory of the instance with trailing slash
         // Example "/var/www/instance-name/htdocs/typo3/"
         define('PATH_typo3', PATH_site . TYPO3_mainDir);
@@ -272,9 +286,8 @@ class SystemEnvironmentBuilder
     {
         if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
             return self::getPathThisScriptCli();
-        } else {
-            return self::getPathThisScriptNonCli();
         }
+        return self::getPathThisScriptNonCli();
     }
 
     /**
@@ -301,10 +314,6 @@ class SystemEnvironmentBuilder
                 $scriptPath = $_SERVER['SCRIPT_FILENAME'];
             }
         }
-        // Replace \ to / for Windows
-        $scriptPath = str_replace('\\', '/', $scriptPath);
-        // Replace double // to /
-        $scriptPath = str_replace('//', '/', $scriptPath);
         return $scriptPath;
     }
 
@@ -360,33 +369,19 @@ class SystemEnvironmentBuilder
      * - A Backend script: This is the case for the typo3/index.php dispatcher and other entry scripts like 'cli_dispatch.phpsh'
      * or 'typo3/index.php' that are located inside typo3/ directly.
      *
+     * @param string $scriptPath Calculated path to the entry script
      * @param int $entryPointLevel Number of subdirectories where the entry script is located under the document root
      * @return string Absolute path to document root of installation
      */
-    protected static function getPathSite($entryPointLevel)
+    protected static function getRootPathFromScriptPath($scriptPath, $entryPointLevel)
     {
-        $entryScriptDirectory = self::getUnifiedDirectoryName(PATH_thisScript);
+        $entryScriptDirectory = dirname($scriptPath);
         if ($entryPointLevel > 0) {
-            list($pathSite) = GeneralUtility::revExplode('/', $entryScriptDirectory, $entryPointLevel+1);
+            list($rootPath) = GeneralUtility::revExplode('/', $entryScriptDirectory, $entryPointLevel + 1);
         } else {
-            $pathSite = $entryScriptDirectory;
-        }
-        return $pathSite . '/';
-    }
-
-    /**
-     * Remove file name from script path and unify for Windows and Unix
-     *
-     * @param string $absolutePath Absolute path to script
-     * @return string Directory name of script file location, unified for Windows and Unix without the trailing slash
-     */
-    protected static function getUnifiedDirectoryName($absolutePath)
-    {
-        $directory = dirname($absolutePath);
-        if (TYPO3_OS === 'WIN') {
-            $directory = str_replace('\\', '/', $directory);
+            $rootPath = $entryScriptDirectory;
         }
-        return $directory;
+        return $rootPath;
     }
 
     /**
index 8e3277a..b8c9539 100644 (file)
@@ -108,17 +108,6 @@ class SystemEnvironmentBuilderTest extends \TYPO3\TestingFramework\Core\Unit\Uni
     /**
      * @test
      */
-    public function getUnifiedDirectoryNameReturnsCorrectPathOnUnix()
-    {
-        $input = '/foo/bar/test.php';
-        $expected = '/foo/bar';
-        $actual = $this->subject->_call('getUnifiedDirectoryName', $input);
-        $this->assertEquals($expected, $actual);
-    }
-
-    /**
-     * @test
-     */
     public function initializeGlobalVariablesUnsetsGlobalErrorArray()
     {
         $GLOBALS['error'] = 'foo';