Chris@17
|
1 <?php
|
Chris@17
|
2 namespace TYPO3\PharStreamWrapper;
|
Chris@17
|
3
|
Chris@17
|
4 /*
|
Chris@17
|
5 * This file is part of the TYPO3 project.
|
Chris@17
|
6 *
|
Chris@17
|
7 * It is free software; you can redistribute it and/or modify it under the terms
|
Chris@17
|
8 * of the MIT License (MIT). For the full copyright and license information,
|
Chris@17
|
9 * please read the LICENSE file that was distributed with this source code.
|
Chris@17
|
10 *
|
Chris@17
|
11 * The TYPO3 project - inspiring people to share!
|
Chris@17
|
12 */
|
Chris@17
|
13
|
Chris@18
|
14 /**
|
Chris@18
|
15 * Helper provides low-level tools on file name resolving. However it does not
|
Chris@18
|
16 * (and should not) maintain any runtime state information. In order to resolve
|
Chris@18
|
17 * Phar archive paths according resolvers have to be used.
|
Chris@18
|
18 *
|
Chris@18
|
19 * @see \TYPO3\PharStreamWrapper\Resolvable::resolve()
|
Chris@18
|
20 */
|
Chris@17
|
21 class Helper
|
Chris@17
|
22 {
|
Chris@17
|
23 /*
|
Chris@17
|
24 * Resets PHP's OPcache if enabled as work-around for issues in `include()`
|
Chris@17
|
25 * or `require()` calls and OPcache delivering wrong results.
|
Chris@17
|
26 *
|
Chris@17
|
27 * @see https://bugs.php.net/bug.php?id=66569
|
Chris@17
|
28 */
|
Chris@17
|
29 public static function resetOpCache()
|
Chris@17
|
30 {
|
Chris@17
|
31 if (function_exists('opcache_reset')
|
Chris@17
|
32 && function_exists('opcache_get_status')
|
Chris@17
|
33 ) {
|
Chris@17
|
34 $status = opcache_get_status();
|
Chris@17
|
35 if (!empty($status['opcache_enabled'])) {
|
Chris@17
|
36 opcache_reset();
|
Chris@17
|
37 }
|
Chris@17
|
38 }
|
Chris@17
|
39 }
|
Chris@17
|
40
|
Chris@17
|
41 /**
|
Chris@17
|
42 * Determines base file that can be accessed using the regular file system.
|
Chris@17
|
43 * For e.g. "phar:///home/user/bundle.phar/content.txt" that would result
|
Chris@17
|
44 * into "/home/user/bundle.phar".
|
Chris@17
|
45 *
|
Chris@17
|
46 * @param string $path
|
Chris@17
|
47 * @return string|null
|
Chris@17
|
48 */
|
Chris@17
|
49 public static function determineBaseFile($path)
|
Chris@17
|
50 {
|
Chris@17
|
51 $parts = explode('/', static::normalizePath($path));
|
Chris@17
|
52
|
Chris@17
|
53 while (count($parts)) {
|
Chris@17
|
54 $currentPath = implode('/', $parts);
|
Chris@17
|
55 if (@is_file($currentPath)) {
|
Chris@17
|
56 return $currentPath;
|
Chris@17
|
57 }
|
Chris@17
|
58 array_pop($parts);
|
Chris@17
|
59 }
|
Chris@17
|
60
|
Chris@17
|
61 return null;
|
Chris@17
|
62 }
|
Chris@17
|
63
|
Chris@17
|
64 /**
|
Chris@17
|
65 * @param string $path
|
Chris@18
|
66 * @return bool
|
Chris@18
|
67 */
|
Chris@18
|
68 public static function hasPharPrefix($path)
|
Chris@18
|
69 {
|
Chris@18
|
70 return stripos($path, 'phar://') === 0;
|
Chris@18
|
71 }
|
Chris@18
|
72
|
Chris@18
|
73 /**
|
Chris@18
|
74 * @param string $path
|
Chris@17
|
75 * @return string
|
Chris@17
|
76 */
|
Chris@17
|
77 public static function removePharPrefix($path)
|
Chris@17
|
78 {
|
Chris@17
|
79 $path = trim($path);
|
Chris@18
|
80 if (!static::hasPharPrefix($path)) {
|
Chris@17
|
81 return $path;
|
Chris@17
|
82 }
|
Chris@17
|
83 return substr($path, 7);
|
Chris@17
|
84 }
|
Chris@17
|
85
|
Chris@17
|
86 /**
|
Chris@17
|
87 * Normalizes a path, removes phar:// prefix, fixes Windows directory
|
Chris@17
|
88 * separators. Result is without trailing slash.
|
Chris@17
|
89 *
|
Chris@17
|
90 * @param string $path
|
Chris@17
|
91 * @return string
|
Chris@17
|
92 */
|
Chris@17
|
93 public static function normalizePath($path)
|
Chris@17
|
94 {
|
Chris@17
|
95 return rtrim(
|
Chris@18
|
96 static::normalizeWindowsPath(
|
Chris@17
|
97 static::removePharPrefix($path)
|
Chris@17
|
98 ),
|
Chris@17
|
99 '/'
|
Chris@17
|
100 );
|
Chris@17
|
101 }
|
Chris@17
|
102
|
Chris@17
|
103 /**
|
Chris@17
|
104 * Fixes a path for windows-backslashes and reduces double-slashes to single slashes
|
Chris@17
|
105 *
|
Chris@17
|
106 * @param string $path File path to process
|
Chris@17
|
107 * @return string
|
Chris@17
|
108 */
|
Chris@17
|
109 private static function normalizeWindowsPath($path)
|
Chris@17
|
110 {
|
Chris@17
|
111 return str_replace('\\', '/', $path);
|
Chris@17
|
112 }
|
Chris@17
|
113
|
Chris@17
|
114 /**
|
Chris@17
|
115 * Resolves all dots, slashes and removes spaces after or before a path...
|
Chris@17
|
116 *
|
Chris@17
|
117 * @param string $path Input string
|
Chris@17
|
118 * @return string Canonical path, always without trailing slash
|
Chris@17
|
119 */
|
Chris@17
|
120 private static function getCanonicalPath($path)
|
Chris@17
|
121 {
|
Chris@17
|
122 $path = static::normalizeWindowsPath($path);
|
Chris@17
|
123
|
Chris@17
|
124 $absolutePathPrefix = '';
|
Chris@17
|
125 if (static::isAbsolutePath($path)) {
|
Chris@17
|
126 if (static::isWindows() && strpos($path, ':/') === 1) {
|
Chris@17
|
127 $absolutePathPrefix = substr($path, 0, 3);
|
Chris@17
|
128 $path = substr($path, 3);
|
Chris@17
|
129 } else {
|
Chris@17
|
130 $path = ltrim($path, '/');
|
Chris@17
|
131 $absolutePathPrefix = '/';
|
Chris@17
|
132 }
|
Chris@17
|
133 }
|
Chris@17
|
134
|
Chris@17
|
135 $pathParts = explode('/', $path);
|
Chris@17
|
136 $pathPartsLength = count($pathParts);
|
Chris@17
|
137 for ($partCount = 0; $partCount < $pathPartsLength; $partCount++) {
|
Chris@17
|
138 // double-slashes in path: remove element
|
Chris@17
|
139 if ($pathParts[$partCount] === '') {
|
Chris@17
|
140 array_splice($pathParts, $partCount, 1);
|
Chris@17
|
141 $partCount--;
|
Chris@17
|
142 $pathPartsLength--;
|
Chris@17
|
143 }
|
Chris@17
|
144 // "." in path: remove element
|
Chris@17
|
145 if ((isset($pathParts[$partCount]) ? $pathParts[$partCount] : '') === '.') {
|
Chris@17
|
146 array_splice($pathParts, $partCount, 1);
|
Chris@17
|
147 $partCount--;
|
Chris@17
|
148 $pathPartsLength--;
|
Chris@17
|
149 }
|
Chris@17
|
150 // ".." in path:
|
Chris@17
|
151 if ((isset($pathParts[$partCount]) ? $pathParts[$partCount] : '') === '..') {
|
Chris@17
|
152 if ($partCount === 0) {
|
Chris@17
|
153 array_splice($pathParts, $partCount, 1);
|
Chris@17
|
154 $partCount--;
|
Chris@17
|
155 $pathPartsLength--;
|
Chris@17
|
156 } elseif ($partCount >= 1) {
|
Chris@17
|
157 // Rremove this and previous element
|
Chris@17
|
158 array_splice($pathParts, $partCount - 1, 2);
|
Chris@17
|
159 $partCount -= 2;
|
Chris@17
|
160 $pathPartsLength -= 2;
|
Chris@17
|
161 } elseif ($absolutePathPrefix) {
|
Chris@17
|
162 // can't go higher than root dir
|
Chris@17
|
163 // simply remove this part and continue
|
Chris@17
|
164 array_splice($pathParts, $partCount, 1);
|
Chris@17
|
165 $partCount--;
|
Chris@17
|
166 $pathPartsLength--;
|
Chris@17
|
167 }
|
Chris@17
|
168 }
|
Chris@17
|
169 }
|
Chris@17
|
170
|
Chris@17
|
171 return $absolutePathPrefix . implode('/', $pathParts);
|
Chris@17
|
172 }
|
Chris@17
|
173
|
Chris@17
|
174 /**
|
Chris@17
|
175 * Checks if the $path is absolute or relative (detecting either '/' or
|
Chris@17
|
176 * 'x:/' as first part of string) and returns TRUE if so.
|
Chris@17
|
177 *
|
Chris@17
|
178 * @param string $path File path to evaluate
|
Chris@17
|
179 * @return bool
|
Chris@17
|
180 */
|
Chris@17
|
181 private static function isAbsolutePath($path)
|
Chris@17
|
182 {
|
Chris@17
|
183 // Path starting with a / is always absolute, on every system
|
Chris@17
|
184 // On Windows also a path starting with a drive letter is absolute: X:/
|
Chris@17
|
185 return (isset($path[0]) ? $path[0] : null) === '/'
|
Chris@17
|
186 || static::isWindows() && (
|
Chris@17
|
187 strpos($path, ':/') === 1
|
Chris@17
|
188 || strpos($path, ':\\') === 1
|
Chris@17
|
189 );
|
Chris@17
|
190 }
|
Chris@17
|
191
|
Chris@17
|
192 /**
|
Chris@17
|
193 * @return bool
|
Chris@17
|
194 */
|
Chris@17
|
195 private static function isWindows()
|
Chris@17
|
196 {
|
Chris@17
|
197 return stripos(PHP_OS, 'WIN') === 0;
|
Chris@17
|
198 }
|
Chris@17
|
199 } |