[FEATURE] Integrate possibility to resolve relative path walks
authorOliver Hader <oliver@typo3.org>
Wed, 8 Feb 2012 12:26:48 +0000 (13:26 +0100)
committerTolleiv Nietsch <info@tolleiv.de>
Wed, 8 Feb 2012 19:09:31 +0000 (20:09 +0100)
The BACK_PATH is a known thing in TYPO3, used to define the
relative path to the TYPO3 main directory (./typo3/). Since this
setting is static and strict, it would be nice to finally get
rid of it and have a dynamic way to the determine the relative
paths to be walked.

Examples:
t3lib_utility_Path::resolveBackPath(PATH_t3lib)
t3lib_utility_Path::resolveBackPath(PATH_typo3)
t3lib_utility_Path::resolveBackPath(t3lib_extMgm::extPath('myext') . 'Resources/'):

Change-Id: I4e3b0483299f030bf017074a076201acf61edab9
Resolves: #33753
Releases: 4.7
Reviewed-on: http://review.typo3.org/8905
Reviewed-by: Philipp Gampe
Tested-by: Philipp Gampe
Reviewed-by: Tolleiv Nietsch
Tested-by: Tolleiv Nietsch
t3lib/core_autoload.php
t3lib/utility/class.t3lib_utility_path.php [new file with mode: 0644]
tests/t3lib/utility/class.t3lib_utility_pathTest.php [new file with mode: 0644]

