]> BookStack Code Mirror - system-cli/blob - src/Services/Paths.php
d0bb10fa26b8bce6576ff7c9191204b741bcc872
[system-cli] / src / Services / Paths.php
1 <?php declare(strict_types=1);
2
3 namespace Cli\Services;
4
5 class Paths
6 {
7
8     /**
9      * Join together the given path components.
10      * Does no resolving or cleaning.
11      * Only the $base will remain absolute if so,
12      * $parts are assumed to treated as non-absolute paths.
13      */
14     public static function join(string $base, string ...$parts): string
15     {
16         $outParts = [rtrim($base, '/\\')];
17         foreach ($parts as $part) {
18             $outParts[] = trim($part, '/\\');
19         }
20
21         return implode(DIRECTORY_SEPARATOR, $outParts);
22     }
23
24     /**
25      * Resolve the full path for the given path/sub-path.
26      * If the provided path is not absolute, it will be returned
27      * be resolved to the provided $base or current working directory if
28      * no $base is provided.
29      */
30     public static function resolve(string $path, string $base = ''): string
31     {
32         if (str_starts_with($path, '/') || str_starts_with($path, '\\')) {
33             return DIRECTORY_SEPARATOR . self::clean($path);
34         }
35
36         $base = rtrim($base ?: getcwd(), '/');
37         $joined = $base . '/' . $path;
38         $absoluteBase = (str_starts_with($base, '/') || str_starts_with($base, '\\'));
39         return ($absoluteBase ? '/' : '') . self::clean($joined);
40     }
41
42     /**
43      * Clean the given path so that all up/down navigations are resolved,
44      * and so its using system-correct directory separators.
45      * Credit to Sven Arduwie in PHP docs:
46      * https://www.php.net/manual/en/function.realpath.php#84012
47      */
48     private static function clean(string $path): string
49     {
50         $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
51         $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
52         $absolutes = [];
53         foreach ($parts as $part) {
54             if ('.' == $part) continue;
55             if ('..' == $part) {
56                 array_pop($absolutes);
57             } else {
58                 $absolutes[] = $part;
59             }
60         }
61         return implode(DIRECTORY_SEPARATOR, $absolutes);
62     }
63 }