Mercurial > hg > isophonics-drupal-site
comparison vendor/guzzlehttp/psr7/src/functions.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 129ea1e6d783 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 namespace GuzzleHttp\Psr7; | |
3 | |
4 use Psr\Http\Message\MessageInterface; | |
5 use Psr\Http\Message\RequestInterface; | |
6 use Psr\Http\Message\ResponseInterface; | |
7 use Psr\Http\Message\ServerRequestInterface; | |
8 use Psr\Http\Message\StreamInterface; | |
9 use Psr\Http\Message\UriInterface; | |
10 | |
11 /** | |
12 * Returns the string representation of an HTTP message. | |
13 * | |
14 * @param MessageInterface $message Message to convert to a string. | |
15 * | |
16 * @return string | |
17 */ | |
18 function str(MessageInterface $message) | |
19 { | |
20 if ($message instanceof RequestInterface) { | |
21 $msg = trim($message->getMethod() . ' ' | |
22 . $message->getRequestTarget()) | |
23 . ' HTTP/' . $message->getProtocolVersion(); | |
24 if (!$message->hasHeader('host')) { | |
25 $msg .= "\r\nHost: " . $message->getUri()->getHost(); | |
26 } | |
27 } elseif ($message instanceof ResponseInterface) { | |
28 $msg = 'HTTP/' . $message->getProtocolVersion() . ' ' | |
29 . $message->getStatusCode() . ' ' | |
30 . $message->getReasonPhrase(); | |
31 } else { | |
32 throw new \InvalidArgumentException('Unknown message type'); | |
33 } | |
34 | |
35 foreach ($message->getHeaders() as $name => $values) { | |
36 $msg .= "\r\n{$name}: " . implode(', ', $values); | |
37 } | |
38 | |
39 return "{$msg}\r\n\r\n" . $message->getBody(); | |
40 } | |
41 | |
42 /** | |
43 * Returns a UriInterface for the given value. | |
44 * | |
45 * This function accepts a string or {@see Psr\Http\Message\UriInterface} and | |
46 * returns a UriInterface for the given value. If the value is already a | |
47 * `UriInterface`, it is returned as-is. | |
48 * | |
49 * @param string|UriInterface $uri | |
50 * | |
51 * @return UriInterface | |
52 * @throws \InvalidArgumentException | |
53 */ | |
54 function uri_for($uri) | |
55 { | |
56 if ($uri instanceof UriInterface) { | |
57 return $uri; | |
58 } elseif (is_string($uri)) { | |
59 return new Uri($uri); | |
60 } | |
61 | |
62 throw new \InvalidArgumentException('URI must be a string or UriInterface'); | |
63 } | |
64 | |
65 /** | |
66 * Create a new stream based on the input type. | |
67 * | |
68 * Options is an associative array that can contain the following keys: | |
69 * - metadata: Array of custom metadata. | |
70 * - size: Size of the stream. | |
71 * | |
72 * @param resource|string|null|int|float|bool|StreamInterface|callable $resource Entity body data | |
73 * @param array $options Additional options | |
74 * | |
75 * @return Stream | |
76 * @throws \InvalidArgumentException if the $resource arg is not valid. | |
77 */ | |
78 function stream_for($resource = '', array $options = []) | |
79 { | |
80 if (is_scalar($resource)) { | |
81 $stream = fopen('php://temp', 'r+'); | |
82 if ($resource !== '') { | |
83 fwrite($stream, $resource); | |
84 fseek($stream, 0); | |
85 } | |
86 return new Stream($stream, $options); | |
87 } | |
88 | |
89 switch (gettype($resource)) { | |
90 case 'resource': | |
91 return new Stream($resource, $options); | |
92 case 'object': | |
93 if ($resource instanceof StreamInterface) { | |
94 return $resource; | |
95 } elseif ($resource instanceof \Iterator) { | |
96 return new PumpStream(function () use ($resource) { | |
97 if (!$resource->valid()) { | |
98 return false; | |
99 } | |
100 $result = $resource->current(); | |
101 $resource->next(); | |
102 return $result; | |
103 }, $options); | |
104 } elseif (method_exists($resource, '__toString')) { | |
105 return stream_for((string) $resource, $options); | |
106 } | |
107 break; | |
108 case 'NULL': | |
109 return new Stream(fopen('php://temp', 'r+'), $options); | |
110 } | |
111 | |
112 if (is_callable($resource)) { | |
113 return new PumpStream($resource, $options); | |
114 } | |
115 | |
116 throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource)); | |
117 } | |
118 | |
119 /** | |
120 * Parse an array of header values containing ";" separated data into an | |
121 * array of associative arrays representing the header key value pair | |
122 * data of the header. When a parameter does not contain a value, but just | |
123 * contains a key, this function will inject a key with a '' string value. | |
124 * | |
125 * @param string|array $header Header to parse into components. | |
126 * | |
127 * @return array Returns the parsed header values. | |
128 */ | |
129 function parse_header($header) | |
130 { | |
131 static $trimmed = "\"' \n\t\r"; | |
132 $params = $matches = []; | |
133 | |
134 foreach (normalize_header($header) as $val) { | |
135 $part = []; | |
136 foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { | |
137 if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { | |
138 $m = $matches[0]; | |
139 if (isset($m[1])) { | |
140 $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed); | |
141 } else { | |
142 $part[] = trim($m[0], $trimmed); | |
143 } | |
144 } | |
145 } | |
146 if ($part) { | |
147 $params[] = $part; | |
148 } | |
149 } | |
150 | |
151 return $params; | |
152 } | |
153 | |
154 /** | |
155 * Converts an array of header values that may contain comma separated | |
156 * headers into an array of headers with no comma separated values. | |
157 * | |
158 * @param string|array $header Header to normalize. | |
159 * | |
160 * @return array Returns the normalized header field values. | |
161 */ | |
162 function normalize_header($header) | |
163 { | |
164 if (!is_array($header)) { | |
165 return array_map('trim', explode(',', $header)); | |
166 } | |
167 | |
168 $result = []; | |
169 foreach ($header as $value) { | |
170 foreach ((array) $value as $v) { | |
171 if (strpos($v, ',') === false) { | |
172 $result[] = $v; | |
173 continue; | |
174 } | |
175 foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) { | |
176 $result[] = trim($vv); | |
177 } | |
178 } | |
179 } | |
180 | |
181 return $result; | |
182 } | |
183 | |
184 /** | |
185 * Clone and modify a request with the given changes. | |
186 * | |
187 * The changes can be one of: | |
188 * - method: (string) Changes the HTTP method. | |
189 * - set_headers: (array) Sets the given headers. | |
190 * - remove_headers: (array) Remove the given headers. | |
191 * - body: (mixed) Sets the given body. | |
192 * - uri: (UriInterface) Set the URI. | |
193 * - query: (string) Set the query string value of the URI. | |
194 * - version: (string) Set the protocol version. | |
195 * | |
196 * @param RequestInterface $request Request to clone and modify. | |
197 * @param array $changes Changes to apply. | |
198 * | |
199 * @return RequestInterface | |
200 */ | |
201 function modify_request(RequestInterface $request, array $changes) | |
202 { | |
203 if (!$changes) { | |
204 return $request; | |
205 } | |
206 | |
207 $headers = $request->getHeaders(); | |
208 | |
209 if (!isset($changes['uri'])) { | |
210 $uri = $request->getUri(); | |
211 } else { | |
212 // Remove the host header if one is on the URI | |
213 if ($host = $changes['uri']->getHost()) { | |
214 $changes['set_headers']['Host'] = $host; | |
215 | |
216 if ($port = $changes['uri']->getPort()) { | |
217 $standardPorts = ['http' => 80, 'https' => 443]; | |
218 $scheme = $changes['uri']->getScheme(); | |
219 if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) { | |
220 $changes['set_headers']['Host'] .= ':'.$port; | |
221 } | |
222 } | |
223 } | |
224 $uri = $changes['uri']; | |
225 } | |
226 | |
227 if (!empty($changes['remove_headers'])) { | |
228 $headers = _caseless_remove($changes['remove_headers'], $headers); | |
229 } | |
230 | |
231 if (!empty($changes['set_headers'])) { | |
232 $headers = _caseless_remove(array_keys($changes['set_headers']), $headers); | |
233 $headers = $changes['set_headers'] + $headers; | |
234 } | |
235 | |
236 if (isset($changes['query'])) { | |
237 $uri = $uri->withQuery($changes['query']); | |
238 } | |
239 | |
240 if ($request instanceof ServerRequestInterface) { | |
241 return new ServerRequest( | |
242 isset($changes['method']) ? $changes['method'] : $request->getMethod(), | |
243 $uri, | |
244 $headers, | |
245 isset($changes['body']) ? $changes['body'] : $request->getBody(), | |
246 isset($changes['version']) | |
247 ? $changes['version'] | |
248 : $request->getProtocolVersion(), | |
249 $request->getServerParams() | |
250 ); | |
251 } | |
252 | |
253 return new Request( | |
254 isset($changes['method']) ? $changes['method'] : $request->getMethod(), | |
255 $uri, | |
256 $headers, | |
257 isset($changes['body']) ? $changes['body'] : $request->getBody(), | |
258 isset($changes['version']) | |
259 ? $changes['version'] | |
260 : $request->getProtocolVersion() | |
261 ); | |
262 } | |
263 | |
264 /** | |
265 * Attempts to rewind a message body and throws an exception on failure. | |
266 * | |
267 * The body of the message will only be rewound if a call to `tell()` returns a | |
268 * value other than `0`. | |
269 * | |
270 * @param MessageInterface $message Message to rewind | |
271 * | |
272 * @throws \RuntimeException | |
273 */ | |
274 function rewind_body(MessageInterface $message) | |
275 { | |
276 $body = $message->getBody(); | |
277 | |
278 if ($body->tell()) { | |
279 $body->rewind(); | |
280 } | |
281 } | |
282 | |
283 /** | |
284 * Safely opens a PHP stream resource using a filename. | |
285 * | |
286 * When fopen fails, PHP normally raises a warning. This function adds an | |
287 * error handler that checks for errors and throws an exception instead. | |
288 * | |
289 * @param string $filename File to open | |
290 * @param string $mode Mode used to open the file | |
291 * | |
292 * @return resource | |
293 * @throws \RuntimeException if the file cannot be opened | |
294 */ | |
295 function try_fopen($filename, $mode) | |
296 { | |
297 $ex = null; | |
298 set_error_handler(function () use ($filename, $mode, &$ex) { | |
299 $ex = new \RuntimeException(sprintf( | |
300 'Unable to open %s using mode %s: %s', | |
301 $filename, | |
302 $mode, | |
303 func_get_args()[1] | |
304 )); | |
305 }); | |
306 | |
307 $handle = fopen($filename, $mode); | |
308 restore_error_handler(); | |
309 | |
310 if ($ex) { | |
311 /** @var $ex \RuntimeException */ | |
312 throw $ex; | |
313 } | |
314 | |
315 return $handle; | |
316 } | |
317 | |
318 /** | |
319 * Copy the contents of a stream into a string until the given number of | |
320 * bytes have been read. | |
321 * | |
322 * @param StreamInterface $stream Stream to read | |
323 * @param int $maxLen Maximum number of bytes to read. Pass -1 | |
324 * to read the entire stream. | |
325 * @return string | |
326 * @throws \RuntimeException on error. | |
327 */ | |
328 function copy_to_string(StreamInterface $stream, $maxLen = -1) | |
329 { | |
330 $buffer = ''; | |
331 | |
332 if ($maxLen === -1) { | |
333 while (!$stream->eof()) { | |
334 $buf = $stream->read(1048576); | |
335 // Using a loose equality here to match on '' and false. | |
336 if ($buf == null) { | |
337 break; | |
338 } | |
339 $buffer .= $buf; | |
340 } | |
341 return $buffer; | |
342 } | |
343 | |
344 $len = 0; | |
345 while (!$stream->eof() && $len < $maxLen) { | |
346 $buf = $stream->read($maxLen - $len); | |
347 // Using a loose equality here to match on '' and false. | |
348 if ($buf == null) { | |
349 break; | |
350 } | |
351 $buffer .= $buf; | |
352 $len = strlen($buffer); | |
353 } | |
354 | |
355 return $buffer; | |
356 } | |
357 | |
358 /** | |
359 * Copy the contents of a stream into another stream until the given number | |
360 * of bytes have been read. | |
361 * | |
362 * @param StreamInterface $source Stream to read from | |
363 * @param StreamInterface $dest Stream to write to | |
364 * @param int $maxLen Maximum number of bytes to read. Pass -1 | |
365 * to read the entire stream. | |
366 * | |
367 * @throws \RuntimeException on error. | |
368 */ | |
369 function copy_to_stream( | |
370 StreamInterface $source, | |
371 StreamInterface $dest, | |
372 $maxLen = -1 | |
373 ) { | |
374 $bufferSize = 8192; | |
375 | |
376 if ($maxLen === -1) { | |
377 while (!$source->eof()) { | |
378 if (!$dest->write($source->read($bufferSize))) { | |
379 break; | |
380 } | |
381 } | |
382 } else { | |
383 $remaining = $maxLen; | |
384 while ($remaining > 0 && !$source->eof()) { | |
385 $buf = $source->read(min($bufferSize, $remaining)); | |
386 $len = strlen($buf); | |
387 if (!$len) { | |
388 break; | |
389 } | |
390 $remaining -= $len; | |
391 $dest->write($buf); | |
392 } | |
393 } | |
394 } | |
395 | |
396 /** | |
397 * Calculate a hash of a Stream | |
398 * | |
399 * @param StreamInterface $stream Stream to calculate the hash for | |
400 * @param string $algo Hash algorithm (e.g. md5, crc32, etc) | |
401 * @param bool $rawOutput Whether or not to use raw output | |
402 * | |
403 * @return string Returns the hash of the stream | |
404 * @throws \RuntimeException on error. | |
405 */ | |
406 function hash( | |
407 StreamInterface $stream, | |
408 $algo, | |
409 $rawOutput = false | |
410 ) { | |
411 $pos = $stream->tell(); | |
412 | |
413 if ($pos > 0) { | |
414 $stream->rewind(); | |
415 } | |
416 | |
417 $ctx = hash_init($algo); | |
418 while (!$stream->eof()) { | |
419 hash_update($ctx, $stream->read(1048576)); | |
420 } | |
421 | |
422 $out = hash_final($ctx, (bool) $rawOutput); | |
423 $stream->seek($pos); | |
424 | |
425 return $out; | |
426 } | |
427 | |
428 /** | |
429 * Read a line from the stream up to the maximum allowed buffer length | |
430 * | |
431 * @param StreamInterface $stream Stream to read from | |
432 * @param int $maxLength Maximum buffer length | |
433 * | |
434 * @return string|bool | |
435 */ | |
436 function readline(StreamInterface $stream, $maxLength = null) | |
437 { | |
438 $buffer = ''; | |
439 $size = 0; | |
440 | |
441 while (!$stream->eof()) { | |
442 // Using a loose equality here to match on '' and false. | |
443 if (null == ($byte = $stream->read(1))) { | |
444 return $buffer; | |
445 } | |
446 $buffer .= $byte; | |
447 // Break when a new line is found or the max length - 1 is reached | |
448 if ($byte === "\n" || ++$size === $maxLength - 1) { | |
449 break; | |
450 } | |
451 } | |
452 | |
453 return $buffer; | |
454 } | |
455 | |
456 /** | |
457 * Parses a request message string into a request object. | |
458 * | |
459 * @param string $message Request message string. | |
460 * | |
461 * @return Request | |
462 */ | |
463 function parse_request($message) | |
464 { | |
465 $data = _parse_message($message); | |
466 $matches = []; | |
467 if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) { | |
468 throw new \InvalidArgumentException('Invalid request string'); | |
469 } | |
470 $parts = explode(' ', $data['start-line'], 3); | |
471 $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1'; | |
472 | |
473 $request = new Request( | |
474 $parts[0], | |
475 $matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1], | |
476 $data['headers'], | |
477 $data['body'], | |
478 $version | |
479 ); | |
480 | |
481 return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]); | |
482 } | |
483 | |
484 /** | |
485 * Parses a response message string into a response object. | |
486 * | |
487 * @param string $message Response message string. | |
488 * | |
489 * @return Response | |
490 */ | |
491 function parse_response($message) | |
492 { | |
493 $data = _parse_message($message); | |
494 // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space | |
495 // between status-code and reason-phrase is required. But browsers accept | |
496 // responses without space and reason as well. | |
497 if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) { | |
498 throw new \InvalidArgumentException('Invalid response string'); | |
499 } | |
500 $parts = explode(' ', $data['start-line'], 3); | |
501 | |
502 return new Response( | |
503 $parts[1], | |
504 $data['headers'], | |
505 $data['body'], | |
506 explode('/', $parts[0])[1], | |
507 isset($parts[2]) ? $parts[2] : null | |
508 ); | |
509 } | |
510 | |
511 /** | |
512 * Parse a query string into an associative array. | |
513 * | |
514 * If multiple values are found for the same key, the value of that key | |
515 * value pair will become an array. This function does not parse nested | |
516 * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will | |
517 * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']). | |
518 * | |
519 * @param string $str Query string to parse | |
520 * @param bool|string $urlEncoding How the query string is encoded | |
521 * | |
522 * @return array | |
523 */ | |
524 function parse_query($str, $urlEncoding = true) | |
525 { | |
526 $result = []; | |
527 | |
528 if ($str === '') { | |
529 return $result; | |
530 } | |
531 | |
532 if ($urlEncoding === true) { | |
533 $decoder = function ($value) { | |
534 return rawurldecode(str_replace('+', ' ', $value)); | |
535 }; | |
536 } elseif ($urlEncoding == PHP_QUERY_RFC3986) { | |
537 $decoder = 'rawurldecode'; | |
538 } elseif ($urlEncoding == PHP_QUERY_RFC1738) { | |
539 $decoder = 'urldecode'; | |
540 } else { | |
541 $decoder = function ($str) { return $str; }; | |
542 } | |
543 | |
544 foreach (explode('&', $str) as $kvp) { | |
545 $parts = explode('=', $kvp, 2); | |
546 $key = $decoder($parts[0]); | |
547 $value = isset($parts[1]) ? $decoder($parts[1]) : null; | |
548 if (!isset($result[$key])) { | |
549 $result[$key] = $value; | |
550 } else { | |
551 if (!is_array($result[$key])) { | |
552 $result[$key] = [$result[$key]]; | |
553 } | |
554 $result[$key][] = $value; | |
555 } | |
556 } | |
557 | |
558 return $result; | |
559 } | |
560 | |
561 /** | |
562 * Build a query string from an array of key value pairs. | |
563 * | |
564 * This function can use the return value of parse_query() to build a query | |
565 * string. This function does not modify the provided keys when an array is | |
566 * encountered (like http_build_query would). | |
567 * | |
568 * @param array $params Query string parameters. | |
569 * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986 | |
570 * to encode using RFC3986, or PHP_QUERY_RFC1738 | |
571 * to encode using RFC1738. | |
572 * @return string | |
573 */ | |
574 function build_query(array $params, $encoding = PHP_QUERY_RFC3986) | |
575 { | |
576 if (!$params) { | |
577 return ''; | |
578 } | |
579 | |
580 if ($encoding === false) { | |
581 $encoder = function ($str) { return $str; }; | |
582 } elseif ($encoding === PHP_QUERY_RFC3986) { | |
583 $encoder = 'rawurlencode'; | |
584 } elseif ($encoding === PHP_QUERY_RFC1738) { | |
585 $encoder = 'urlencode'; | |
586 } else { | |
587 throw new \InvalidArgumentException('Invalid type'); | |
588 } | |
589 | |
590 $qs = ''; | |
591 foreach ($params as $k => $v) { | |
592 $k = $encoder($k); | |
593 if (!is_array($v)) { | |
594 $qs .= $k; | |
595 if ($v !== null) { | |
596 $qs .= '=' . $encoder($v); | |
597 } | |
598 $qs .= '&'; | |
599 } else { | |
600 foreach ($v as $vv) { | |
601 $qs .= $k; | |
602 if ($vv !== null) { | |
603 $qs .= '=' . $encoder($vv); | |
604 } | |
605 $qs .= '&'; | |
606 } | |
607 } | |
608 } | |
609 | |
610 return $qs ? (string) substr($qs, 0, -1) : ''; | |
611 } | |
612 | |
613 /** | |
614 * Determines the mimetype of a file by looking at its extension. | |
615 * | |
616 * @param $filename | |
617 * | |
618 * @return null|string | |
619 */ | |
620 function mimetype_from_filename($filename) | |
621 { | |
622 return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION)); | |
623 } | |
624 | |
625 /** | |
626 * Maps a file extensions to a mimetype. | |
627 * | |
628 * @param $extension string The file extension. | |
629 * | |
630 * @return string|null | |
631 * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types | |
632 */ | |
633 function mimetype_from_extension($extension) | |
634 { | |
635 static $mimetypes = [ | |
636 '7z' => 'application/x-7z-compressed', | |
637 'aac' => 'audio/x-aac', | |
638 'ai' => 'application/postscript', | |
639 'aif' => 'audio/x-aiff', | |
640 'asc' => 'text/plain', | |
641 'asf' => 'video/x-ms-asf', | |
642 'atom' => 'application/atom+xml', | |
643 'avi' => 'video/x-msvideo', | |
644 'bmp' => 'image/bmp', | |
645 'bz2' => 'application/x-bzip2', | |
646 'cer' => 'application/pkix-cert', | |
647 'crl' => 'application/pkix-crl', | |
648 'crt' => 'application/x-x509-ca-cert', | |
649 'css' => 'text/css', | |
650 'csv' => 'text/csv', | |
651 'cu' => 'application/cu-seeme', | |
652 'deb' => 'application/x-debian-package', | |
653 'doc' => 'application/msword', | |
654 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', | |
655 'dvi' => 'application/x-dvi', | |
656 'eot' => 'application/vnd.ms-fontobject', | |
657 'eps' => 'application/postscript', | |
658 'epub' => 'application/epub+zip', | |
659 'etx' => 'text/x-setext', | |
660 'flac' => 'audio/flac', | |
661 'flv' => 'video/x-flv', | |
662 'gif' => 'image/gif', | |
663 'gz' => 'application/gzip', | |
664 'htm' => 'text/html', | |
665 'html' => 'text/html', | |
666 'ico' => 'image/x-icon', | |
667 'ics' => 'text/calendar', | |
668 'ini' => 'text/plain', | |
669 'iso' => 'application/x-iso9660-image', | |
670 'jar' => 'application/java-archive', | |
671 'jpe' => 'image/jpeg', | |
672 'jpeg' => 'image/jpeg', | |
673 'jpg' => 'image/jpeg', | |
674 'js' => 'text/javascript', | |
675 'json' => 'application/json', | |
676 'latex' => 'application/x-latex', | |
677 'log' => 'text/plain', | |
678 'm4a' => 'audio/mp4', | |
679 'm4v' => 'video/mp4', | |
680 'mid' => 'audio/midi', | |
681 'midi' => 'audio/midi', | |
682 'mov' => 'video/quicktime', | |
683 'mp3' => 'audio/mpeg', | |
684 'mp4' => 'video/mp4', | |
685 'mp4a' => 'audio/mp4', | |
686 'mp4v' => 'video/mp4', | |
687 'mpe' => 'video/mpeg', | |
688 'mpeg' => 'video/mpeg', | |
689 'mpg' => 'video/mpeg', | |
690 'mpg4' => 'video/mp4', | |
691 'oga' => 'audio/ogg', | |
692 'ogg' => 'audio/ogg', | |
693 'ogv' => 'video/ogg', | |
694 'ogx' => 'application/ogg', | |
695 'pbm' => 'image/x-portable-bitmap', | |
696 'pdf' => 'application/pdf', | |
697 'pgm' => 'image/x-portable-graymap', | |
698 'png' => 'image/png', | |
699 'pnm' => 'image/x-portable-anymap', | |
700 'ppm' => 'image/x-portable-pixmap', | |
701 'ppt' => 'application/vnd.ms-powerpoint', | |
702 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', | |
703 'ps' => 'application/postscript', | |
704 'qt' => 'video/quicktime', | |
705 'rar' => 'application/x-rar-compressed', | |
706 'ras' => 'image/x-cmu-raster', | |
707 'rss' => 'application/rss+xml', | |
708 'rtf' => 'application/rtf', | |
709 'sgm' => 'text/sgml', | |
710 'sgml' => 'text/sgml', | |
711 'svg' => 'image/svg+xml', | |
712 'swf' => 'application/x-shockwave-flash', | |
713 'tar' => 'application/x-tar', | |
714 'tif' => 'image/tiff', | |
715 'tiff' => 'image/tiff', | |
716 'torrent' => 'application/x-bittorrent', | |
717 'ttf' => 'application/x-font-ttf', | |
718 'txt' => 'text/plain', | |
719 'wav' => 'audio/x-wav', | |
720 'webm' => 'video/webm', | |
721 'wma' => 'audio/x-ms-wma', | |
722 'wmv' => 'video/x-ms-wmv', | |
723 'woff' => 'application/x-font-woff', | |
724 'wsdl' => 'application/wsdl+xml', | |
725 'xbm' => 'image/x-xbitmap', | |
726 'xls' => 'application/vnd.ms-excel', | |
727 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', | |
728 'xml' => 'application/xml', | |
729 'xpm' => 'image/x-xpixmap', | |
730 'xwd' => 'image/x-xwindowdump', | |
731 'yaml' => 'text/yaml', | |
732 'yml' => 'text/yaml', | |
733 'zip' => 'application/zip', | |
734 ]; | |
735 | |
736 $extension = strtolower($extension); | |
737 | |
738 return isset($mimetypes[$extension]) | |
739 ? $mimetypes[$extension] | |
740 : null; | |
741 } | |
742 | |
743 /** | |
744 * Parses an HTTP message into an associative array. | |
745 * | |
746 * The array contains the "start-line" key containing the start line of | |
747 * the message, "headers" key containing an associative array of header | |
748 * array values, and a "body" key containing the body of the message. | |
749 * | |
750 * @param string $message HTTP request or response to parse. | |
751 * | |
752 * @return array | |
753 * @internal | |
754 */ | |
755 function _parse_message($message) | |
756 { | |
757 if (!$message) { | |
758 throw new \InvalidArgumentException('Invalid message'); | |
759 } | |
760 | |
761 // Iterate over each line in the message, accounting for line endings | |
762 $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); | |
763 $result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => '']; | |
764 array_shift($lines); | |
765 | |
766 for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { | |
767 $line = $lines[$i]; | |
768 // If two line breaks were encountered, then this is the end of body | |
769 if (empty($line)) { | |
770 if ($i < $totalLines - 1) { | |
771 $result['body'] = implode('', array_slice($lines, $i + 2)); | |
772 } | |
773 break; | |
774 } | |
775 if (strpos($line, ':')) { | |
776 $parts = explode(':', $line, 2); | |
777 $key = trim($parts[0]); | |
778 $value = isset($parts[1]) ? trim($parts[1]) : ''; | |
779 $result['headers'][$key][] = $value; | |
780 } | |
781 } | |
782 | |
783 return $result; | |
784 } | |
785 | |
786 /** | |
787 * Constructs a URI for an HTTP request message. | |
788 * | |
789 * @param string $path Path from the start-line | |
790 * @param array $headers Array of headers (each value an array). | |
791 * | |
792 * @return string | |
793 * @internal | |
794 */ | |
795 function _parse_request_uri($path, array $headers) | |
796 { | |
797 $hostKey = array_filter(array_keys($headers), function ($k) { | |
798 return strtolower($k) === 'host'; | |
799 }); | |
800 | |
801 // If no host is found, then a full URI cannot be constructed. | |
802 if (!$hostKey) { | |
803 return $path; | |
804 } | |
805 | |
806 $host = $headers[reset($hostKey)][0]; | |
807 $scheme = substr($host, -4) === ':443' ? 'https' : 'http'; | |
808 | |
809 return $scheme . '://' . $host . '/' . ltrim($path, '/'); | |
810 } | |
811 | |
812 /** @internal */ | |
813 function _caseless_remove($keys, array $data) | |
814 { | |
815 $result = []; | |
816 | |
817 foreach ($keys as &$key) { | |
818 $key = strtolower($key); | |
819 } | |
820 | |
821 foreach ($data as $k => $v) { | |
822 if (!in_array(strtolower($k), $keys)) { | |
823 $result[$k] = $v; | |
824 } | |
825 } | |
826 | |
827 return $result; | |
828 } |