Completed
Push — orm-dm-info ( abf332 )
by Nikolaos
02:10
created

ServerRequestFactoryTrait::parseUploadedFiles()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6.8395

Importance

Changes 0
Metric Value
dl 0
loc 38
c 0
b 0
f 0
ccs 15
cts 21
cp 0.7143
rs 8.6897
cc 6
nc 5
nop 1
crap 6.8395
1
<?php
2
3
/**
4
 * This file is part of the Phalcon Framework.
5
 *
6
 * (c) Phalcon Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Phalcon\Http\Message\Traits;
15
16
use Phalcon\Collection;
17
use Phalcon\Helper\Arr;
18
use Phalcon\Http\Message\Exception\InvalidArgumentException;
19
use Phalcon\Http\Message\UploadedFile;
20
use Phalcon\Http\Message\Uri;
21
use Psr\Http\Message\UploadedFileInterface;
22
23
use function explode;
24
use function implode;
25
use function is_array;
26
use function ltrim;
27
use function preg_match;
28
use function preg_replace;
29
use function strlen;
30
use function substr;
31
32
/**
33
 * Trait ServerRequestFactoryTrait
34
 */
35
trait ServerRequestFactoryTrait
36
{
37
    /**
38
     * Calculates the host and port from the headers or the server superglobal
39
     *
40
     * @param Collection $server
41
     * @param Collection $headers
42
     *
43
     * @return array
44
     */
45 11
    private function calculateUriHost(Collection $server, Collection $headers): array
46
    {
47 11
        $return = ['', null];
48
49 11
        if (false !== $this->getHeader($headers, 'host', false)) {
50 3
            $host = $this->getHeader($headers, 'host');
51 3
            return $this->calculateUriHostFromHeader($host);
52
        }
53
54 8
        if (true !== $server->has('SERVER_NAME')) {
55 7
            return $return;
56
        }
57
58 1
        $host = $server->get('SERVER_NAME');
59 1
        $port = $server->get('SERVER_PORT', null);
60
61 1
        return [$host, $port];
62
    }
63
64
    /**
65
     * Get the host and calculate the port if present from the header
66
     *
67
     * @param string $host
68
     *
69
     * @return array
70
     */
71 3
    private function calculateUriHostFromHeader(string $host): array
72
    {
73 3
        $port = null;
74
75
        // works for regname, IPv4 & IPv6
76 3
        if (preg_match('|:(\d+)$|', $host, $matches)) {
77 1
            $host = substr($host, 0, -1 * (strlen($matches[1]) + 1));
78 1
            $port = (int) $matches[1];
79
        }
80
81 3
        return [$host, $port];
82
    }
83
84
    /**
85
     * Get the path from the request from IIS7/Rewrite, REQUEST_URL or
86
     * ORIG_PATH_INFO
87
     *
88
     * @param Collection $server
89
     *
90
     * @return string
91
     */
92 11
    private function calculateUriPath(Collection $server): string
93
    {
94
        /**
95
         * IIS7 with URL Rewrite - double slash
96
         */
97 11
        $iisRewrite   = $server->get('IIS_WasUrlRewritten', null);
98 11
        $unencodedUrl = $server->get('UNENCODED_URL', '');
99
100 11
        if ('1' === $iisRewrite && true !== empty($unencodedUrl)) {
101 1
            return $unencodedUrl;
102
        }
103
104
        /**
105
         * REQUEST_URI
106
         */
107 10
        $requestUri = $server->get('REQUEST_URI', null);
108
109 10
        if (null !== $requestUri) {
110 1
            $result = preg_replace('#^[^/:]+://[^/]+#', '', $requestUri);
111
112 1
            if (!is_string($result)) {
113
                $result = "";
114
            }
115
116 1
            return $result;
117
        }
118
119
        /**
120
         * ORIG_PATH_INFO
121
         */
122 9
        $origPathInfo = $server->get('ORIG_PATH_INFO', null);
123 9
        if (empty($origPathInfo)) {
124 8
            return '/';
125
        }
126
127 1
        return $origPathInfo;
128
    }
129
130
    /**
131
     * Get the query string from the server array
132
     *
133
     * @param Collection $server
134
     *
135
     * @return string
136
     */
137 11
    private function calculateUriQuery(Collection $server): string
138
    {
139 11
        return ltrim($server->get('QUERY_STRING', ''), '?');
140
    }
141
142
    /**
143
     * Calculates the scheme from the server variables
144
     *
145
     * @param Collection $server
146
     * @param Collection $headers
147
     *
148
     * @return string
149
     */
150 11
    private function calculateUriScheme(Collection $server, Collection $headers): string
151
    {
152
        // URI scheme
153 11
        $scheme  = 'https';
154 11
        $isHttps = true;
155 11
        if ($server->has('HTTPS')) {
156
            /** @var mixed $isHttps */
157 1
            $isHttps = (string) $server->get('HTTPS', 'on');
158 1
            $isHttps = 'off' !== mb_strtolower($isHttps);
159
        }
160
161 11
        $header = $this->getHeader($headers, 'x-forwarded-proto', 'https');
162 11
        if (true !== $isHttps || 'https' !== $header) {
163 1
            $scheme = 'http';
164
        }
165
166 11
        return $scheme;
167
    }
168
169
    /**
170
     * Create an UploadedFile object from an $_FILES array element
171
     *
172
     * @param array $file The $_FILES element
173
     *
174
     * @return UploadedFile
175
     *
176
     * @throws InvalidArgumentException If one of the elements is missing
177
     */
178 2
    private function createUploadedFile(array $file): UploadedFile
179
    {
180
        if (
181 2
            !isset($file['tmp_name']) ||
182 2
            !isset($file['size']) ||
183 2
            !isset($file['error'])
184
        ) {
185 1
            throw new InvalidArgumentException(
186
                'The file array must contain tmp_name, size and error; ' .
187 1
                'one or more are missing'
188
            );
189
        }
190
191 1
        return new UploadedFile(
192 1
            $file['tmp_name'],
193 1
            $file['size'],
194 1
            $file['error'],
195 1
            Arr::get($file, 'name'),
196 1
            Arr::get($file, 'type')
197
        );
198
    }
199
200
    /**
201
     * Returns a header
202
     *
203
     * @param Collection $headers
204
     * @param string     $name
205
     * @param mixed|null $defaultValue
206
     *
207
     * @return mixed|string
208
     */
209 11
    private function getHeader(Collection $headers, string $name, $defaultValue = null)
210
    {
211 11
        $value = $headers->get($name, $defaultValue);
212
213 11
        if (is_array($value)) {
214 1
            $value = implode(',', $value);
215
        }
216
217 11
        return $value;
218
    }
219
220
    /**
221
     * Traverses a $_FILES and creates UploadedFile objects from it. It is used
222
     * recursively
223
     *
224
     * @param array $files
225
     *
226
     * @return Collection
227
     */
228 12
    private function parseUploadedFiles(array $files): Collection
229
    {
230 12
        $collection = new Collection();
231
232
        /**
233
         * Loop through the files and check them recursively
234
         */
235 12
        foreach ($files as $key => $file) {
236 2
            $key = (string) $key;
237
238
            /**
239
             * UriInterface
240
             */
241 2
            if ($file instanceof UploadedFileInterface) {
242 1
                $collection->set($key, $file);
243 1
                continue;
244
            }
245
246
            /**
247
             * file is array with 'tmp_name'
248
             */
249 2
            if (is_array($file) && isset($file['tmp_name'])) {
250 2
                $collection->set($key, $this->createUploadedFile($file));
251 1
                continue;
252
            }
253
254
            /**
255
             * file is array of elements - recursion
256
             */
257 1
            if (is_array($file)) {
258 1
                $data = $this->parseUploadedFiles($file);
259 1
                $collection->set($key, $data->toArray());
260 1
                continue;
261
            }
262
        }
263
264 11
        return $collection;
265
    }
266
267
    /**
268
     * Calculates the Uri from the server superglobal or the headers
269
     *
270
     * @param Collection $server
271
     * @param Collection $headers
272
     *
273
     * @return Uri
274
     */
275 11
    private function parseUri(Collection $server, Collection $headers): Uri
276
    {
277 11
        $uri = new Uri('');
278
279
        /**
280
         * Scheme
281
         */
282 11
        $scheme = $this->calculateUriScheme($server, $headers);
283 11
        $uri    = $uri->withScheme($scheme);
284
285
        /**
286
         * Host/Port
287
         */
288 11
        [$host, $port] = $this->calculateUriHost($server, $headers);
0 ignored issues
show
Bug introduced by
The variable $host does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $port does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
289 11
        if (true !== empty($host)) {
290 4
            $uri = $uri->withHost($host);
291 4
            if (true !== empty($port)) {
292 2
                $uri = $uri->withPort($port);
293
            }
294
        }
295
296
        /**
297
         * Path
298
         */
299 11
        $path  = $this->calculateUriPath($server);
300 11
        $split = explode('#', $path);
301 11
        $path  = explode('?', $split[0]);
302 11
        $uri   = $uri->withPath($path[0]);
303
304 11
        if (count($split) > 1) {
305
            /**
306
             * Fragment
307
             */
308 1
            $uri = $uri->withFragment($split[1]);
309
        }
310
311
312
        /**
313
         * Query
314
         */
315 11
        $query = $this->calculateUriQuery($server);
316 11
        $uri   = $uri->withQuery($query);
317
318 11
        return $uri;
319
    }
320
}
321