Passed
Push — 4.1.1 ( 01ed8a )
by Robbie
09:45
created

Path::join()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 17
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 4
nop 1
dl 0
loc 17
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Core;
4
5
use InvalidArgumentException;
6
7
/**
8
 * Path manipulation helpers
9
 */
10
class Path
11
{
12
    const TRIM_CHARS = ' /\\';
13
14
    /**
15
     * Joins one or more paths, normalising all separators to DIRECTORY_SEPARATOR
16
     *
17
     * Note: Errors on collapsed `/../` for security reasons. Use realpath() if you need to
18
     * join a trusted relative path.
19
     * @link https://www.owasp.org/index.php/Testing_Directory_traversal/file_include_(OTG-AUTHZ-001)
20
     * @see File::join_paths() for joining file identifiers
21
     *
22
     * @param array $parts
23
     * @return string Combined path, not including trailing slash (unless it's a single slash)
24
     */
25
    public static function join(...$parts)
26
    {
27
        // In case $parts passed as an array in first parameter
28
        if (count($parts) === 1 && is_array($parts[0])) {
29
            $parts = $parts[0];
30
        }
31
32
        // Cleanup and join all parts
33
        $parts = array_filter(array_map('trim', $parts));
34
        $fullPath = static::normalise(implode(DIRECTORY_SEPARATOR, $parts));
35
36
        // Protect against directory traversal vulnerability (OTG-AUTHZ-001)
37
        if (strpos($fullPath, '..') !== false) {
38
            throw new InvalidArgumentException('Can not collapse relative folders');
39
        }
40
41
        return $fullPath ?: DIRECTORY_SEPARATOR;
42
    }
43
44
    /**
45
     * Normalise absolute or relative filesystem path.
46
     * Important: Single slashes are converted to empty strings (empty relative paths)
47
     *
48
     * @param string $path Input path
49
     * @param bool $relative
50
     * @return string Path with no trailing slash. If $relative is true, also trim leading slashes
51
     */
52
    public static function normalise($path, $relative = false)
53
    {
54
        $path = trim(Convert::slashes($path));
55
        if ($relative) {
56
            return trim($path, self::TRIM_CHARS);
57
        } else {
58
            return rtrim($path, self::TRIM_CHARS);
59
        }
60
    }
61
}
62