TYPO3  7.6
PathUtility.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Utility;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
21 {
29  public static function getRelativePathTo($targetPath)
30  {
31  return self::getRelativePath(dirname(PATH_thisScript), $targetPath);
32  }
33 
40  public static function getAbsoluteWebPath($targetPath)
41  {
42  if (self::isAbsolutePath($targetPath)) {
43  if (StringUtility::beginsWith($targetPath, PATH_site)) {
44  $targetPath = self::stripPathSitePrefix($targetPath);
45  if (!defined('TYPO3_cliMode')) {
46  $targetPath = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH') . $targetPath;
47  }
48  }
49  } elseif (strpos($targetPath, '://') !== false) {
50  return $targetPath;
51  } else {
52  // Make an absolute path out of it
53  $targetPath = GeneralUtility::resolveBackPath(dirname(PATH_thisScript) . '/' . $targetPath);
54  $targetPath = self::stripPathSitePrefix($targetPath);
55  if (!defined('TYPO3_cliMode')) {
56  $targetPath = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH') . $targetPath;
57  }
58  }
59  return $targetPath;
60  }
61 
70  public static function getRelativePath($sourcePath, $targetPath)
71  {
72  $relativePath = null;
73  $sourcePath = rtrim(GeneralUtility::fixWindowsFilePath($sourcePath), '/');
74  $targetPath = rtrim(GeneralUtility::fixWindowsFilePath($targetPath), '/');
75  if ($sourcePath !== $targetPath) {
76  $commonPrefix = self::getCommonPrefix(array($sourcePath, $targetPath));
77  if ($commonPrefix !== null && GeneralUtility::isAllowedAbsPath($commonPrefix)) {
78  $commonPrefixLength = strlen($commonPrefix);
79  $resolvedSourcePath = '';
80  $resolvedTargetPath = '';
81  $sourcePathSteps = 0;
82  if (strlen($sourcePath) > $commonPrefixLength) {
83  $resolvedSourcePath = (string)substr($sourcePath, $commonPrefixLength);
84  }
85  if (strlen($targetPath) > $commonPrefixLength) {
86  $resolvedTargetPath = (string)substr($targetPath, $commonPrefixLength);
87  }
88  if ($resolvedSourcePath !== '') {
89  $sourcePathSteps = count(explode('/', $resolvedSourcePath));
90  }
91  $relativePath = self::sanitizeTrailingSeparator(str_repeat('../', $sourcePathSteps) . $resolvedTargetPath);
92  }
93  }
94  return $relativePath;
95  }
96 
107  public static function getCommonPrefix(array $paths)
108  {
109  $paths = array_map(array(\TYPO3\CMS\Core\Utility\GeneralUtility::class, 'fixWindowsFilePath'), $paths);
110  $commonPath = null;
111  if (count($paths) === 1) {
112  $commonPath = array_shift($paths);
113  } elseif (count($paths) > 1) {
114  $parts = explode('/', array_shift($paths));
115  $comparePath = '';
116  $break = false;
117  foreach ($parts as $part) {
118  $comparePath .= $part . '/';
119  foreach ($paths as $path) {
120  if (strpos($path . '/', $comparePath) !== 0) {
121  $break = true;
122  break;
123  }
124  }
125  if ($break) {
126  break;
127  }
128  $commonPath = $comparePath;
129  }
130  }
131  if ($commonPath !== null) {
132  $commonPath = self::sanitizeTrailingSeparator($commonPath, '/');
133  }
134  return $commonPath;
135  }
136 
145  public static function sanitizeTrailingSeparator($path, $separator = '/')
146  {
147  return rtrim($path, $separator) . $separator;
148  }
149 
163  public static function basename($path)
164  {
165  $currentLocale = setlocale(LC_CTYPE, 0);
166  setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
167  $basename = basename($path);
168  setlocale(LC_CTYPE, $currentLocale);
169  return $basename;
170  }
171 
185  public static function dirname($path)
186  {
187  $currentLocale = setlocale(LC_CTYPE, 0);
188  setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
189  $dirname = dirname($path);
190  setlocale(LC_CTYPE, $currentLocale);
191  return $dirname;
192  }
193 
208  public static function pathinfo($path, $options = null)
209  {
210  $currentLocale = setlocale(LC_CTYPE, 0);
211  setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
212  $pathinfo = $options == null ? pathinfo($path) : pathinfo($path, $options);
213  setlocale(LC_CTYPE, $currentLocale);
214  return $pathinfo;
215  }
216 
223  public static function isAbsolutePath($path)
224  {
225  // On Windows also a path starting with a drive letter is absolute: X:/
226  if (static::isWindows() && (substr($path, 1, 2) === ':/' || substr($path, 1, 2) === ':\\')) {
227  return true;
228  }
229  // Path starting with a / is always absolute, on every system
230  return $path[0] === '/';
231  }
232 
256  public static function getAbsolutePathOfRelativeReferencedFileOrPath($baseFilenameOrPath, $includeFileName)
257  {
258  $fileName = static::basename($includeFileName);
259  $basePath = substr($baseFilenameOrPath, -1) === '/' ? $baseFilenameOrPath : static::dirname($baseFilenameOrPath);
260  $newDir = static::getCanonicalPath($basePath . '/' . static::dirname($includeFileName));
261  // Avoid double slash on empty path
262  $result = (($newDir !== '/') ? $newDir : '') . '/' . $fileName;
263  return $result;
264  }
265 
266 
267  /*********************
268  *
269  * Cleaning methods
270  *
271  *********************/
278  public static function getCanonicalPath($path)
279  {
280  // Replace backslashes with slashes to work with Windows paths if given
281  $path = trim(str_replace('\\', '/', $path));
282 
283  // @todo do we really need this? Probably only in testing context for vfs?
284  $protocol = '';
285  if (strpos($path, '://') !== false) {
286  list($protocol, $path) = explode('://', $path);
287  $protocol .= '://';
288  }
289 
290  $absolutePathPrefix = '';
291  if (static::isAbsolutePath($path)) {
292  if (static::isWindows() && substr($path, 1, 2) === ':/') {
293  $absolutePathPrefix = substr($path, 0, 3);
294  $path = substr($path, 3);
295  } else {
296  $path = ltrim($path, '/');
297  $absolutePathPrefix = '/';
298  }
299  }
300 
301  $theDirParts = explode('/', $path);
302  $theDirPartsCount = count($theDirParts);
303  for ($partCount = 0; $partCount < $theDirPartsCount; $partCount++) {
304  // double-slashes in path: remove element
305  if ($theDirParts[$partCount] === '') {
306  array_splice($theDirParts, $partCount, 1);
307  $partCount--;
308  $theDirPartsCount--;
309  }
310  // "." in path: remove element
311  if ($theDirParts[$partCount] === '.') {
312  array_splice($theDirParts, $partCount, 1);
313  $partCount--;
314  $theDirPartsCount--;
315  }
316  // ".." in path:
317  if ($theDirParts[$partCount] === '..') {
318  if ($partCount >= 1) {
319  // Rremove this and previous element
320  array_splice($theDirParts, $partCount - 1, 2);
321  $partCount -= 2;
322  $theDirPartsCount -= 2;
323  } elseif ($absolutePathPrefix) {
324  // can't go higher than root dir
325  // simply remove this part and continue
326  array_splice($theDirParts, $partCount, 1);
327  $partCount--;
328  $theDirPartsCount--;
329  }
330  }
331  }
332 
333  return $protocol . $absolutePathPrefix . implode('/', $theDirParts);
334  }
335 
343  public static function stripPathSitePrefix($path)
344  {
345  static $pathSiteLength = null;
346 
347  // calculate length when first needed
348  if (!isset($pathSiteLength)) {
349  $pathSiteLength = strlen(PATH_site);
350  }
351  return substr($path, $pathSiteLength);
352  }
353 
354  /*********************
355  *
356  * Helper methods
357  *
358  *********************/
359 
365  protected static function isWindows()
366  {
367  return TYPO3_OS === 'WIN';
368  }
369 }