8523d59e1a5ea8dd5267d4d6da1cb7d34f60719b
[yaffs-website] / src / ServerRequest.php
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
8 namespace Zend\Diactoros;
9
10 use InvalidArgumentException;
11 use Psr\Http\Message\ServerRequestInterface;
12 use Psr\Http\Message\StreamInterface;
13 use Psr\Http\Message\UploadedFileInterface;
14 use Psr\Http\Message\UriInterface;
15
16 use function array_key_exists;
17 use function is_array;
18
19 /**
20  * Server-side HTTP request
21  *
22  * Extends the Request definition to add methods for accessing incoming data,
23  * specifically server parameters, cookies, matched path parameters, query
24  * string arguments, body parameters, and upload file information.
25  *
26  * "Attributes" are discovered via decomposing the request (and usually
27  * specifically the URI path), and typically will be injected by the application.
28  *
29  * Requests are considered immutable; all methods that might change state are
30  * implemented such that they retain the internal state of the current
31  * message and return a new instance that contains the changed state.
32  */
33 class ServerRequest implements ServerRequestInterface
34 {
35     use RequestTrait;
36
37     /**
38      * @var array
39      */
40     private $attributes = [];
41
42     /**
43      * @var array
44      */
45     private $cookieParams = [];
46
47     /**
48      * @var null|array|object
49      */
50     private $parsedBody;
51
52     /**
53      * @var array
54      */
55     private $queryParams = [];
56
57     /**
58      * @var array
59      */
60     private $serverParams;
61
62     /**
63      * @var array
64      */
65     private $uploadedFiles;
66
67     /**
68      * @param array $serverParams Server parameters, typically from $_SERVER
69      * @param array $uploadedFiles Upload file information, a tree of UploadedFiles
70      * @param null|string|UriInterface $uri URI for the request, if any.
71      * @param null|string $method HTTP method for the request, if any.
72      * @param string|resource|StreamInterface $body Message body, if any.
73      * @param array $headers Headers for the message, if any.
74      * @param array $cookies Cookies for the message, if any.
75      * @param array $queryParams Query params for the message, if any.
76      * @param null|array|object $parsedBody The deserialized body parameters, if any.
77      * @param string $protocol HTTP protocol version.
78      * @throws InvalidArgumentException for any invalid value.
79      */
80     public function __construct(
81         array $serverParams = [],
82         array $uploadedFiles = [],
83         $uri = null,
84         $method = null,
85         $body = 'php://input',
86         array $headers = [],
87         array $cookies = [],
88         array $queryParams = [],
89         $parsedBody = null,
90         $protocol = '1.1'
91     ) {
92         $this->validateUploadedFiles($uploadedFiles);
93
94         if ($body === 'php://input') {
95             $body = new PhpInputStream();
96         }
97
98         $this->initialize($uri, $method, $body, $headers);
99         $this->serverParams  = $serverParams;
100         $this->uploadedFiles = $uploadedFiles;
101         $this->cookieParams  = $cookies;
102         $this->queryParams   = $queryParams;
103         $this->parsedBody    = $parsedBody;
104         $this->protocol      = $protocol;
105     }
106
107     /**
108      * {@inheritdoc}
109      */
110     public function getServerParams()
111     {
112         return $this->serverParams;
113     }
114
115     /**
116      * {@inheritdoc}
117      */
118     public function getUploadedFiles()
119     {
120         return $this->uploadedFiles;
121     }
122
123     /**
124      * {@inheritdoc}
125      */
126     public function withUploadedFiles(array $uploadedFiles)
127     {
128         $this->validateUploadedFiles($uploadedFiles);
129         $new = clone $this;
130         $new->uploadedFiles = $uploadedFiles;
131         return $new;
132     }
133
134     /**
135      * {@inheritdoc}
136      */
137     public function getCookieParams()
138     {
139         return $this->cookieParams;
140     }
141
142     /**
143      * {@inheritdoc}
144      */
145     public function withCookieParams(array $cookies)
146     {
147         $new = clone $this;
148         $new->cookieParams = $cookies;
149         return $new;
150     }
151
152     /**
153      * {@inheritdoc}
154      */
155     public function getQueryParams()
156     {
157         return $this->queryParams;
158     }
159
160     /**
161      * {@inheritdoc}
162      */
163     public function withQueryParams(array $query)
164     {
165         $new = clone $this;
166         $new->queryParams = $query;
167         return $new;
168     }
169
170     /**
171      * {@inheritdoc}
172      */
173     public function getParsedBody()
174     {
175         return $this->parsedBody;
176     }
177
178     /**
179      * {@inheritdoc}
180      */
181     public function withParsedBody($data)
182     {
183         if (! is_array($data) && ! is_object($data) && null !== $data) {
184             throw new InvalidArgumentException(sprintf(
185                 '%s expects a null, array, or object argument; received %s',
186                 __METHOD__,
187                 gettype($data)
188             ));
189         }
190
191         $new = clone $this;
192         $new->parsedBody = $data;
193         return $new;
194     }
195
196     /**
197      * {@inheritdoc}
198      */
199     public function getAttributes()
200     {
201         return $this->attributes;
202     }
203
204     /**
205      * {@inheritdoc}
206      */
207     public function getAttribute($attribute, $default = null)
208     {
209         if (! array_key_exists($attribute, $this->attributes)) {
210             return $default;
211         }
212
213         return $this->attributes[$attribute];
214     }
215
216     /**
217      * {@inheritdoc}
218      */
219     public function withAttribute($attribute, $value)
220     {
221         $new = clone $this;
222         $new->attributes[$attribute] = $value;
223         return $new;
224     }
225
226     /**
227      * {@inheritdoc}
228      */
229     public function withoutAttribute($attribute)
230     {
231         $new = clone $this;
232         unset($new->attributes[$attribute]);
233         return $new;
234     }
235
236     /**
237      * Proxy to receive the request method.
238      *
239      * This overrides the parent functionality to ensure the method is never
240      * empty; if no method is present, it returns 'GET'.
241      *
242      * @return string
243      */
244     public function getMethod()
245     {
246         if (empty($this->method)) {
247             return 'GET';
248         }
249         return $this->method;
250     }
251
252     /**
253      * Set the request method.
254      *
255      * Unlike the regular Request implementation, the server-side
256      * normalizes the method to uppercase to ensure consistency
257      * and make checking the method simpler.
258      *
259      * This methods returns a new instance.
260      *
261      * @param string $method
262      * @return self
263      */
264     public function withMethod($method)
265     {
266         $this->validateMethod($method);
267         $new = clone $this;
268         $new->method = $method;
269         return $new;
270     }
271
272     /**
273      * Recursively validate the structure in an uploaded files array.
274      *
275      * @param array $uploadedFiles
276      * @throws InvalidArgumentException if any leaf is not an UploadedFileInterface instance.
277      */
278     private function validateUploadedFiles(array $uploadedFiles)
279     {
280         foreach ($uploadedFiles as $file) {
281             if (is_array($file)) {
282                 $this->validateUploadedFiles($file);
283                 continue;
284             }
285
286             if (! $file instanceof UploadedFileInterface) {
287                 throw new InvalidArgumentException('Invalid leaf in uploaded files structure');
288             }
289         }
290     }
291 }