krz/vox-populi

A Tumblr web client.

clone: git clone https://gitbay.org/krz/vox-populi.git

main: vendor/guzzlehttp/psr7/src/ServerRequest.php · raw

  1<?php
  2
  3namespace GuzzleHttp\Psr7;
  4
  5use InvalidArgumentException;
  6use Psr\Http\Message\ServerRequestInterface;
  7use Psr\Http\Message\UriInterface;
  8use Psr\Http\Message\StreamInterface;
  9use 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 */
 25class 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 = getallheaders();
170        $uri = self::getUriFromGlobals();
171        $body = new CachingStream(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    private static function extractHostAndPortFromAuthority($authority)
184    {
185        $uri = 'http://'.$authority;
186        $parts = parse_url($uri);
187        if (false === $parts) {
188            return [null, null];
189        }
190
191        $host = isset($parts['host']) ? $parts['host'] : null;
192        $port = isset($parts['port']) ? $parts['port'] : null;
193
194        return [$host, $port];
195    }
196
197    /**
198     * Get a Uri populated with values from $_SERVER.
199     *
200     * @return UriInterface
201     */
202    public static function getUriFromGlobals()
203    {
204        $uri = new Uri('');
205
206        $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
207
208        $hasPort = false;
209        if (isset($_SERVER['HTTP_HOST'])) {
210            list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
211            if ($host !== null) {
212                $uri = $uri->withHost($host);
213            }
214
215            if ($port !== null) {
216                $hasPort = true;
217                $uri = $uri->withPort($port);
218            }
219        } elseif (isset($_SERVER['SERVER_NAME'])) {
220            $uri = $uri->withHost($_SERVER['SERVER_NAME']);
221        } elseif (isset($_SERVER['SERVER_ADDR'])) {
222            $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
223        }
224
225        if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
226            $uri = $uri->withPort($_SERVER['SERVER_PORT']);
227        }
228
229        $hasQuery = false;
230        if (isset($_SERVER['REQUEST_URI'])) {
231            $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
232            $uri = $uri->withPath($requestUriParts[0]);
233            if (isset($requestUriParts[1])) {
234                $hasQuery = true;
235                $uri = $uri->withQuery($requestUriParts[1]);
236            }
237        }
238
239        if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
240            $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
241        }
242
243        return $uri;
244    }
245
246
247    /**
248     * {@inheritdoc}
249     */
250    public function getServerParams()
251    {
252        return $this->serverParams;
253    }
254
255    /**
256     * {@inheritdoc}
257     */
258    public function getUploadedFiles()
259    {
260        return $this->uploadedFiles;
261    }
262
263    /**
264     * {@inheritdoc}
265     */
266    public function withUploadedFiles(array $uploadedFiles)
267    {
268        $new = clone $this;
269        $new->uploadedFiles = $uploadedFiles;
270
271        return $new;
272    }
273
274    /**
275     * {@inheritdoc}
276     */
277    public function getCookieParams()
278    {
279        return $this->cookieParams;
280    }
281
282    /**
283     * {@inheritdoc}
284     */
285    public function withCookieParams(array $cookies)
286    {
287        $new = clone $this;
288        $new->cookieParams = $cookies;
289
290        return $new;
291    }
292
293    /**
294     * {@inheritdoc}
295     */
296    public function getQueryParams()
297    {
298        return $this->queryParams;
299    }
300
301    /**
302     * {@inheritdoc}
303     */
304    public function withQueryParams(array $query)
305    {
306        $new = clone $this;
307        $new->queryParams = $query;
308
309        return $new;
310    }
311
312    /**
313     * {@inheritdoc}
314     */
315    public function getParsedBody()
316    {
317        return $this->parsedBody;
318    }
319
320    /**
321     * {@inheritdoc}
322     */
323    public function withParsedBody($data)
324    {
325        $new = clone $this;
326        $new->parsedBody = $data;
327
328        return $new;
329    }
330
331    /**
332     * {@inheritdoc}
333     */
334    public function getAttributes()
335    {
336        return $this->attributes;
337    }
338
339    /**
340     * {@inheritdoc}
341     */
342    public function getAttribute($attribute, $default = null)
343    {
344        if (false === array_key_exists($attribute, $this->attributes)) {
345            return $default;
346        }
347
348        return $this->attributes[$attribute];
349    }
350
351    /**
352     * {@inheritdoc}
353     */
354    public function withAttribute($attribute, $value)
355    {
356        $new = clone $this;
357        $new->attributes[$attribute] = $value;
358
359        return $new;
360    }
361
362    /**
363     * {@inheritdoc}
364     */
365    public function withoutAttribute($attribute)
366    {
367        if (false === array_key_exists($attribute, $this->attributes)) {
368            return $this;
369        }
370
371        $new = clone $this;
372        unset($new->attributes[$attribute]);
373
374        return $new;
375    }
376}