Completed
Push — master ( 3a471b...f724e5 )
by Tobias
02:11
created

ServerRequestFactory::getUriFromEnvWithHTTP()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Nyholm\Psr7\Factory;
6
7
use InvalidArgumentException;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Message\UploadedFileInterface;
10
use Interop\Http\Factory\ServerRequestFactoryInterface;
11
use Nyholm\Psr7\ServerRequest;
12
use Nyholm\Psr7\UploadedFile;
13
14
/**
15
 * @author Tobias Nyholm <[email protected]>
16
 * @author Martijn van der Ven <[email protected]>
17
 */
18
final class ServerRequestFactory implements ServerRequestFactoryInterface
19
{
20 23
    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface
21
    {
22 23
        return new ServerRequest($method, $uri, [], null, '1.1', $serverParams);
23
    }
24
25 15
    public function createServerRequestFromArray(array $server): ServerRequestInterface
26
    {
27 15
        return new ServerRequest($this->getMethodFromEnv($server), $this->getUriFromEnvWithHTTP($server), [], null, '1.1', $server);
28
    }
29
30
    /**
31
     * Create a new server request from a set of arrays.
32
     *
33
     * @param array $server  Typically $_SERVER or similar structure.
34
     * @param array $headers Typically the output of getallheaders() or similar structure.
35
     * @param array $cookie  Typically $_COOKIE or similar structure.
36
     * @param array $get     Typically $_GET or similar structure.
37
     * @param array $post    Typically $_POST or similar structure.
38
     * @param array $files   Typically $_FILES or similar structure.
39
     *
40
     * @throws InvalidArgumentException If no valid method or URI can be determined.
41
     */
42
    public function createServerRequestFromArrays(array $server, array $headers, array $cookie, array $get, array $post, array $files): ServerRequestInterface
43
    {
44
        $method = $this->getMethodFromEnv($server);
45
        $uri = $this->getUriFromEnvWithHTTP($server);
46
47
        $protocol = isset($server['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $server['SERVER_PROTOCOL']) : '1.1';
48
49
        $serverRequest = new ServerRequest($method, $uri, $headers, null, $protocol, $server);
50
51
        return $serverRequest
52
            ->withCookieParams($cookie)
53
            ->withQueryParams($get)
54
            ->withParsedBody($post)
55
            ->withUploadedFiles(self::normalizeFiles($files));
56
    }
57
58
    /**
59
     * Create a new server request from the current environment variables.
60
     * Defaults to a GET request to minimise the risk of an InvalidArgumentException.
61
     * Includes the current request headers as supplied by the server through `getallheaders()`.
62
     *
63
     * @throws InvalidArgumentException If no valid method or URI can be determined.
64
     */
65
    public function createServerRequestFromGlobals(): ServerRequestInterface
66
    {
67
        $server = $_SERVER;
68
        if (false === isset($server['REQUEST_METHOD'])) {
69
            $server['REQUEST_METHOD'] = 'GET';
70
        }
71
        $headers = function_exists('getallheaders') ? getallheaders() : [];
72
73
        return $this->createServerRequestFromArrays($server, $headers, $_COOKIE, $_GET, $_POST, $_FILES);
74
    }
75
76 15
    private function getMethodFromEnv(array $environment): string
77
    {
78 15
        if (false === isset($environment['REQUEST_METHOD'])) {
79
            throw new InvalidArgumentException('Cannot determine HTTP method');
80
        }
81
82 15
        return $environment['REQUEST_METHOD'];
83
    }
84
85 15
    private function getUriFromEnvWithHTTP(array $environment): \Psr\Http\Message\UriInterface
86
    {
87 15
        $uri = (new UriFactory())->createUriFromArray($environment);
0 ignored issues
show
Deprecated Code introduced by
The method Nyholm\Psr7\Factory\UriF...y::createUriFromArray() has been deprecated with message: This function will be removed as it serves no purpose.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
88 15
        if ('' === $uri->getScheme()) {
89 15
            $uri = $uri->withScheme('http');
90
        }
91
92 15
        return $uri;
93
    }
94
95
    /**
96
     * Return an UploadedFile instance array.
97
     *
98
     * @param array $files A array which respect $_FILES structure
99
     *
100
     * @throws InvalidArgumentException for unrecognized values
101
     */
102
    private static function normalizeFiles(array $files): array
103
    {
104
        $normalized = [];
105
106
        foreach ($files as $key => $value) {
107
            if ($value instanceof UploadedFileInterface) {
108
                $normalized[$key] = $value;
109
            } elseif (is_array($value) && isset($value['tmp_name'])) {
110
                $normalized[$key] = self::createUploadedFileFromSpec($value);
111
            } elseif (is_array($value)) {
112
                $normalized[$key] = self::normalizeFiles($value);
113
114
                continue;
115
            } else {
116
                throw new InvalidArgumentException('Invalid value in files specification');
117
            }
118
        }
119
120
        return $normalized;
121
    }
122
123
    /**
124
     * Create and return an UploadedFile instance from a $_FILES specification.
125
     *
126
     * If the specification represents an array of values, this method will
127
     * delegate to normalizeNestedFileSpec() and return that return value.
128
     *
129
     * @param array $value $_FILES struct
130
     *
131
     * @return array|UploadedFileInterface
132
     */
133
    private static function createUploadedFileFromSpec(array $value)
134
    {
135
        if (is_array($value['tmp_name'])) {
136
            return self::normalizeNestedFileSpec($value);
137
        }
138
139
        return new UploadedFile(
140
            $value['tmp_name'],
141
            (int) $value['size'],
142
            (int) $value['error'],
143
            $value['name'],
144
            $value['type']
145
        );
146
    }
147
148
    /**
149
     * Normalize an array of file specifications.
150
     *
151
     * Loops through all nested files and returns a normalized array of
152
     * UploadedFileInterface instances.
153
     *
154
     * @param array $files
155
     *
156
     * @return UploadedFileInterface[]
157
     */
158
    private static function normalizeNestedFileSpec(array $files = []): array
159
    {
160
        $normalizedFiles = [];
161
162
        foreach (array_keys($files['tmp_name']) as $key) {
163
            $spec = [
164
                'tmp_name' => $files['tmp_name'][$key],
165
                'size' => $files['size'][$key],
166
                'error' => $files['error'][$key],
167
                'name' => $files['name'][$key],
168
                'type' => $files['type'][$key],
169
            ];
170
            $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
171
        }
172
173
        return $normalizedFiles;
174
    }
175
}
176