1<?php
2/**
3 * @see       https://github.com/zendframework/zend-diactoros for the canonical source repository
4 * @copyright Copyright (c) 2015-2017 Zend Technologies USA Inc. (http://www.zend.com)
5 * @license   https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
6 */
7
8namespace Zend\Diactoros;
9
10use InvalidArgumentException;
11use Psr\Http\Message\UploadedFileInterface;
12use stdClass;
13use UnexpectedValueException;
14
15use function array_change_key_case;
16use function array_key_exists;
17use function explode;
18use function implode;
19use function is_array;
20use function is_callable;
21use function strtolower;
22
23use const CASE_LOWER;
24
25/**
26 * Class for marshaling a request object from the current PHP environment.
27 *
28 * Logic largely refactored from the ZF2 Zend\Http\PhpEnvironment\Request class.
29 *
30 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
31 * @license   http://framework.zend.com/license/new-bsd New BSD License
32 */
33abstract class ServerRequestFactory
34{
35    /**
36     * Function to use to get apache request headers; present only to simplify mocking.
37     *
38     * @var callable
39     */
40    private static $apacheRequestHeaders = 'apache_request_headers';
41
42    /**
43     * Create a request from the supplied superglobal values.
44     *
45     * If any argument is not supplied, the corresponding superglobal value will
46     * be used.
47     *
48     * The ServerRequest created is then passed to the fromServer() method in
49     * order to marshal the request URI and headers.
50     *
51     * @see fromServer()
52     * @param array $server $_SERVER superglobal
53     * @param array $query $_GET superglobal
54     * @param array $body $_POST superglobal
55     * @param array $cookies $_COOKIE superglobal
56     * @param array $files $_FILES superglobal
57     * @return ServerRequest
58     * @throws InvalidArgumentException for invalid file values
59     */
60    public static function fromGlobals(
61        array $server = null,
62        array $query = null,
63        array $body = null,
64        array $cookies = null,
65        array $files = null
66    ) {
67        $server = normalizeServer(
68            $server ?: $_SERVER,
69            is_callable(self::$apacheRequestHeaders) ? self::$apacheRequestHeaders : null
70        );
71        $files   = normalizeUploadedFiles($files ?: $_FILES);
72        $headers = marshalHeadersFromSapi($server);
73
74        if (null === $cookies && array_key_exists('cookie', $headers)) {
75            $cookies = parseCookieHeader($headers['cookie']);
76        }
77
78        return new ServerRequest(
79            $server,
80            $files,
81            marshalUriFromSapi($server, $headers),
82            marshalMethodFromSapi($server),
83            'php://input',
84            $headers,
85            $cookies ?: $_COOKIE,
86            $query ?: $_GET,
87            $body ?: $_POST,
88            marshalProtocolVersionFromSapi($server)
89        );
90    }
91
92    /**
93     * Access a value in an array, returning a default value if not found
94     *
95     * @deprecated since 1.8.0; no longer used internally.
96     * @param string $key
97     * @param array $values
98     * @param mixed $default
99     * @return mixed
100     */
101    public static function get($key, array $values, $default = null)
102    {
103        if (array_key_exists($key, $values)) {
104            return $values[$key];
105        }
106
107        return $default;
108    }
109
110    /**
111     * Search for a header value.
112     *
113     * Does a case-insensitive search for a matching header.
114     *
115     * If found, it is returned as a string, using comma concatenation.
116     *
117     * If not, the $default is returned.
118     *
119     * @deprecated since 1.8.0; no longer used internally.
120     * @param string $header
121     * @param array $headers
122     * @param mixed $default
123     * @return string
124     */
125    public static function getHeader($header, array $headers, $default = null)
126    {
127        $header  = strtolower($header);
128        $headers = array_change_key_case($headers, CASE_LOWER);
129        if (array_key_exists($header, $headers)) {
130            $value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header];
131            return $value;
132        }
133
134        return $default;
135    }
136
137    /**
138     * Marshal the $_SERVER array
139     *
140     * Pre-processes and returns the $_SERVER superglobal.
141     *
142     * @deprected since 1.8.0; use Zend\Diactoros\normalizeServer() instead.
143     * @param array $server
144     * @return array
145     */
146    public static function normalizeServer(array $server)
147    {
148        return normalizeServer(
149            $server ?: $_SERVER,
150            is_callable(self::$apacheRequestHeaders) ? self::$apacheRequestHeaders : null
151        );
152    }
153
154    /**
155     * Normalize uploaded files
156     *
157     * Transforms each value into an UploadedFileInterface instance, and ensures
158     * that nested arrays are normalized.
159     *
160     * @deprecated since 1.8.0; use \Zend\Diactoros\normalizeUploadedFiles instead.
161     * @param array $files
162     * @return array
163     * @throws InvalidArgumentException for unrecognized values
164     */
165    public static function normalizeFiles(array $files)
166    {
167        return normalizeUploadedFiles($files);
168    }
169
170    /**
171     * Marshal headers from $_SERVER
172     *
173     * @deprecated since 1.8.0; use Zend\Diactoros\marshalHeadersFromSapi().
174     * @param array $server
175     * @return array
176     */
177    public static function marshalHeaders(array $server)
178    {
179        return marshalHeadersFromSapi($server);
180    }
181
182    /**
183     * Marshal the URI from the $_SERVER array and headers
184     *
185     * @deprecated since 1.8.0; use Zend\Diactoros\marshalUriFromSapi() instead.
186     * @param array $server
187     * @param array $headers
188     * @return Uri
189     */
190    public static function marshalUriFromServer(array $server, array $headers)
191    {
192        return marshalUriFromSapi($server, $headers);
193    }
194
195    /**
196     * Marshal the host and port from HTTP headers and/or the PHP environment
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.
201     * @param stdClass $accumulator
202     * @param array $server
203     * @param array $headers
204     */
205    public static function marshalHostAndPortFromHeaders(stdClass $accumulator, array $server, array $headers)
206    {
207        $uri = marshalUriFromSapi($server, $headers);
208        $accumulator->host = $uri->getHost();
209        $accumulator->port = $uri->getPort();
210    }
211
212    /**
213     * Detect the base URI for the request
214     *
215     * Looks at a variety of criteria in order to attempt to autodetect a base
216     * URI, including rewrite URIs, proxy URIs, etc.
217     *
218     * @deprecated since 1.8.0; use Zend\Diactoros\marshalUriFromSapi() instead,
219     *     and pull the path from the Uri instance that function returns.
220     * @param array $server
221     * @return string
222     */
223    public static function marshalRequestUri(array $server)
224    {
225        $uri = marshalUriFromSapi($server, []);
226        return $uri->getPath();
227    }
228
229    /**
230     * Strip the query string from a path
231     *
232     * @deprecated since 1.8.0; no longer used internally.
233     * @param mixed $path
234     * @return string
235     */
236    public static function stripQueryString($path)
237    {
238        return explode('?', $path, 2)[0];
239    }
240}
241