VirtualPath::isTrusted()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * (c) Dennis Meckel
5
 *
6
 * For the full copyright and license information,
7
 * please view the LICENSE file that was distributed with this source code.
8
 */
9
10
namespace Rayne\VirtualPath;
11
12
/**
13
 * A `VirtualPath` object represents a normalised path.
14
 * It detects, removes and flags malicious directory traversals.
15
 *
16
 * *Example*: The path `hello/../world/../../test` gets normalized to `/test`
17
 * but also gets the "jail-breaking attempt" flag set.
18
 *
19
 * @see JailedPath
20
 */
21
class VirtualPath
22
{
23
    /**
24
     * @var bool
25
     */
26
    private $hasJailbreakAttempt = false;
27
28
    /**
29
     * @var string[]
30
     */
31
    private $segments = [];
32
33
    /**
34
     * @var string
35
     */
36
    private $trustedPath;
37
38
    /**
39
     * @var string
40
     */
41
    private $untrustedPath;
42
43
    /**
44
     * @param string|mixed $untrustedPath Gets string casted if possible. Otherwise gets flagged as untrusted and replaced by an empty string.
45
     */
46 185
    public function __construct($untrustedPath)
47
    {
48 185
        $this->setUntrustedPath($untrustedPath);
49 185
        $this->createPathSegments();
50
51 185
        $this->trustedPath = '/' . implode('/', $this->segments);
52 185
    }
53
54
    /**
55
     * @return string Normalised and trusted path relative to the virtual jail.
56
     * @see VirtualPath::getTrustedPath()
57
     */
58 132
    public function __toString()
59
    {
60 132
        return $this->getTrustedPath();
61
    }
62
63
    /**
64
     * Converts the untrusted input to string.
65
     * If converting to string isn't possible
66
     * the jailbreak attempt flag will be set
67
     * and an empty string will be defined as untrusted value.
68
     *
69
     * @param mixed $untrustedPath
70
     */
71 185
    private function setUntrustedPath($untrustedPath)
72
    {
73 185
        if (is_scalar($untrustedPath) || is_object($untrustedPath) && method_exists($untrustedPath, '__toString')) {
74 182
            $this->untrustedPath = (string) $untrustedPath;
75 182
        } else {
76 3
            $this->untrustedPath = '';
77
78
            // Invalid input is interpreted as malicious input.
79 3
            $this->hasJailbreakAttempt = true;
80
        }
81 185
    }
82
83
    /**
84
     *
85
     */
86 185
    private function createPathSegments()
87
    {
88 185
        foreach (explode('/', str_replace('\\', '/', $this->untrustedPath)) as $segment) {
89 185
            if ($segment === '.' || $segment === '') {
90 145
                continue;
91
            }
92
93 158
            if ($segment === '..') {
94 112
                if (null === array_pop($this->segments)) {
95 76
                    $this->hasJailbreakAttempt = true;
96 76
                }
97
98 112
                continue;
99
            }
100
101 116
            $this->segments[] = $segment;
102 185
        }
103 185
    }
104
105
    /**
106
     * @return string[]
107
     */
108 147
    public function getSegments()
109
    {
110 147
        return $this->segments;
111
    }
112
113
    /**
114
     * @return string Normalised and trusted path relative to the virtual jail.
115
     */
116 185
    public function getTrustedPath()
117
    {
118 185
        return $this->trustedPath;
119
    }
120
121
    /**
122
     * @return string Untrusted and perhaps malicious path.
123
     */
124 147
    public function getUntrustedPath()
125
    {
126 147
        return $this->untrustedPath;
127
    }
128
129
    /**
130
     * @return bool Whether the original path input is trustworthy.
131
     */
132 185
    public function isTrusted()
133
    {
134 185
        return !$this->hasJailbreakAttempt;
135
    }
136
137
    /**
138
     * @return VirtualPath Parent of the trusted path. By definition trusted.
139
     */
140 50
    public function buildParent()
141
    {
142 50
        return new self(dirname($this->getTrustedPath()));
143
    }
144
}
145