1 | <?php |
||
15 | class ServerRequestCreator |
||
16 | { |
||
17 | private $serverRequestFactory; |
||
18 | |||
19 | private $uriFactory; |
||
20 | |||
21 | private $uploadedFileFactory; |
||
22 | |||
23 | private $streamFactory; |
||
24 | |||
25 | 13 | public function __construct( |
|
36 | |||
37 | /** |
||
38 | * Create a new server request from the current environment variables. |
||
39 | * Defaults to a GET request to minimise the risk of an \InvalidArgumentException. |
||
40 | * Includes the current request headers as supplied by the server through `getallheaders()`. |
||
41 | * |
||
42 | * @throws \InvalidArgumentException If no valid method or URI can be determined. |
||
43 | */ |
||
44 | public function fromGlobals(): ServerRequestInterface |
||
54 | |||
55 | /** |
||
56 | * Create a new server request from a set of arrays. |
||
57 | * |
||
58 | * @param array $server Typically $_SERVER or similar structure. |
||
59 | * @param array $headers Typically the output of getallheaders() or similar structure. |
||
60 | * @param array $cookie Typically $_COOKIE or similar structure. |
||
61 | * @param array $get Typically $_GET or similar structure. |
||
62 | * @param array $post Typically $_POST or similar structure. |
||
63 | * @param array $files Typically $_FILES or similar structure. |
||
64 | * |
||
65 | * @throws \InvalidArgumentException If no valid method or URI can be determined. |
||
66 | */ |
||
67 | 7 | public function fromArrays(array $server, array $headers = [], array $cookie = [], array $get = [], array $post = [], array $files = []): ServerRequestInterface |
|
68 | { |
||
69 | 7 | $method = $this->getMethodFromEnv($server); |
|
70 | 7 | $uri = $this->getUriFromEnvWithHTTP($server); |
|
71 | 7 | $protocol = isset($server['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $server['SERVER_PROTOCOL']) : '1.1'; |
|
72 | |||
73 | 7 | $serverRequest = $this->serverRequestFactory->createServerRequest($method, $uri, $server); |
|
74 | 7 | foreach ($headers as $name => $value) { |
|
75 | $serverRequest = $serverRequest->withAddedHeader($name, $value); |
||
76 | } |
||
77 | |||
78 | return $serverRequest |
||
79 | 7 | ->withProtocolVersion($protocol) |
|
80 | 7 | ->withCookieParams($cookie) |
|
81 | 7 | ->withQueryParams($get) |
|
82 | 7 | ->withParsedBody($post) |
|
83 | 7 | ->withUploadedFiles($this->normalizeFiles($files)); |
|
84 | } |
||
85 | |||
86 | 7 | private function getMethodFromEnv(array $environment): string |
|
87 | { |
||
88 | 7 | if (false === isset($environment['REQUEST_METHOD'])) { |
|
89 | throw new \InvalidArgumentException('Cannot determine HTTP method'); |
||
90 | } |
||
91 | |||
92 | 7 | return $environment['REQUEST_METHOD']; |
|
93 | } |
||
94 | |||
95 | 7 | private function getUriFromEnvWithHTTP(array $environment): UriInterface |
|
96 | { |
||
97 | 7 | $uri = $this->createUriFromArray($environment); |
|
98 | 7 | if (empty($uri->getScheme())) { |
|
99 | 6 | $uri = $uri->withScheme('http'); |
|
100 | } |
||
101 | |||
102 | 7 | return $uri; |
|
103 | } |
||
104 | |||
105 | /** |
||
106 | * Return an UploadedFile instance array. |
||
107 | * |
||
108 | * @param array $files A array which respect $_FILES structure |
||
109 | * |
||
110 | * @return UploadedFileInterface[] |
||
111 | * |
||
112 | * @throws \InvalidArgumentException for unrecognized values |
||
113 | */ |
||
114 | 7 | private function normalizeFiles(array $files): array |
|
115 | { |
||
116 | 7 | $normalized = []; |
|
117 | |||
118 | 7 | foreach ($files as $key => $value) { |
|
119 | 7 | if ($value instanceof UploadedFileInterface) { |
|
120 | 2 | $normalized[$key] = $value; |
|
121 | 6 | } elseif (is_array($value) && isset($value['tmp_name'])) { |
|
122 | 4 | $normalized[$key] = $this->createUploadedFileFromSpec($value); |
|
123 | 2 | } elseif (is_array($value)) { |
|
124 | 1 | $normalized[$key] = $this->normalizeFiles($value); |
|
125 | } else { |
||
126 | 7 | throw new \InvalidArgumentException('Invalid value in files specification'); |
|
127 | } |
||
128 | } |
||
129 | |||
130 | 6 | return $normalized; |
|
131 | } |
||
132 | |||
133 | /** |
||
134 | * Create and return an UploadedFile instance from a $_FILES specification. |
||
135 | * |
||
136 | * If the specification represents an array of values, this method will |
||
137 | * delegate to normalizeNestedFileSpec() and return that return value. |
||
138 | * |
||
139 | * @param array $value $_FILES struct |
||
140 | * |
||
141 | * @return array|UploadedFileInterface |
||
142 | */ |
||
143 | 4 | private function createUploadedFileFromSpec(array $value) |
|
144 | { |
||
145 | 4 | if (is_array($value['tmp_name'])) { |
|
146 | 1 | return $this->normalizeNestedFileSpec($value); |
|
147 | } |
||
148 | |||
149 | 4 | return $this->uploadedFileFactory->createUploadedFile( |
|
150 | 4 | $this->streamFactory->createStreamFromFile($value['tmp_name']), |
|
151 | 4 | (int) $value['size'], |
|
152 | 4 | (int) $value['error'], |
|
153 | 4 | $value['name'], |
|
154 | 4 | $value['type'] |
|
155 | ); |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Normalize an array of file specifications. |
||
160 | * |
||
161 | * Loops through all nested files and returns a normalized array of |
||
162 | * UploadedFileInterface instances. |
||
163 | * |
||
164 | * @param array $files |
||
165 | * |
||
166 | * @return UploadedFileInterface[] |
||
167 | */ |
||
168 | 1 | private function normalizeNestedFileSpec(array $files = []): array |
|
169 | { |
||
170 | 1 | $normalizedFiles = []; |
|
171 | |||
172 | 1 | foreach (array_keys($files['tmp_name']) as $key) { |
|
173 | $spec = [ |
||
174 | 1 | 'tmp_name' => $files['tmp_name'][$key], |
|
175 | 1 | 'size' => $files['size'][$key], |
|
176 | 1 | 'error' => $files['error'][$key], |
|
177 | 1 | 'name' => $files['name'][$key], |
|
178 | 1 | 'type' => $files['type'][$key], |
|
179 | ]; |
||
180 | 1 | $normalizedFiles[$key] = $this->createUploadedFileFromSpec($spec); |
|
181 | } |
||
182 | |||
183 | 1 | return $normalizedFiles; |
|
184 | } |
||
185 | |||
186 | /** |
||
187 | * Create a new uri from server variable. |
||
188 | * |
||
189 | * @param array $server Typically $_SERVER or similar structure. |
||
190 | */ |
||
191 | 13 | private function createUriFromArray(array $server): UriInterface |
|
221 | } |
||
222 |