Completed
Push — master ( ccc96b...3d250b )
by Ankit
02:27
created

Request::extractAllMeta()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 18
ccs 0
cts 10
cp 0
crap 12
rs 9.9666
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
     * Extracts all meta data from the request header.
160
     *
161
     * @return string[]
162
     */
163
    public function extractAllMeta() : array
164
    {
165
        $uploadMetaData = $this->request->headers->get('Upload-Metadata');
166
167
        if (empty($uploadMetaData)) {
168
            return [];
169
        }
170
171
        $uploadMetaDataChunks = explode(',', $uploadMetaData);
172
173
        $result = [];
174
        foreach ($uploadMetaDataChunks as $chunk) {
175
            list($key, $value) = explode(' ', $chunk);
176
177
            $result[$key] = base64_decode($value);
178
        }
179
180
        return $result;
181
    }
182
183
    /**
184
     * Extract partials from header.
185
     *
186
     * @return array
187
     */
188 1
    public function extractPartials() : array
189
    {
190 1
        return $this->extractFromHeader('Upload-Concat', Server::UPLOAD_TYPE_FINAL . ';');
191
    }
192
193
    /**
194
     * Check if this is a partial upload request.
195
     *
196
     * @return bool
197
     */
198 1
    public function isPartial() : bool
199
    {
200 1
        return Server::UPLOAD_TYPE_PARTIAL === $this->header('Upload-Concat');
201
    }
202
203
    /**
204
     * Check if this is a final concatenation request.
205
     *
206
     * @return bool
207
     */
208 1
    public function isFinal() : bool
209
    {
210 1
        return false !== strpos($this->header('Upload-Concat'), Server::UPLOAD_TYPE_FINAL . ';');
211
    }
212
213
    /**
214
     * Get request.
215
     *
216
     * @return HttpRequest
217
     */
218 1
    public function getRequest() : HttpRequest
219
    {
220 1
        return $this->request;
221
    }
222
223
    /**
224
     * Validate file name.
225
     *
226
     * @param string $filename
227
     *
228
     * @return bool
229
     */
230 2
    protected function isValidFilename(string $filename) : bool
231
    {
232 2
        $forbidden = ['../', '"', "'", '&', '/', '\\', '?', '#', ':'];
233
234 2
        foreach ($forbidden as $char) {
235 2
            if (false !== strpos($filename, $char)) {
236 1
                return false;
237
            }
238
        }
239
240 1
        return true;
241
    }
242
}
243