Security update to Drupal 8.4.6
[yaffs-website] / vendor / guzzlehttp / psr7 / src / ServerRequest.php
1 <?php
2
3 namespace GuzzleHttp\Psr7;
4
5 use InvalidArgumentException;
6 use Psr\Http\Message\ServerRequestInterface;
7 use Psr\Http\Message\UriInterface;
8 use Psr\Http\Message\StreamInterface;
9 use Psr\Http\Message\UploadedFileInterface;
10
11 /**
12  * Server-side HTTP request
13  *
14  * Extends the Request definition to add methods for accessing incoming data,
15  * specifically server parameters, cookies, matched path parameters, query
16  * string arguments, body parameters, and upload file information.
17  *
18  * "Attributes" are discovered via decomposing the request (and usually
19  * specifically the URI path), and typically will be injected by the application.
20  *
21  * Requests are considered immutable; all methods that might change state are
22  * implemented such that they retain the internal state of the current
23  * message and return a new instance that contains the changed state.
24  */
25 class ServerRequest extends Request implements ServerRequestInterface
26 {
27     /**
28      * @var array
29      */
30     private $attributes = [];
31
32     /**
33      * @var array
34      */
35     private $cookieParams = [];
36
37     /**
38      * @var null|array|object
39      */
40     private $parsedBody;
41
42     /**
43      * @var array
44      */
45     private $queryParams = [];
46
47     /**
48      * @var array
49      */
50     private $serverParams;
51
52     /**
53      * @var array
54      */
55     private $uploadedFiles = [];
56
57     /**
58      * @param string                               $method       HTTP method
59      * @param string|UriInterface                  $uri          URI
60      * @param array                                $headers      Request headers
61      * @param string|null|resource|StreamInterface $body         Request body
62      * @param string                               $version      Protocol version
63      * @param array                                $serverParams Typically the $_SERVER superglobal
64      */
65     public function __construct(
66         $method,
67         $uri,
68         array $headers = [],
69         $body = null,
70         $version = '1.1',
71         array $serverParams = []
72     ) {
73         $this->serverParams = $serverParams;
74
75         parent::__construct($method, $uri, $headers, $body, $version);
76     }
77
78     /**
79      * Return an UploadedFile instance array.
80      *
81      * @param array $files A array which respect $_FILES structure
82      * @throws InvalidArgumentException for unrecognized values
83      * @return array
84      */
85     public static function normalizeFiles(array $files)
86     {
87         $normalized = [];
88
89         foreach ($files as $key => $value) {
90             if ($value instanceof UploadedFileInterface) {
91                 $normalized[$key] = $value;
92             } elseif (is_array($value) && isset($value['tmp_name'])) {
93                 $normalized[$key] = self::createUploadedFileFromSpec($value);
94             } elseif (is_array($value)) {
95                 $normalized[$key] = self::normalizeFiles($value);
96                 continue;
97             } else {
98                 throw new InvalidArgumentException('Invalid value in files specification');
99             }
100         }
101
102         return $normalized;
103     }
104
105     /**
106      * Create and return an UploadedFile instance from a $_FILES specification.
107      *
108      * If the specification represents an array of values, this method will
109      * delegate to normalizeNestedFileSpec() and return that return value.
110      *
111      * @param array $value $_FILES struct
112      * @return array|UploadedFileInterface
113      */
114     private static function createUploadedFileFromSpec(array $value)
115     {
116         if (is_array($value['tmp_name'])) {
117             return self::normalizeNestedFileSpec($value);
118         }
119
120         return new UploadedFile(
121             $value['tmp_name'],
122             (int) $value['size'],
123             (int) $value['error'],
124             $value['name'],
125             $value['type']
126         );
127     }
128
129     /**
130      * Normalize an array of file specifications.
131      *
132      * Loops through all nested files and returns a normalized array of
133      * UploadedFileInterface instances.
134      *
135      * @param array $files
136      * @return UploadedFileInterface[]
137      */
138     private static function normalizeNestedFileSpec(array $files = [])
139     {
140         $normalizedFiles = [];
141
142         foreach (array_keys($files['tmp_name']) as $key) {
143             $spec = [
144                 'tmp_name' => $files['tmp_name'][$key],
145                 'size'     => $files['size'][$key],
146                 'error'    => $files['error'][$key],
147                 'name'     => $files['name'][$key],
148                 'type'     => $files['type'][$key],
149             ];
150             $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
151         }
152
153         return $normalizedFiles;
154     }
155
156     /**
157      * Return a ServerRequest populated with superglobals:
158      * $_GET
159      * $_POST
160      * $_COOKIE
161      * $_FILES
162      * $_SERVER
163      *
164      * @return ServerRequestInterface
165      */
166     public static function fromGlobals()
167     {
168         $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
169         $headers = function_exists('getallheaders') ? getallheaders() : [];
170         $uri = self::getUriFromGlobals();
171         $body = new LazyOpenStream('php://input', 'r+');
172         $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
173
174         $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
175
176         return $serverRequest
177             ->withCookieParams($_COOKIE)
178             ->withQueryParams($_GET)
179             ->withParsedBody($_POST)
180             ->withUploadedFiles(self::normalizeFiles($_FILES));
181     }
182
183     /**
184      * Get a Uri populated with values from $_SERVER.
185      *
186      * @return UriInterface
187      */
188     public static function getUriFromGlobals() {
189         $uri = new Uri('');
190
191         $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
192
193         $hasPort = false;
194         if (isset($_SERVER['HTTP_HOST'])) {
195             $hostHeaderParts = explode(':', $_SERVER['HTTP_HOST']);
196             $uri = $uri->withHost($hostHeaderParts[0]);
197             if (isset($hostHeaderParts[1])) {
198                 $hasPort = true;
199                 $uri = $uri->withPort($hostHeaderParts[1]);
200             }
201         } elseif (isset($_SERVER['SERVER_NAME'])) {
202             $uri = $uri->withHost($_SERVER['SERVER_NAME']);
203         } elseif (isset($_SERVER['SERVER_ADDR'])) {
204             $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
205         }
206
207         if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
208             $uri = $uri->withPort($_SERVER['SERVER_PORT']);
209         }
210
211         $hasQuery = false;
212         if (isset($_SERVER['REQUEST_URI'])) {
213             $requestUriParts = explode('?', $_SERVER['REQUEST_URI']);
214             $uri = $uri->withPath($requestUriParts[0]);
215             if (isset($requestUriParts[1])) {
216                 $hasQuery = true;
217                 $uri = $uri->withQuery($requestUriParts[1]);
218             }
219         }
220
221         if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
222             $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
223         }
224
225         return $uri;
226     }
227
228
229     /**
230      * {@inheritdoc}
231      */
232     public function getServerParams()
233     {
234         return $this->serverParams;
235     }
236
237     /**
238      * {@inheritdoc}
239      */
240     public function getUploadedFiles()
241     {
242         return $this->uploadedFiles;
243     }
244
245     /**
246      * {@inheritdoc}
247      */
248     public function withUploadedFiles(array $uploadedFiles)
249     {
250         $new = clone $this;
251         $new->uploadedFiles = $uploadedFiles;
252
253         return $new;
254     }
255
256     /**
257      * {@inheritdoc}
258      */
259     public function getCookieParams()
260     {
261         return $this->cookieParams;
262     }
263
264     /**
265      * {@inheritdoc}
266      */
267     public function withCookieParams(array $cookies)
268     {
269         $new = clone $this;
270         $new->cookieParams = $cookies;
271
272         return $new;
273     }
274
275     /**
276      * {@inheritdoc}
277      */
278     public function getQueryParams()
279     {
280         return $this->queryParams;
281     }
282
283     /**
284      * {@inheritdoc}
285      */
286     public function withQueryParams(array $query)
287     {
288         $new = clone $this;
289         $new->queryParams = $query;
290
291         return $new;
292     }
293
294     /**
295      * {@inheritdoc}
296      */
297     public function getParsedBody()
298     {
299         return $this->parsedBody;
300     }
301
302     /**
303      * {@inheritdoc}
304      */
305     public function withParsedBody($data)
306     {
307         $new = clone $this;
308         $new->parsedBody = $data;
309
310         return $new;
311     }
312
313     /**
314      * {@inheritdoc}
315      */
316     public function getAttributes()
317     {
318         return $this->attributes;
319     }
320
321     /**
322      * {@inheritdoc}
323      */
324     public function getAttribute($attribute, $default = null)
325     {
326         if (false === array_key_exists($attribute, $this->attributes)) {
327             return $default;
328         }
329
330         return $this->attributes[$attribute];
331     }
332
333     /**
334      * {@inheritdoc}
335      */
336     public function withAttribute($attribute, $value)
337     {
338         $new = clone $this;
339         $new->attributes[$attribute] = $value;
340
341         return $new;
342     }
343
344     /**
345      * {@inheritdoc}
346      */
347     public function withoutAttribute($attribute)
348     {
349         if (false === array_key_exists($attribute, $this->attributes)) {
350             return $this;
351         }
352
353         $new = clone $this;
354         unset($new->attributes[$attribute]);
355
356         return $new;
357     }
358 }