Mercurial > hg > isophonics-drupal-site
comparison vendor/zendframework/zend-diactoros/src/ServerRequestFactory.php @ 16:c2387f117808
Routine composer update
author | Chris Cannam |
---|---|
date | Tue, 10 Jul 2018 15:07:59 +0100 |
parents | 5fb285c0d0e3 |
children | 129ea1e6d783 |
comparison
equal
deleted
inserted
replaced
15:e200cb7efeb3 | 16:c2387f117808 |
---|---|
9 | 9 |
10 use InvalidArgumentException; | 10 use InvalidArgumentException; |
11 use Psr\Http\Message\UploadedFileInterface; | 11 use Psr\Http\Message\UploadedFileInterface; |
12 use stdClass; | 12 use stdClass; |
13 use UnexpectedValueException; | 13 use UnexpectedValueException; |
14 | |
15 use function array_change_key_case; | |
16 use function array_key_exists; | |
17 use function explode; | |
18 use function implode; | |
19 use function is_array; | |
20 use function is_callable; | |
21 use function strtolower; | |
22 | |
23 use const CASE_LOWER; | |
14 | 24 |
15 /** | 25 /** |
16 * Class for marshaling a request object from the current PHP environment. | 26 * Class for marshaling a request object from the current PHP environment. |
17 * | 27 * |
18 * Logic largely refactored from the ZF2 Zend\Http\PhpEnvironment\Request class. | 28 * Logic largely refactored from the ZF2 Zend\Http\PhpEnvironment\Request class. |
52 array $query = null, | 62 array $query = null, |
53 array $body = null, | 63 array $body = null, |
54 array $cookies = null, | 64 array $cookies = null, |
55 array $files = null | 65 array $files = null |
56 ) { | 66 ) { |
57 $server = static::normalizeServer($server ?: $_SERVER); | 67 $server = normalizeServer( |
58 $files = static::normalizeFiles($files ?: $_FILES); | 68 $server ?: $_SERVER, |
59 $headers = static::marshalHeaders($server); | 69 is_callable(self::$apacheRequestHeaders) ? self::$apacheRequestHeaders : null |
70 ); | |
71 $files = normalizeUploadedFiles($files ?: $_FILES); | |
72 $headers = marshalHeadersFromSapi($server); | |
60 | 73 |
61 if (null === $cookies && array_key_exists('cookie', $headers)) { | 74 if (null === $cookies && array_key_exists('cookie', $headers)) { |
62 $cookies = self::parseCookieHeader($headers['cookie']); | 75 $cookies = parseCookieHeader($headers['cookie']); |
63 } | 76 } |
64 | 77 |
65 return new ServerRequest( | 78 return new ServerRequest( |
66 $server, | 79 $server, |
67 $files, | 80 $files, |
68 static::marshalUriFromServer($server, $headers), | 81 marshalUriFromSapi($server, $headers), |
69 static::get('REQUEST_METHOD', $server, 'GET'), | 82 marshalMethodFromSapi($server), |
70 'php://input', | 83 'php://input', |
71 $headers, | 84 $headers, |
72 $cookies ?: $_COOKIE, | 85 $cookies ?: $_COOKIE, |
73 $query ?: $_GET, | 86 $query ?: $_GET, |
74 $body ?: $_POST, | 87 $body ?: $_POST, |
75 static::marshalProtocolVersion($server) | 88 marshalProtocolVersionFromSapi($server) |
76 ); | 89 ); |
77 } | 90 } |
78 | 91 |
79 /** | 92 /** |
80 * Access a value in an array, returning a default value if not found | 93 * Access a value in an array, returning a default value if not found |
81 * | 94 * |
82 * Will also do a case-insensitive search if a case sensitive search fails. | 95 * @deprecated since 1.8.0; no longer used internally. |
83 * | |
84 * @param string $key | 96 * @param string $key |
85 * @param array $values | 97 * @param array $values |
86 * @param mixed $default | 98 * @param mixed $default |
87 * @return mixed | 99 * @return mixed |
88 */ | 100 */ |
102 * | 114 * |
103 * If found, it is returned as a string, using comma concatenation. | 115 * If found, it is returned as a string, using comma concatenation. |
104 * | 116 * |
105 * If not, the $default is returned. | 117 * If not, the $default is returned. |
106 * | 118 * |
119 * @deprecated since 1.8.0; no longer used internally. | |
107 * @param string $header | 120 * @param string $header |
108 * @param array $headers | 121 * @param array $headers |
109 * @param mixed $default | 122 * @param mixed $default |
110 * @return string | 123 * @return string |
111 */ | 124 */ |
112 public static function getHeader($header, array $headers, $default = null) | 125 public static function getHeader($header, array $headers, $default = null) |
113 { | 126 { |
114 $header = strtolower($header); | 127 $header = strtolower($name); |
115 $headers = array_change_key_case($headers, CASE_LOWER); | 128 $headers = array_change_key_case($headers, CASE_LOWER); |
116 if (array_key_exists($header, $headers)) { | 129 if (array_key_exists($header, $headers)) { |
117 $value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header]; | 130 $value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header]; |
118 return $value; | 131 return $value; |
119 } | 132 } |
124 /** | 137 /** |
125 * Marshal the $_SERVER array | 138 * Marshal the $_SERVER array |
126 * | 139 * |
127 * Pre-processes and returns the $_SERVER superglobal. | 140 * Pre-processes and returns the $_SERVER superglobal. |
128 * | 141 * |
142 * @deprected since 1.8.0; use Zend\Diactoros\normalizeServer() instead. | |
129 * @param array $server | 143 * @param array $server |
130 * @return array | 144 * @return array |
131 */ | 145 */ |
132 public static function normalizeServer(array $server) | 146 public static function normalizeServer(array $server) |
133 { | 147 { |
134 // This seems to be the only way to get the Authorization header on Apache | 148 return normalizeServer( |
135 $apacheRequestHeaders = self::$apacheRequestHeaders; | 149 $server ?: $_SERVER, |
136 if (isset($server['HTTP_AUTHORIZATION']) | 150 is_callable(self::$apacheRequestHeaders) ? self::$apacheRequestHeaders : null |
137 || ! is_callable($apacheRequestHeaders) | 151 ); |
138 ) { | |
139 return $server; | |
140 } | |
141 | |
142 $apacheRequestHeaders = $apacheRequestHeaders(); | |
143 if (isset($apacheRequestHeaders['Authorization'])) { | |
144 $server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['Authorization']; | |
145 return $server; | |
146 } | |
147 | |
148 if (isset($apacheRequestHeaders['authorization'])) { | |
149 $server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['authorization']; | |
150 return $server; | |
151 } | |
152 | |
153 return $server; | |
154 } | 152 } |
155 | 153 |
156 /** | 154 /** |
157 * Normalize uploaded files | 155 * Normalize uploaded files |
158 * | 156 * |
159 * Transforms each value into an UploadedFileInterface instance, and ensures | 157 * Transforms each value into an UploadedFileInterface instance, and ensures |
160 * that nested arrays are normalized. | 158 * that nested arrays are normalized. |
161 * | 159 * |
160 * @deprecated since 1.8.0; use \Zend\Diactoros\normalizeUploadedFiles instead. | |
162 * @param array $files | 161 * @param array $files |
163 * @return array | 162 * @return array |
164 * @throws InvalidArgumentException for unrecognized values | 163 * @throws InvalidArgumentException for unrecognized values |
165 */ | 164 */ |
166 public static function normalizeFiles(array $files) | 165 public static function normalizeFiles(array $files) |
167 { | 166 { |
168 $normalized = []; | 167 return normalizeUploadedFiles($files); |
169 foreach ($files as $key => $value) { | |
170 if ($value instanceof UploadedFileInterface) { | |
171 $normalized[$key] = $value; | |
172 continue; | |
173 } | |
174 | |
175 if (is_array($value) && isset($value['tmp_name'])) { | |
176 $normalized[$key] = self::createUploadedFileFromSpec($value); | |
177 continue; | |
178 } | |
179 | |
180 if (is_array($value)) { | |
181 $normalized[$key] = self::normalizeFiles($value); | |
182 continue; | |
183 } | |
184 | |
185 throw new InvalidArgumentException('Invalid value in files specification'); | |
186 } | |
187 return $normalized; | |
188 } | 168 } |
189 | 169 |
190 /** | 170 /** |
191 * Marshal headers from $_SERVER | 171 * Marshal headers from $_SERVER |
192 * | 172 * |
173 * @deprecated since 1.8.0; use Zend\Diactoros\marshalHeadersFromSapi(). | |
193 * @param array $server | 174 * @param array $server |
194 * @return array | 175 * @return array |
195 */ | 176 */ |
196 public static function marshalHeaders(array $server) | 177 public static function marshalHeaders(array $server) |
197 { | 178 { |
198 $headers = []; | 179 return marshalHeadersFromSapi($server); |
199 foreach ($server as $key => $value) { | |
200 // Apache prefixes environment variables with REDIRECT_ | |
201 // if they are added by rewrite rules | |
202 if (strpos($key, 'REDIRECT_') === 0) { | |
203 $key = substr($key, 9); | |
204 | |
205 // We will not overwrite existing variables with the | |
206 // prefixed versions, though | |
207 if (array_key_exists($key, $server)) { | |
208 continue; | |
209 } | |
210 } | |
211 | |
212 if ($value && strpos($key, 'HTTP_') === 0) { | |
213 $name = strtr(strtolower(substr($key, 5)), '_', '-'); | |
214 $headers[$name] = $value; | |
215 continue; | |
216 } | |
217 | |
218 if ($value && strpos($key, 'CONTENT_') === 0) { | |
219 $name = 'content-' . strtolower(substr($key, 8)); | |
220 $headers[$name] = $value; | |
221 continue; | |
222 } | |
223 } | |
224 | |
225 return $headers; | |
226 } | 180 } |
227 | 181 |
228 /** | 182 /** |
229 * Marshal the URI from the $_SERVER array and headers | 183 * Marshal the URI from the $_SERVER array and headers |
230 * | 184 * |
185 * @deprecated since 1.8.0; use Zend\Diactoros\marshalUriFromSapi() instead. | |
231 * @param array $server | 186 * @param array $server |
232 * @param array $headers | 187 * @param array $headers |
233 * @return Uri | 188 * @return Uri |
234 */ | 189 */ |
235 public static function marshalUriFromServer(array $server, array $headers) | 190 public static function marshalUriFromServer(array $server, array $headers) |
236 { | 191 { |
237 $uri = new Uri(''); | 192 return marshalUriFromSapi($server, $headers); |
238 | |
239 // URI scheme | |
240 $scheme = 'http'; | |
241 $https = self::get('HTTPS', $server); | |
242 if (($https && 'off' !== $https) | |
243 || self::getHeader('x-forwarded-proto', $headers, false) === 'https' | |
244 ) { | |
245 $scheme = 'https'; | |
246 } | |
247 $uri = $uri->withScheme($scheme); | |
248 | |
249 // Set the host | |
250 $accumulator = (object) ['host' => '', 'port' => null]; | |
251 self::marshalHostAndPortFromHeaders($accumulator, $server, $headers); | |
252 $host = $accumulator->host; | |
253 $port = $accumulator->port; | |
254 if (! empty($host)) { | |
255 $uri = $uri->withHost($host); | |
256 if (! empty($port)) { | |
257 $uri = $uri->withPort($port); | |
258 } | |
259 } | |
260 | |
261 // URI path | |
262 $path = self::marshalRequestUri($server); | |
263 $path = self::stripQueryString($path); | |
264 | |
265 // URI query | |
266 $query = ''; | |
267 if (isset($server['QUERY_STRING'])) { | |
268 $query = ltrim($server['QUERY_STRING'], '?'); | |
269 } | |
270 | |
271 // URI fragment | |
272 $fragment = ''; | |
273 if (strpos($path, '#') !== false) { | |
274 list($path, $fragment) = explode('#', $path, 2); | |
275 } | |
276 | |
277 return $uri | |
278 ->withPath($path) | |
279 ->withFragment($fragment) | |
280 ->withQuery($query); | |
281 } | 193 } |
282 | 194 |
283 /** | 195 /** |
284 * Marshal the host and port from HTTP headers and/or the PHP environment | 196 * Marshal the host and port from HTTP headers and/or the PHP environment |
285 * | 197 * |
198 * @deprecated since 1.8.0; use Zend\Diactoros\marshalUriFromSapi() instead, | |
199 * and pull the host and port from the Uri instance that function | |
200 * returns. | |
286 * @param stdClass $accumulator | 201 * @param stdClass $accumulator |
287 * @param array $server | 202 * @param array $server |
288 * @param array $headers | 203 * @param array $headers |
289 */ | 204 */ |
290 public static function marshalHostAndPortFromHeaders(stdClass $accumulator, array $server, array $headers) | 205 public static function marshalHostAndPortFromHeaders(stdClass $accumulator, array $server, array $headers) |
291 { | 206 { |
292 if (self::getHeader('host', $headers, false)) { | 207 $uri = marshalUriFromSapi($server, $headers); |
293 self::marshalHostAndPortFromHeader($accumulator, self::getHeader('host', $headers)); | 208 $accumulator->host = $uri->getHost(); |
294 return; | 209 $accumulator->port = $uri->getPort(); |
295 } | |
296 | |
297 if (! isset($server['SERVER_NAME'])) { | |
298 return; | |
299 } | |
300 | |
301 $accumulator->host = $server['SERVER_NAME']; | |
302 if (isset($server['SERVER_PORT'])) { | |
303 $accumulator->port = (int) $server['SERVER_PORT']; | |
304 } | |
305 | |
306 if (! isset($server['SERVER_ADDR']) || ! preg_match('/^\[[0-9a-fA-F\:]+\]$/', $accumulator->host)) { | |
307 return; | |
308 } | |
309 | |
310 // Misinterpreted IPv6-Address | |
311 // Reported for Safari on Windows | |
312 self::marshalIpv6HostAndPort($accumulator, $server); | |
313 } | 210 } |
314 | 211 |
315 /** | 212 /** |
316 * Detect the base URI for the request | 213 * Detect the base URI for the request |
317 * | 214 * |
318 * Looks at a variety of criteria in order to attempt to autodetect a base | 215 * Looks at a variety of criteria in order to attempt to autodetect a base |
319 * URI, including rewrite URIs, proxy URIs, etc. | 216 * URI, including rewrite URIs, proxy URIs, etc. |
320 * | 217 * |
321 * From ZF2's Zend\Http\PhpEnvironment\Request class | 218 * @deprecated since 1.8.0; use Zend\Diactoros\marshalUriFromSapi() instead, |
322 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) | 219 * and pull the path from the Uri instance that function returns. |
323 * @license http://framework.zend.com/license/new-bsd New BSD License | |
324 * | |
325 * @param array $server | 220 * @param array $server |
326 * @return string | 221 * @return string |
327 */ | 222 */ |
328 public static function marshalRequestUri(array $server) | 223 public static function marshalRequestUri(array $server) |
329 { | 224 { |
330 // IIS7 with URL Rewrite: make sure we get the unencoded url | 225 $uri = marshalUriFromSapi($server, []); |
331 // (double slash problem). | 226 return $uri->getPath(); |
332 $iisUrlRewritten = self::get('IIS_WasUrlRewritten', $server); | |
333 $unencodedUrl = self::get('UNENCODED_URL', $server, ''); | |
334 if ('1' == $iisUrlRewritten && ! empty($unencodedUrl)) { | |
335 return $unencodedUrl; | |
336 } | |
337 | |
338 $requestUri = self::get('REQUEST_URI', $server); | |
339 | |
340 // Check this first so IIS will catch. | |
341 $httpXRewriteUrl = self::get('HTTP_X_REWRITE_URL', $server); | |
342 if ($httpXRewriteUrl !== null) { | |
343 $requestUri = $httpXRewriteUrl; | |
344 } | |
345 | |
346 // Check for IIS 7.0 or later with ISAPI_Rewrite | |
347 $httpXOriginalUrl = self::get('HTTP_X_ORIGINAL_URL', $server); | |
348 if ($httpXOriginalUrl !== null) { | |
349 $requestUri = $httpXOriginalUrl; | |
350 } | |
351 | |
352 if ($requestUri !== null) { | |
353 return preg_replace('#^[^/:]+://[^/]+#', '', $requestUri); | |
354 } | |
355 | |
356 $origPathInfo = self::get('ORIG_PATH_INFO', $server); | |
357 if (empty($origPathInfo)) { | |
358 return '/'; | |
359 } | |
360 | |
361 return $origPathInfo; | |
362 } | 227 } |
363 | 228 |
364 /** | 229 /** |
365 * Strip the query string from a path | 230 * Strip the query string from a path |
366 * | 231 * |
232 * @deprecated since 1.8.0; no longer used internally. | |
367 * @param mixed $path | 233 * @param mixed $path |
368 * @return string | 234 * @return string |
369 */ | 235 */ |
370 public static function stripQueryString($path) | 236 public static function stripQueryString($path) |
371 { | 237 { |
372 if (($qpos = strpos($path, '?')) !== false) { | 238 return explode('?', $path, 2)[0]; |
373 return substr($path, 0, $qpos); | |
374 } | |
375 return $path; | |
376 } | |
377 | |
378 /** | |
379 * Marshal the host and port from the request header | |
380 * | |
381 * @param stdClass $accumulator | |
382 * @param string|array $host | |
383 * @return void | |
384 */ | |
385 private static function marshalHostAndPortFromHeader(stdClass $accumulator, $host) | |
386 { | |
387 if (is_array($host)) { | |
388 $host = implode(', ', $host); | |
389 } | |
390 | |
391 $accumulator->host = $host; | |
392 $accumulator->port = null; | |
393 | |
394 // works for regname, IPv4 & IPv6 | |
395 if (preg_match('|\:(\d+)$|', $accumulator->host, $matches)) { | |
396 $accumulator->host = substr($accumulator->host, 0, -1 * (strlen($matches[1]) + 1)); | |
397 $accumulator->port = (int) $matches[1]; | |
398 } | |
399 } | |
400 | |
401 /** | |
402 * Marshal host/port from misinterpreted IPv6 address | |
403 * | |
404 * @param stdClass $accumulator | |
405 * @param array $server | |
406 */ | |
407 private static function marshalIpv6HostAndPort(stdClass $accumulator, array $server) | |
408 { | |
409 $accumulator->host = '[' . $server['SERVER_ADDR'] . ']'; | |
410 $accumulator->port = $accumulator->port ?: 80; | |
411 if ($accumulator->port . ']' === substr($accumulator->host, strrpos($accumulator->host, ':') + 1)) { | |
412 // The last digit of the IPv6-Address has been taken as port | |
413 // Unset the port so the default port can be used | |
414 $accumulator->port = null; | |
415 } | |
416 } | |
417 | |
418 /** | |
419 * Create and return an UploadedFile instance from a $_FILES specification. | |
420 * | |
421 * If the specification represents an array of values, this method will | |
422 * delegate to normalizeNestedFileSpec() and return that return value. | |
423 * | |
424 * @param array $value $_FILES struct | |
425 * @return array|UploadedFileInterface | |
426 */ | |
427 private static function createUploadedFileFromSpec(array $value) | |
428 { | |
429 if (is_array($value['tmp_name'])) { | |
430 return self::normalizeNestedFileSpec($value); | |
431 } | |
432 | |
433 return new UploadedFile( | |
434 $value['tmp_name'], | |
435 $value['size'], | |
436 $value['error'], | |
437 $value['name'], | |
438 $value['type'] | |
439 ); | |
440 } | |
441 | |
442 /** | |
443 * Normalize an array of file specifications. | |
444 * | |
445 * Loops through all nested files and returns a normalized array of | |
446 * UploadedFileInterface instances. | |
447 * | |
448 * @param array $files | |
449 * @return UploadedFileInterface[] | |
450 */ | |
451 private static function normalizeNestedFileSpec(array $files = []) | |
452 { | |
453 $normalizedFiles = []; | |
454 foreach (array_keys($files['tmp_name']) as $key) { | |
455 $spec = [ | |
456 'tmp_name' => $files['tmp_name'][$key], | |
457 'size' => $files['size'][$key], | |
458 'error' => $files['error'][$key], | |
459 'name' => $files['name'][$key], | |
460 'type' => $files['type'][$key], | |
461 ]; | |
462 $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec); | |
463 } | |
464 return $normalizedFiles; | |
465 } | |
466 | |
467 /** | |
468 * Return HTTP protocol version (X.Y) | |
469 * | |
470 * @param array $server | |
471 * @return string | |
472 */ | |
473 private static function marshalProtocolVersion(array $server) | |
474 { | |
475 if (! isset($server['SERVER_PROTOCOL'])) { | |
476 return '1.1'; | |
477 } | |
478 | |
479 if (! preg_match('#^(HTTP/)?(?P<version>[1-9]\d*(?:\.\d)?)$#', $server['SERVER_PROTOCOL'], $matches)) { | |
480 throw new UnexpectedValueException(sprintf( | |
481 'Unrecognized protocol version (%s)', | |
482 $server['SERVER_PROTOCOL'] | |
483 )); | |
484 } | |
485 | |
486 return $matches['version']; | |
487 } | |
488 | |
489 /** | |
490 * Parse a cookie header according to RFC 6265. | |
491 * | |
492 * PHP will replace special characters in cookie names, which results in other cookies not being available due to | |
493 * overwriting. Thus, the server request should take the cookies from the request header instead. | |
494 * | |
495 * @param $cookieHeader | |
496 * @return array | |
497 */ | |
498 private static function parseCookieHeader($cookieHeader) | |
499 { | |
500 preg_match_all('( | |
501 (?:^\\n?[ \t]*|;[ ]) | |
502 (?P<name>[!#$%&\'*+-.0-9A-Z^_`a-z|~]+) | |
503 = | |
504 (?P<DQUOTE>"?) | |
505 (?P<value>[\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]*) | |
506 (?P=DQUOTE) | |
507 (?=\\n?[ \t]*$|;[ ]) | |
508 )x', $cookieHeader, $matches, PREG_SET_ORDER); | |
509 | |
510 $cookies = []; | |
511 | |
512 foreach ($matches as $match) { | |
513 $cookies[$match['name']] = urldecode($match['value']); | |
514 } | |
515 | |
516 return $cookies; | |
517 } | 239 } |
518 } | 240 } |