index 234f83d..1d81c04 100644 (file)
@@ -244,6 +244,7 @@ $t3libClasses = array(
        't3lib_utility_mail' => PATH_t3lib . 'utility/class.t3lib_utility_mail.php',
        't3lib_utility_math' => PATH_t3lib . 'utility/class.t3lib_utility_math.php',
        't3lib_utility_monitor' => PATH_t3lib . 'utility/class.t3lib_utility_monitor.php',
+       't3lib_utility_path' => PATH_t3lib . 'utility/class.t3lib_utility_path.php',
        't3lib_utility_phpoptions' => PATH_t3lib . 'utility/class.t3lib_utility_phpoptions.php',
        't3lib_utility_versionnumber' => PATH_t3lib . 'utility/class.t3lib_utility_versionnumber.php',
        't3lib_xml' => PATH_t3lib . 'class.t3lib_xml.php',
diff --git a/t3lib/utility/class.t3lib_utility_path.php b/t3lib/utility/class.t3lib_utility_path.php
new file mode 100644 (file)
index 0000000..5472977
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2012 Oliver Hader <oliver.hader@typo3.org>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ * A copy is found in the textfile GPL.txt and important notices to the license
+ * from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Class with helper functions for file paths.
+ *
+ * @author Oliver Hader <oliver.hader@typo3.org>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+final class t3lib_utility_Path {
+       /**
+        * Gets the relative path from the current used script to a given directory.
+        * The allowed TYPO3 path is checked as well, thus it's not possible to go to upper levels.
+        *
+        * @param string $targetPath Absolute target path
+        * @return NULL|string
+        */
+       public static function getRelativePathTo($targetPath) {
+               return self::getRelativePath(
+                       dirname(PATH_thisScript),
+                       $targetPath
+               );
+       }
+
+       /**
+        * Gets the relative path from a source directory to a target directory.
+        * The allowed TYPO3 path is checked as well, thus it's not possible to go to upper levels.
+        *
+        * @param string $sourcePath Absolute source path
+        * @param string $targetPath Absolute target path
+        * @return NULL|string
+        */
+       public static function getRelativePath($sourcePath, $targetPath) {
+               $relativePath = NULL;
+
+               $sourcePath = rtrim($sourcePath, DIRECTORY_SEPARATOR);
+               $targetPath = rtrim($targetPath, DIRECTORY_SEPARATOR);
+
+               if ($sourcePath !== $targetPath) {
+                       $commonPrefix = self::getCommonPrefix(array($sourcePath, $targetPath));
+
+                       if ($commonPrefix !== NULL && t3lib_div::isAllowedAbsPath($commonPrefix)) {
+                               $commonPrefixLength = strlen($commonPrefix);
+                               $resolvedSourcePath = '';
+                               $resolvedTargetPath = '';
+
+                               if (strlen($sourcePath) > $commonPrefixLength) {
+                                       $resolvedSourcePath = (string) substr($sourcePath, $commonPrefixLength);
+                               }
+                               if (strlen($targetPath) > $commonPrefixLength) {
+                                       $resolvedTargetPath = (string) substr($targetPath, $commonPrefixLength);
+                               }
+
+                               $sourcePathSteps = count(explode(DIRECTORY_SEPARATOR, $resolvedSourcePath));
+                               $relativePath = self::sanitizeTrailingSeparator(
+                                       str_repeat('../', $sourcePathSteps) .
+                                       str_replace(DIRECTORY_SEPARATOR, '/', $resolvedTargetPath)
+                               );
+                       }
+               }
+
+               return $relativePath;
+       }
+
+       /**
+        * Gets the common path prefix out of many paths.
+        * + /var/www/domain.com/typo3/sysext/cms/
+        * + /var/www/domain.com/typo3/sysext/em/
+        * + /var/www/domain.com/typo3/sysext/file/
+        * = /var/www/domain.com/typo3/sysext/
+        *
+        * @param array $paths Paths to be processed
+        * @return NULL|string
+        */
+       public static function getCommonPrefix(array $paths) {
+               $commonPath = NULL;
+
+               if (count($paths) === 1) {
+                       $commonPath = array_shift($paths);
+               } elseif (count($paths) > 1) {
+                       $parts = explode(DIRECTORY_SEPARATOR, array_shift($paths));
+                       $comparePath = '';
+                       $break = FALSE;
+
+                       foreach ($parts as $part) {
+                               $comparePath .= $part . DIRECTORY_SEPARATOR;
+
+                               foreach ($paths as $path) {
+                                       if (strpos($path . DIRECTORY_SEPARATOR, $comparePath) !== 0) {
+                                               $break = TRUE;
+                                               break;
+                                       }
+                               }
+
+                               if ($break) {
+                                       break;
+                               }
+
+                               $commonPath = $comparePath;
+                       }
+               }
+
+               if ($commonPath !== NULL) {
+                       $commonPath = self::sanitizeTrailingSeparator(
+                               $commonPath,
+                               DIRECTORY_SEPARATOR
+                       );
+               }
+
+               return $commonPath;
+       }
+
+       /**
+        * Sanitizes a trailing separator.
+        * (e.g. 'some/path' -> 'some/path/')
+        *
+        * @param string $path The path to be sanitized
+        * @param string $separator The separator to be used
+        * @return string
+        */
+       public static function sanitizeTrailingSeparator($path, $separator = '/') {
+               return rtrim($path, $separator) . $separator;
+       }
+}
+?>
\ No newline at end of file
diff --git a/tests/t3lib/utility/class.t3lib_utility_pathTest.php b/tests/t3lib/utility/class.t3lib_utility_pathTest.php
new file mode 100644 (file)
index 0000000..a307c4a
--- /dev/null
@@ -0,0 +1,158 @@
+<?php
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2012 Oliver Hader <oliver.hader@typo3.org>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ * A copy is found in the textfile GPL.txt and important notices to the license
+ * from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Testcase for class t3lib_utility_Path
+ *
+ * @author Oliver Hader <oliver.hader@typo3.org>
+ *
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+
+class t3lib_utility_PathTest extends tx_phpunit_testcase {
+       /**
+        * @param array $paths
+        * @param string $expected
+        * @dataProvider isCommonPrefixResolvedCorrectlyDataProvider
+        * @test
+        */
+       public function isCommonPrefixResolvedCorrectly(array $paths, $expected) {
+               $commonPrefix = t3lib_utility_Path::getCommonPrefix($paths);
+               $this->assertEquals($expected, $commonPrefix);
+       }
+
+       /**
+        * @return array
+        */
+       public function isCommonPrefixResolvedCorrectlyDataProvider() {
+               return array(
+                       array(
+                               array(
+                                       '/var/www/myhost.com/t3lib/',
+                               ),
+                               '/var/www/myhost.com/t3lib/'
+                       ),
+                       array(
+                               array(
+                                       '/var/www/myhost.com/t3lib/',
+                                       '/var/www/myhost.com/t3lib/',
+                               ),
+                               '/var/www/myhost.com/t3lib/'
+                       ),
+                       array(
+                               array(
+                                       '/var/www/myhost.com/typo3/',
+                                       '/var/www/myhost.com/t3lib/',
+                               ),
+                               '/var/www/myhost.com/'
+                       ),
+                       array(
+                               array(
+                                       '/var/www/myhost.com/uploads/',
+                                       '/var/www/myhost.com/typo3/',
+                                       '/var/www/myhost.com/t3lib/',
+                               ),
+                               '/var/www/myhost.com/'
+                       ),
+                       array(
+                               array(
+                                       '/var/www/myhost.com/uploads/directory/',
+                                       '/var/www/myhost.com/typo3/sysext/',
+                                       '/var/www/myhost.com/typo3/contrib/',
+                                       '/var/www/myhost.com/t3lib/utility/',
+                               ),
+                               '/var/www/myhost.com/'
+                       ),
+               );
+       }
+
+       /**
+        * @param string $source
+        * @param string $target
+        * @param string $expected
+        * @dataProvider isRelativePathResolvedCorrectlyDataProvider
+        * @test
+        */
+       public function isRelativePathResolvedCorrectly($source, $target, $expected) {
+               $relativePath = t3lib_utility_Path::getRelativePath($source, $target);
+               $this->assertEquals($expected, $relativePath);
+       }
+
+       /**
+        * @return array
+        */
+       public function isRelativePathResolvedCorrectlyDataProvider() {
+               return array(
+                       array(
+                               '/',
+                               PATH_site . 'directory',
+                               NULL
+                       ),
+                       array(
+                               PATH_site . 't3lib/',
+                               PATH_site . 't3lib/',
+                               ''
+                       ),
+                       array(
+                               PATH_site . 'typo3/',
+                               PATH_site . 't3lib/',
+                               '../t3lib/'
+                       ),
+                       array(
+                               PATH_site . 'typo3/sysext/cms/',
+                               PATH_site . 't3lib/utility/',
+                               '../../../t3lib/utility/'
+                       ),
+               );
+       }
+
+       /**
+        * @param string $path
+        * @param string $separator
+        * @param string $expected
+        * @dataProvider isTrailingSeparatorSanitizedCorrectlyDataProvider
+        * @test
+        */
+       public function isTrailingSeparatorSanitizedCorrectly($path, $separator, $expected) {
+               $sanitizedPath = t3lib_utility_Path::sanitizeTrailingSeparator($path, $separator);
+               $this->assertEquals($expected, $sanitizedPath);
+       }
+
+       /**
+        * @return array
+        */
+       public function isTrailingSeparatorSanitizedCorrectlyDataProvider() {
+               return array(
+                       array('/var/www//', '/', '/var/www/'),
+                       array('/var/www/', '/', '/var/www/'),
+                       array('/var/www', '/', '/var/www/'),
+               );
+       }
+}
+
+?>
\ No newline at end of file