Completed
Pull Request — master (#168)
by Ankit
03:41
created

Request::isValidFilename()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 3
rs 10
1
<?php
2
3
namespace TusPhp;
4
5
use TusPhp\Tus\Server;
6
use Symfony\Component\HttpFoundation\Request as HttpRequest;
7
8
class Request
9
{
10
    /** @var HttpRequest */
11
    protected $request;
12
13
    /**
14
     * Request constructor.
15
     */
16 1
    public function __construct()
17
    {
18 1
        if (null === $this->request) {
19 1
            $this->request = HttpRequest::createFromGlobals();
20
        }
21 1
    }
22
23
    /**
24
     * Get http method from current request.
25
     *
26
     * @return string
27
     */
28 1
    public function method() : string
29
    {
30 1
        return $this->request->getMethod();
31
    }
32
33
    /**
34
     * Get the current path info for the request.
35
     *
36
     * @return string
37
     */
38 1
    public function path() : string
39
    {
40 1
        return $this->request->getPathInfo();
41
    }
42
43
    /**
44
     * Get upload key from url.
45
     *
46
     * @return string
47
     */
48 1
    public function key() : string
49
    {
50 1
        return basename($this->path());
51
    }
52
53
    /**
54
     * Supported http requests.
55
     *
56
     * @return array
57
     */
58 1
    public function allowedHttpVerbs() : array
59
    {
60
        return [
61 1
            HttpRequest::METHOD_GET,
62 1
            HttpRequest::METHOD_POST,
63 1
            HttpRequest::METHOD_PATCH,
64 1
            HttpRequest::METHOD_DELETE,
65 1
            HttpRequest::METHOD_HEAD,
66 1
            HttpRequest::METHOD_OPTIONS,
67
        ];
68
    }
69
70
    /**
71
     * Retrieve a header from the request.
72
     *
73
     * @param string               $key
74
     * @param string|string[]|null $default
75
     *
76
     * @return string|null
77
     */
78 1
    public function header(string $key, $default = null)
79
    {
80 1
        return $this->request->headers->get($key, $default);
0 ignored issues
show
Bug introduced by
It seems like $default can also be of type string[]; however, parameter $default of Symfony\Component\HttpFoundation\HeaderBag::get() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

80
        return $this->request->headers->get($key, /** @scrutinizer ignore-type */ $default);
Loading history...
81
    }
82
83
    /**
84
     * Get the root URL for the request.
85
     *
86
     * @return string
87
     */
88 1
    public function url() : string
89
    {
90 1
        return rtrim($this->request->getUriForPath('/'), '/');
91
    }
92
93
    /**
94
     * Extract metadata from header.
95
     *
96
     * @param string $key
97
     * @param string $value
98
     *
99
     * @return array
100
     */
101 2
    public function extractFromHeader(string $key, string $value) : array
102
    {
103 2
        $meta = $this->header($key);
104
105 2
        if (false !== strpos($meta, $value)) {
106 2
            $meta = trim(str_replace($value, '', $meta));
107
108 2
            return explode(' ', $meta) ?? [];
109
        }
110
111 1
        return [];
112
    }
113
114
    /**
115
     * Extract base64 encoded filename from header.
116
     *
117
     * @return string
118
     */
119 3
    public function extractFileName() : string
120
    {
121 3
        $name = $this->extractMeta('name') ?: $this->extractMeta('filename');
122
123 3
        if ( ! $this->isValidFilename($name)) {
124 1
            return '';
125
        }
126
127 2
        return $name;
128
    }
129
130
    /**
131
     * Extracts the meta data from the request header.
132
     *
133
     * @param string $requestedKey
134
     *
135
     * @return string
136
     */
137 4
    public function extractMeta(string $requestedKey) : string
138
    {
139 4
        $uploadMetaData = $this->request->headers->get('Upload-Metadata');
140
141 4
        if (empty($uploadMetaData)) {
142 1
            return '';
143
        }
144
145 3
        $uploadMetaDataChunks = explode(',', $uploadMetaData);
146
147 3
        foreach ($uploadMetaDataChunks as $chunk) {
148 3
            list($key, $value) = explode(' ', $chunk);
149
150 3
            if ($key === $requestedKey) {
151 3
                return base64_decode($value);
152
            }
153
        }
154
155 1
        return '';
156
    }
157
158
    /**
159
     * Extract partials from header.
160
     *
161
     * @return array
162
     */
163 1
    public function extractPartials() : array
164
    {
165 1
        return $this->extractFromHeader('Upload-Concat', Server::UPLOAD_TYPE_FINAL . ';');
166
    }
167
168
    /**
169
     * Check if this is a partial upload request.
170
     *
171
     * @return bool
172
     */
173 1
    public function isPartial() : bool
174
    {
175 1
        return Server::UPLOAD_TYPE_PARTIAL === $this->header('Upload-Concat');
176
    }
177
178
    /**
179
     * Check if this is a final concatenation request.
180
     *
181
     * @return bool
182
     */
183 1
    public function isFinal() : bool
184
    {
185 1
        return false !== strpos($this->header('Upload-Concat'), Server::UPLOAD_TYPE_FINAL . ';');
186
    }
187
188
    /**
189
     * Get request.
190
     *
191
     * @return HttpRequest
192
     */
193 1
    public function getRequest() : HttpRequest
194
    {
195 1
        return $this->request;
196
    }
197
198
    /**
199
     * Validate file name.
200
     *
201
     * @param string $filename
202
     *
203
     * @return bool
204
     */
205 2
    protected function isValidFilename(string $filename) : bool
206
    {
207 2
        $forbidden = ['../', ' ', '"', "'", '&', '/', '\\', '?', '#', ':'];
208
209 2
        foreach ($forbidden as $char) {
210 2
            if (false !== strpos($filename, $char)) {
211 1
                return false;
212
            }
213
        }
214
215 1
        return true;
216
    }
217
}
218