decaafb835b55cb5abe83374f73919fee1e9d15f
[yaffs-website] / vendor / zendframework / zend-diactoros / src / functions / marshal_uri_from_sapi.php
1 <?php
2 /**
3  * @see       https://github.com/zendframework/zend-diactoros for the canonical source repository
4  * @copyright Copyright (c) 2018 Zend Technologies USA Inc. (https://www.zend.com)
5  * @license   https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
6  */
7
8 namespace Zend\Diactoros;
9
10 use function array_change_key_case;
11 use function array_key_exists;
12 use function explode;
13 use function implode;
14 use function is_array;
15 use function ltrim;
16 use function preg_match;
17 use function preg_replace;
18 use function strlen;
19 use function strpos;
20 use function strtolower;
21 use function substr;
22
23 /**
24  * Marshal a Uri instance based on the values presnt in the $_SERVER array and headers.
25  *
26  * @param array $server SAPI parameters
27  * @param array $headers HTTP request headers
28  * @return Uri
29  */
30 function marshalUriFromSapi(array $server, array $headers)
31 {
32     /**
33      * Retrieve a header value from an array of headers using a case-insensitive lookup.
34      *
35      * @param string $name
36      * @param array $headers Key/value header pairs
37      * @param mixed $default Default value to return if header not found
38      * @return mixed
39      */
40     $getHeaderFromArray = function ($name, array $headers, $default = null) {
41         $header  = strtolower($name);
42         $headers = array_change_key_case($headers, CASE_LOWER);
43         if (array_key_exists($header, $headers)) {
44             $value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header];
45             return $value;
46         }
47
48         return $default;
49     };
50
51     /**
52      * Marshal the host and port from HTTP headers and/or the PHP environment.
53      *
54      * @param array $headers
55      * @param array $server
56      * @return array Array of two items, host and port, in that order (can be
57      *     passed to a list() operation).
58      */
59     $marshalHostAndPort = function (array $headers, array $server) use ($getHeaderFromArray) {
60         /**
61         * @param string|array $host
62         * @return array Array of two items, host and port, in that order (can be
63         *     passed to a list() operation).
64         */
65         $marshalHostAndPortFromHeader = function ($host) {
66             if (is_array($host)) {
67                 $host = implode(', ', $host);
68             }
69
70             $port = null;
71
72             // works for regname, IPv4 & IPv6
73             if (preg_match('|\:(\d+)$|', $host, $matches)) {
74                 $host = substr($host, 0, -1 * (strlen($matches[1]) + 1));
75                 $port = (int) $matches[1];
76             }
77
78             return [$host, $port];
79         };
80
81         /**
82         * @param array $server
83         * @param string $host
84         * @param null|int $port
85         * @return array Array of two items, host and port, in that order (can be
86         *     passed to a list() operation).
87         */
88         $marshalIpv6HostAndPort = function (array $server, $host, $port) {
89             $host = '[' . $server['SERVER_ADDR'] . ']';
90             $port = $port ?: 80;
91             if ($port . ']' === substr($host, strrpos($host, ':') + 1)) {
92                 // The last digit of the IPv6-Address has been taken as port
93                 // Unset the port so the default port can be used
94                 $port = null;
95             }
96             return [$host, $port];
97         };
98
99         static $defaults = ['', null];
100
101         if ($getHeaderFromArray('host', $headers, false)) {
102             return $marshalHostAndPortFromHeader($getHeaderFromArray('host', $headers));
103         }
104
105         if (! isset($server['SERVER_NAME'])) {
106             return $defaults;
107         }
108
109         $host = $server['SERVER_NAME'];
110         $port = isset($server['SERVER_PORT']) ? (int) $server['SERVER_PORT'] : null;
111
112         if (! isset($server['SERVER_ADDR'])
113             || ! preg_match('/^\[[0-9a-fA-F\:]+\]$/', $host)
114         ) {
115             return [$host, $port];
116         }
117
118         // Misinterpreted IPv6-Address
119         // Reported for Safari on Windows
120         return $marshalIpv6HostAndPort($server, $host, $port);
121     };
122
123     /**
124      * Detect the path for the request
125      *
126      * Looks at a variety of criteria in order to attempt to autodetect the base
127      * request path, including:
128      *
129      * - IIS7 UrlRewrite environment
130      * - REQUEST_URI
131      * - ORIG_PATH_INFO
132      *
133      * From ZF2's Zend\Http\PhpEnvironment\Request class
134      * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
135      * @license   http://framework.zend.com/license/new-bsd New BSD License
136      *
137      * @param array $server SAPI environment array (typically `$_SERVER`)
138      * @return string Discovered path
139      */
140     $marshalRequestPath = function (array $server) {
141         // IIS7 with URL Rewrite: make sure we get the unencoded url
142         // (double slash problem).
143         $iisUrlRewritten = array_key_exists('IIS_WasUrlRewritten', $server) ? $server['IIS_WasUrlRewritten'] : null;
144         $unencodedUrl    = array_key_exists('UNENCODED_URL', $server) ? $server['UNENCODED_URL'] : '';
145         if ('1' === $iisUrlRewritten && ! empty($unencodedUrl)) {
146             return $unencodedUrl;
147         }
148
149         $requestUri = array_key_exists('REQUEST_URI', $server) ? $server['REQUEST_URI'] : null;
150
151         if ($requestUri !== null) {
152             return preg_replace('#^[^/:]+://[^/]+#', '', $requestUri);
153         }
154
155         $origPathInfo = array_key_exists('ORIG_PATH_INFO', $server) ? $server['ORIG_PATH_INFO'] : null;
156         if (empty($origPathInfo)) {
157             return '/';
158         }
159
160         return $origPathInfo;
161     };
162
163     $uri = new Uri('');
164
165     // URI scheme
166     $scheme = 'http';
167     if (array_key_exists('HTTPS', $server)) {
168         $https = $server['HTTPS'];
169     } elseif (array_key_exists('https', $server)) {
170         $https = $server['https'];
171     } else {
172         $https = false;
173     }
174     if (($https && 'off' !== strtolower($https))
175         || strtolower($getHeaderFromArray('x-forwarded-proto', $headers, false)) === 'https'
176     ) {
177         $scheme = 'https';
178     }
179     $uri = $uri->withScheme($scheme);
180
181     // Set the host
182     list($host, $port) = $marshalHostAndPort($headers, $server);
183     if (! empty($host)) {
184         $uri = $uri->withHost($host);
185         if (! empty($port)) {
186             $uri = $uri->withPort($port);
187         }
188     }
189
190     // URI path
191     $path = $marshalRequestPath($server);
192
193     // Strip query string
194     $path = explode('?', $path, 2)[0];
195
196     // URI query
197     $query = '';
198     if (isset($server['QUERY_STRING'])) {
199         $query = ltrim($server['QUERY_STRING'], '?');
200     }
201
202     // URI fragment
203     $fragment = '';
204     if (strpos($path, '#') !== false) {
205         list($path, $fragment) = explode('#', $path, 2);
206     }
207
208     return $uri
209         ->withPath($path)
210         ->withFragment($fragment)
211         ->withQuery($query);
212 }