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