1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection\Util;
6:
7: use function array_pop;
8: use function assert;
9: use function explode;
10: use function implode;
11: use function is_string;
12: use function preg_match;
13: use function sprintf;
14: use function str_replace;
15: use function strpos;
16: use function substr;
17: use function trim;
18:
19: use const DIRECTORY_SEPARATOR;
20:
21: class FileHelper
22: {
23: /**
24: * @param non-empty-string $path
25: *
26: * @return non-empty-string
27: *
28: * @psalm-pure
29: */
30: public static function normalizeWindowsPath(string $path): string
31: {
32: $path = str_replace('\\', '/', $path);
33: assert($path !== '');
34:
35: return $path;
36: }
37:
38: /**
39: * @param non-empty-string $originalPath
40: *
41: * @return non-empty-string
42: *
43: * @psalm-pure
44: */
45: public static function normalizePath(string $originalPath, string $directorySeparator = DIRECTORY_SEPARATOR): string
46: {
47: $isLocalPath = $originalPath !== '' && $originalPath[0] === '/';
48:
49: $matches = null;
50: if (! $isLocalPath) {
51: if (! preg_match('~^([a-z]+)\\:\\/\\/(.+)~', $originalPath, $matches)) {
52: $matches = null;
53: }
54: }
55:
56: if ($matches !== null) {
57: [, $scheme, $path] = $matches;
58: } else {
59: $scheme = null;
60: $path = $originalPath;
61: }
62:
63: $path = str_replace(['\\', '//', '///', '////'], '/', $path);
64:
65: $pathRoot = strpos($path, '/') === 0 ? $directorySeparator : '';
66: $pathParts = explode('/', trim($path, '/'));
67:
68: $normalizedPathParts = [];
69: foreach ($pathParts as $pathPart) {
70: if ($pathPart === '.') {
71: continue;
72: }
73:
74: if ($pathPart === '..') {
75: $removedPart = array_pop($normalizedPathParts);
76: assert(is_string($removedPart));
77: if ($scheme === 'phar' && substr($removedPart, -5) === '.phar') {
78: $scheme = null;
79: }
80: } else {
81: $normalizedPathParts[] = $pathPart;
82: }
83: }
84:
85: return ($scheme !== null ? $scheme . '://' : '') . $pathRoot . implode($directorySeparator, $normalizedPathParts);
86: }
87:
88: public static function normalizeSystemPath(string $originalPath): string
89: {
90: $path = self::normalizeWindowsPath($originalPath);
91: preg_match('~^([a-z]+)\\:\\/\\/(.+)~', $path, $matches);
92: $scheme = null;
93: if ($matches !== []) {
94: [, $scheme, $path] = $matches;
95: }
96:
97: // @infection-ignore-all Identical Needed only on Windows
98: if (DIRECTORY_SEPARATOR === '\\') {
99: // @infection-ignore-all UnwrapStrReplace Needed only on Windows
100: $path = str_replace('/', DIRECTORY_SEPARATOR, $path);
101: }
102:
103: assert($path !== '');
104:
105: return ($scheme !== null ? sprintf('%s://', $scheme) : '') . $path;
106: }
107: }
108: