3 namespace GuzzleHttp\Psr7;
5 use InvalidArgumentException;
6 use Psr\Http\Message\ServerRequestInterface;
7 use Psr\Http\Message\UriInterface;
8 use Psr\Http\Message\StreamInterface;
9 use Psr\Http\Message\UploadedFileInterface;
12 * Server-side HTTP request
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.
18 * "Attributes" are discovered via decomposing the request (and usually
19 * specifically the URI path), and typically will be injected by the application.
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.
25 class ServerRequest extends Request implements ServerRequestInterface
30 private $attributes = [];
35 private $cookieParams = [];
38 * @var null|array|object
45 private $queryParams = [];
50 private $serverParams;
55 private $uploadedFiles = [];
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
65 public function __construct(
71 array $serverParams = []
73 $this->serverParams = $serverParams;
75 parent::__construct($method, $uri, $headers, $body, $version);
79 * Return an UploadedFile instance array.
81 * @param array $files A array which respect $_FILES structure
82 * @throws InvalidArgumentException for unrecognized values
85 public static function normalizeFiles(array $files)
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);
98 throw new InvalidArgumentException('Invalid value in files specification');
106 * Create and return an UploadedFile instance from a $_FILES specification.
108 * If the specification represents an array of values, this method will
109 * delegate to normalizeNestedFileSpec() and return that return value.
111 * @param array $value $_FILES struct
112 * @return array|UploadedFileInterface
114 private static function createUploadedFileFromSpec(array $value)
116 if (is_array($value['tmp_name'])) {
117 return self::normalizeNestedFileSpec($value);
120 return new UploadedFile(
122 (int) $value['size'],
123 (int) $value['error'],
130 * Normalize an array of file specifications.
132 * Loops through all nested files and returns a normalized array of
133 * UploadedFileInterface instances.
135 * @param array $files
136 * @return UploadedFileInterface[]
138 private static function normalizeNestedFileSpec(array $files = [])
140 $normalizedFiles = [];
142 foreach (array_keys($files['tmp_name']) as $key) {
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],
150 $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
153 return $normalizedFiles;
157 * Return a ServerRequest populated with superglobals:
164 * @return ServerRequestInterface
166 public static function fromGlobals()
168 $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
169 $headers = function_exists('getallheaders') ? getallheaders() : [];
170 $uri = self::getUriFromGlobals();
171 $body = new LazyOpenStream('php://input', 'r+');
172 $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
174 $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
176 return $serverRequest
177 ->withCookieParams($_COOKIE)
178 ->withQueryParams($_GET)
179 ->withParsedBody($_POST)
180 ->withUploadedFiles(self::normalizeFiles($_FILES));
184 * Get a Uri populated with values from $_SERVER.
186 * @return UriInterface
188 public static function getUriFromGlobals() {
191 $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
194 if (isset($_SERVER['HTTP_HOST'])) {
195 $hostHeaderParts = explode(':', $_SERVER['HTTP_HOST']);
196 $uri = $uri->withHost($hostHeaderParts[0]);
197 if (isset($hostHeaderParts[1])) {
199 $uri = $uri->withPort($hostHeaderParts[1]);
201 } elseif (isset($_SERVER['SERVER_NAME'])) {
202 $uri = $uri->withHost($_SERVER['SERVER_NAME']);
203 } elseif (isset($_SERVER['SERVER_ADDR'])) {
204 $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
207 if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
208 $uri = $uri->withPort($_SERVER['SERVER_PORT']);
212 if (isset($_SERVER['REQUEST_URI'])) {
213 $requestUriParts = explode('?', $_SERVER['REQUEST_URI']);
214 $uri = $uri->withPath($requestUriParts[0]);
215 if (isset($requestUriParts[1])) {
217 $uri = $uri->withQuery($requestUriParts[1]);
221 if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
222 $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
232 public function getServerParams()
234 return $this->serverParams;
240 public function getUploadedFiles()
242 return $this->uploadedFiles;
248 public function withUploadedFiles(array $uploadedFiles)
251 $new->uploadedFiles = $uploadedFiles;
259 public function getCookieParams()
261 return $this->cookieParams;
267 public function withCookieParams(array $cookies)
270 $new->cookieParams = $cookies;
278 public function getQueryParams()
280 return $this->queryParams;
286 public function withQueryParams(array $query)
289 $new->queryParams = $query;
297 public function getParsedBody()
299 return $this->parsedBody;
305 public function withParsedBody($data)
308 $new->parsedBody = $data;
316 public function getAttributes()
318 return $this->attributes;
324 public function getAttribute($attribute, $default = null)
326 if (false === array_key_exists($attribute, $this->attributes)) {
330 return $this->attributes[$attribute];
336 public function withAttribute($attribute, $value)
339 $new->attributes[$attribute] = $value;
347 public function withoutAttribute($attribute)
349 if (false === array_key_exists($attribute, $this->attributes)) {
354 unset($new->attributes[$attribute]);