[BUGFIX] PHP filesystem functions are locale dependent 77/18577/3
authorSteffen Ritter <info@rs-websystems.de>
Sun, 3 Mar 2013 18:46:38 +0000 (19:46 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Mon, 1 Apr 2013 13:03:04 +0000 (15:03 +0200)
PHP filesystem functions like pathinfo, dirname and
basename are dependent on the locale set in PHP.
If one enables UTF8filesystem in the install tool, he may
use non-ascii characters in filenames and directory names.
For this to work properly you need to configure
SystemLocale, too.

The file abstraction layer classes need to take care of
the SystemLocale; to avoid code duplication new static
wrapper functions have been introduced.

Change-Id: I635e18d7ed08d928c6c4e427c0348dd46d9c5900
Releases: 6.0, 6.1
Resolves: #45982
Reviewed-on: https://review.typo3.org/18577
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
typo3/sysext/core/Classes/Resource/AbstractFile.php
typo3/sysext/core/Classes/Resource/Driver/AbstractDriver.php
typo3/sysext/core/Classes/Resource/Driver/LocalDriver.php
typo3/sysext/core/Classes/Resource/Folder.php
typo3/sysext/core/Classes/Resource/ResourceCompressor.php
typo3/sysext/core/Classes/Resource/ResourceFactory.php
typo3/sysext/core/Classes/Resource/ResourceStorage.php
typo3/sysext/core/Classes/Resource/Service/ImageProcessingService.php
typo3/sysext/core/Classes/Resource/Service/MagicImageService.php
typo3/sysext/core/Classes/Utility/PathUtility.php

index 312ebbb..a73e720 100644 (file)
@@ -26,6 +26,9 @@ namespace TYPO3\CMS\Core\Resource;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 /**
  * Abstract file representation in the file abstraction layer.
  *
@@ -156,7 +159,7 @@ abstract class AbstractFile implements FileInterface {
         * @return string
         */
        public function getNameWithoutExtension() {
-               return pathinfo($this->getName(), PATHINFO_FILENAME);
+               return PathUtility::pathinfo($this->getName(), PATHINFO_FILENAME);
        }
 
        /**
@@ -226,7 +229,7 @@ abstract class AbstractFile implements FileInterface {
         * @return string The file extension
         */
        public function getExtension() {
-               $pathinfo = pathinfo($this->getName());
+               $pathinfo = PathUtility::pathinfo($this->getName());
 
                $extension = strtolower($pathinfo['extension']);
 
index 35f3866..e3996e4 100644 (file)
@@ -26,6 +26,9 @@ namespace TYPO3\CMS\Core\Resource\Driver;
  *
  * This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 /**
  * An abstract implementation of a storage driver.
  *
@@ -154,7 +157,7 @@ abstract class AbstractDriver {
         * @return string
         */
        protected function getNameFromIdentifier($identifier) {
-               return basename($identifier);
+               return PathUtility::basename($identifier);
        }
 
        /**
index 5fd9b01..24073cb 100644 (file)
@@ -1,6 +1,5 @@
 <?php
 namespace TYPO3\CMS\Core\Resource\Driver;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /***************************************************************
  * Copyright notice
@@ -28,6 +27,9 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 /**
  * Driver for the local file system
  *
@@ -156,7 +158,7 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
                // If requested, make the path relative to the current script in order to make it possible
                // to use the relative file
                if ($relativeToCurrentScript) {
-                       $publicUrl = \TYPO3\CMS\Core\Utility\PathUtility::getRelativePathTo(dirname((PATH_site . $publicUrl))) . basename($publicUrl);
+                       $publicUrl = PathUtility::getRelativePathTo(PathUtility::dirname((PATH_site . $publicUrl))) . PathUtility::basename($publicUrl);
                }
                return $publicUrl;
        }
@@ -212,7 +214,7 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
                // Makes sure the Path given as parameter is valid
                $this->checkFilePath($fileIdentifier);
                $dirPath = \TYPO3\CMS\Core\Utility\GeneralUtility::fixWindowsFilePath(
-                       dirname($fileIdentifier)
+                       PathUtility::dirname($fileIdentifier)
                );
                if ($dirPath !== '' && $dirPath !== '/') {
                        $dirPath = '/' . trim($dirPath, '/') . '/';
@@ -431,7 +433,7 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
         * @return array
         */
        protected function extractFileInformation($filePath, $containerPath) {
-               $fileName = basename($filePath);
+               $fileName = PathUtility::basename($filePath);
                $fileInformation = array(
                        'size' => filesize($filePath),
                        'atime' => fileatime($filePath),
@@ -453,7 +455,7 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
         * @return array
         */
        protected function extractFolderInformation($folderPath, $containerPath) {
-               $folderName = basename($folderPath);
+               $folderName = PathUtility::basename($folderPath);
                $folderInformation = array(
                        'ctime' => filectime($folderPath),
                        'mtime' => filemtime($folderPath),
@@ -578,7 +580,7 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
                        throw new \InvalidArgumentException('Cannot add a file that is already part of this storage.', 1314778269);
                }
                $relativeTargetPath = ltrim($targetFolder->getIdentifier(), '/');
-               $relativeTargetPath .= $this->sanitizeFileName($fileName ? $fileName : basename($localFilePath));
+               $relativeTargetPath .= $this->sanitizeFileName($fileName ? $fileName : PathUtility::basename($localFilePath));
                $targetPath = $this->absoluteBasePath . $relativeTargetPath;
                if (is_uploaded_file($localFilePath)) {
                        $moveResult = move_uploaded_file($localFilePath, $targetPath);
@@ -895,7 +897,7 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
        public function renameFile(\TYPO3\CMS\Core\Resource\FileInterface $file, $newName) {
                // Makes sure the Path given as parameter is valid
                $newName = $this->sanitizeFileName($newName);
-               $newIdentifier = rtrim(GeneralUtility::fixWindowsFilePath(dirname($file->getIdentifier())), '/') . '/' . $newName;
+               $newIdentifier = rtrim(GeneralUtility::fixWindowsFilePath(PathUtility::dirname($file->getIdentifier())), '/') . '/' . $newName;
                // The target should not exist already
                if ($this->fileExists($newIdentifier)) {
                        throw new \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException('The target file already exists.', 1320291063);
@@ -935,7 +937,7 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
                $newName = $this->sanitizeFileName($newName);
                $relativeSourcePath = $folder->getIdentifier();
                $sourcePath = $this->getAbsolutePath($relativeSourcePath);
-               $relativeTargetPath = rtrim(GeneralUtility::fixWindowsFilePath(dirname($relativeSourcePath)), '/') . '/' . $newName . '/';
+               $relativeTargetPath = rtrim(GeneralUtility::fixWindowsFilePath(PathUtility::dirname($relativeSourcePath)), '/') . '/' . $newName . '/';
                $targetPath = $this->getAbsolutePath($relativeTargetPath);
                // get all files and folders we are going to move, to have a map for updating later.
                $filesAndFolders = $this->getFileAndFoldernamesInPath($sourcePath, TRUE);
index a261ea9..b89d81a 100644 (file)
@@ -26,6 +26,9 @@ namespace TYPO3\CMS\Core\Resource;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 /**
  * A folder that groups files in a storage. This may be a folder on the local
  * disk, a bucket in Amazon S3 or a user or a tag in Flickr.
@@ -273,7 +276,7 @@ class Folder implements FolderInterface {
         * @return File The file object
         */
        public function addFile($localFilePath, $fileName = NULL, $conflictMode = 'cancel') {
-               $fileName = $fileName ? $fileName : basename($localFilePath);
+               $fileName = $fileName ? $fileName : PathUtility::basename($localFilePath);
                return $this->storage->addFile($localFilePath, $this, $fileName, $conflictMode);
        }
 
index cbb51e5..e059c23 100644 (file)
@@ -27,6 +27,9 @@ namespace TYPO3\CMS\Core\Resource;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 /**
  * Compressor
  * This merges and compresses CSS and JavaScript files of the TYPO3 Backend.
@@ -312,7 +315,7 @@ class ResourceCompressor {
                                $contents = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl(\TYPO3\CMS\Core\Utility\GeneralUtility::resolveBackPath($this->rootPath . $filename));
                                // only fix paths if files aren't already in typo3temp (already processed)
                                if ($type === 'css' && !\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($filename, $this->targetDirectory)) {
-                                       $contents = $this->cssFixRelativeUrlPaths($contents, dirname($filename) . '/');
+                                       $contents = $this->cssFixRelativeUrlPaths($contents, PathUtility::dirname($filename) . '/');
                                }
                                $concatenated .= LF . $contents;
                        }
@@ -362,7 +365,7 @@ class ResourceCompressor {
                // generate the unique name of the file
                $filenameAbsolute = \TYPO3\CMS\Core\Utility\GeneralUtility::resolveBackPath($this->rootPath . $this->getFilenameFromMainDir($filename));
                $unique = $filenameAbsolute . filemtime($filenameAbsolute) . filesize($filenameAbsolute);
-               $pathinfo = pathinfo($filename);
+               $pathinfo = PathUtility::pathinfo($filename);
                $targetFile = $this->targetDirectory . $pathinfo['filename'] . '-' . md5($unique) . '.css';
                // only create it, if it doesn't exist, yet
                if (!file_exists((PATH_site . $targetFile)) || $this->createGzipped && !file_exists((PATH_site . $targetFile . '.gzip'))) {
@@ -403,7 +406,7 @@ class ResourceCompressor {
                        // we have to fix relative paths, if we aren't working on a file in our target directory
                        if (strpos($filename, $this->targetDirectory) === FALSE) {
                                $filenameRelativeToMainDir = substr($filename, strlen($this->backPath));
-                               $contents = $this->cssFixRelativeUrlPaths($contents, dirname($filenameRelativeToMainDir) . '/');
+                               $contents = $this->cssFixRelativeUrlPaths($contents, PathUtility::dirname($filenameRelativeToMainDir) . '/');
                        }
                        $this->writeFileAndCompressed($targetFile, $contents);
                }
@@ -496,7 +499,7 @@ class ResourceCompressor {
                // generate the unique name of the file
                $filenameAbsolute = \TYPO3\CMS\Core\Utility\GeneralUtility::resolveBackPath($this->rootPath . $this->getFilenameFromMainDir($filename));
                $unique = $filenameAbsolute . filemtime($filenameAbsolute) . filesize($filenameAbsolute);
-               $pathinfo = pathinfo($filename);
+               $pathinfo = PathUtility::pathinfo($filename);
                $targetFile = $this->targetDirectory . $pathinfo['filename'] . '-' . md5($unique) . '.js';
                // only create it, if it doesn't exist, yet
                if (!file_exists((PATH_site . $targetFile)) || $this->createGzipped && !file_exists((PATH_site . $targetFile . '.gzip'))) {
index 21e0e9e..a6b54f2 100644 (file)
@@ -26,6 +26,9 @@ namespace TYPO3\CMS\Core\Resource;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 // TODO implement constructor-level caching
 /**
  * Factory class for FAL objects.
@@ -323,7 +326,7 @@ class ResourceFactory implements \TYPO3\CMS\Core\SingletonInterface {
                                return $this->getObjectFromCombinedIdentifier($input);
                        } elseif ($prefix == 'EXT') {
                                $input = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName($input);
-                               $input = \t3lib_Utility_Path::getRelativePath(PATH_site, dirname($input)) . basename($input);
+                               $input = PathUtility::getRelativePath(PATH_site, PathUtility::dirname($input)) . PathUtility::basename($input);
                                return $this->getFileObjectFromCombinedIdentifier($input);
                        }
                } else {
index 2c8c454..7f2f931 100644 (file)
@@ -26,6 +26,9 @@ namespace TYPO3\CMS\Core\Resource;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 /**
  * A "mount point" inside the TYPO3 file handling.
  *
@@ -713,7 +716,7 @@ class ResourceStorage {
                        throw new \InvalidArgumentException('File "' . $localFilePath . '" does not exist.', 1319552745);
                }
                $targetFolder = $targetFolder ? $targetFolder : $this->getDefaultFolder();
-               $fileName = $fileName ? $fileName : basename($localFilePath);
+               $fileName = $fileName ? $fileName : PathUtility::basename($localFilePath);
                if ($conflictMode === 'cancel' && $this->driver->fileExistsInFolder($fileName, $targetFolder)) {
                        throw new Exception\ExistingTargetFileNameException('File "' . $fileName . '" already exists in folder ' . $targetFolder->getIdentifier(), 1322121068);
                } elseif ($conflictMode === 'changeName') {
index 49cff0b..4e3b146 100644 (file)
@@ -32,6 +32,9 @@ namespace TYPO3\CMS\Core\Resource\Service;
  *
  * @author Andreas Wolf <andreas.wolf@typo3.org>
  */
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 class ImageProcessingService {
 
        /**
@@ -87,7 +90,7 @@ class ImageProcessingService {
                $gifCreator = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Imaging\\GifBuilder');
                $gifCreator->init();
                if ($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']) {
-                       $filename = basename($theImage);
+                       $filename = PathUtility::basename($theImage);
                        // Remove extension
                        $filename = substr($filename, 0, strrpos($filename, '.'));
                        $tempFilePrefixLength = intval($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']);
index 69076db..cbdb99c 100644 (file)
@@ -26,6 +26,9 @@ namespace TYPO3\CMS\Core\Resource\Service;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\PathUtility;
+
 /**
  * Magic image service
  *
@@ -97,7 +100,7 @@ class MagicImageService {
                // Create the magic image
                $magicImageInfo = $this->getImageObject()->imageMagickConvert($imageFilePath, 'WEB', $maxWidth . 'm', $maxHeight . 'm');
                if ($magicImageInfo[3]) {
-                       $targetFileName = 'RTEmagicC_' . pathInfo($imageFileObject->getName(), PATHINFO_FILENAME) . '.' . pathinfo($magicImageInfo[3], PATHINFO_EXTENSION);
+                       $targetFileName = 'RTEmagicC_' . PathUtility::pathInfo($imageFileObject->getName(), PATHINFO_FILENAME) . '.' . PathUtility::pathinfo($magicImageInfo[3], PATHINFO_EXTENSION);
                        $magicFolder = $this->getMagicFolder($targetFolderCombinedIdentifier);
                        if ($magicFolder instanceof \TYPO3\CMS\Core\Resource\Folder) {
                                $magicImage = $magicFolder->addFile($magicImageInfo[3], $targetFileName, 'changeName');
index 1f60348..6882280 100644 (file)
@@ -129,6 +129,70 @@ class PathUtility {
                return rtrim($path, $separator) . $separator;
        }
 
+
+       /**
+        * Returns trailing name component of path
+        * Since basename() is locale dependent we need to access
+        * the filesystem with the same locale of the system, not
+        * the rendering context.
+        * @see http://www.php.net/manual/en/function.basename.php
+        *
+        *
+        * @param string $path
+        *
+        * @return string
+        *
+        */
+       static public function basename($path) {
+               $currentLocale = setlocale(LC_CTYPE, 0);
+               setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
+               $basename = basename($path);
+               setlocale(LC_CTYPE, $currentLocale);
+               return $basename;
+       }
+
+       /**
+        * Returns parent directory's path
+        * Since dirname() is locale dependent we need to access
+        * the filesystem with the same locale of the system, not
+        * the rendering context.
+        * @see http://www.php.net/manual/en/function.dirname.php
+        *
+        *
+        * @param string $path
+        *
+        * @return string
+        *
+        */
+       static public function dirname($path) {
+               $currentLocale = setlocale(LC_CTYPE, 0);
+               setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
+               $dirname = dirname($path);
+               setlocale(LC_CTYPE, $currentLocale);
+               return $dirname;
+       }
+
+       /**
+        * Returns parent directory's path
+        * Since dirname() is locale dependent we need to access
+        * the filesystem with the same locale of the system, not
+        * the rendering context.
+        * @see http://www.php.net/manual/en/function.dirname.php
+        *
+        *
+        * @param string $path
+        * @param integer $options
+        *
+        * @return string|array
+        *
+        */
+       static public function pathinfo($path, $options = NULL) {
+               $currentLocale = setlocale(LC_CTYPE, 0);
+               setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
+               $pathinfo = $options == NULL ? pathinfo($path) : pathinfo($path, $options);
+               setlocale(LC_CTYPE, $currentLocale);
+               return $pathinfo;
+       }
 }