1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
|
<?php
/**
* ownCloud - Request
*
* @author Thomas Tanghus
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\AppFramework\Http;
use OCP\IRequest;
/**
* Class for accessing variables in the request.
* This class provides an immutable object with request variables.
*/
class Request implements \ArrayAccess, \Countable, IRequest {
protected $inputStream;
protected $content;
protected $items = array();
protected $allowedKeys = array(
'get',
'post',
'files',
'server',
'env',
'cookies',
'urlParams',
'parameters',
'method',
'requesttoken',
);
/**
* @param array $vars An associative array with the following optional values:
* @param array 'urlParams' the parameters which were matched from the URL
* @param array 'get' the $_GET array
* @param array|string 'post' the $_POST array or JSON string
* @param array 'files' the $_FILES array
* @param array 'server' the $_SERVER array
* @param array 'env' the $_ENV array
* @param array 'cookies' the $_COOKIE array
* @param string 'method' the request method (GET, POST etc)
* @param string|false 'requesttoken' the requesttoken or false when not available
* @see http://www.php.net/manual/en/reserved.variables.php
*/
public function __construct(array $vars=array()) {
foreach($this->allowedKeys as $name) {
$this->items[$name] = isset($vars[$name])
? $vars[$name]
: array();
}
if (defined('PHPUNIT_RUN') && PHPUNIT_RUN
&& in_array('fakeinput', stream_get_wrappers())) {
$this->inputStream = 'fakeinput://data';
} else {
$this->inputStream = 'php://input';
}
// Only 'application/x-www-form-urlencoded' requests are automatically
// transformed by PHP, 'application/json' must be decoded manually.
if ($this->method === 'POST'
&& strpos($this->getHeader('Content-Type'), 'application/json') !== false
) {
$this->items['params'] = $this->items['post'] = json_decode(file_get_contents($this->inputStream), true);
}
$this->items['parameters'] = array_merge(
$this->items['get'],
$this->items['post'],
$this->items['urlParams']
);
}
// Countable method.
public function count() {
return count(array_keys($this->items['parameters']));
}
/**
* ArrayAccess methods
*
* Gives access to the combined GET, POST and urlParams arrays
*
* Examples:
*
* $var = $request['myvar'];
*
* or
*
* if(!isset($request['myvar']) {
* // Do something
* }
*
* $request['myvar'] = 'something'; // This throws an exception.
*
* @param string $offset The key to lookup
* @return boolean
*/
public function offsetExists($offset) {
return isset($this->items['parameters'][$offset]);
}
/**
* @see offsetExists
*/
public function offsetGet($offset) {
return isset($this->items['parameters'][$offset])
? $this->items['parameters'][$offset]
: null;
}
/**
* @see offsetExists
*/
public function offsetSet($offset, $value) {
throw new \RuntimeException('You cannot change the contents of the request object');
}
/**
* @see offsetExists
*/
public function offsetUnset($offset) {
throw new \RuntimeException('You cannot change the contents of the request object');
}
// Magic property accessors
public function __set($name, $value) {
throw new \RuntimeException('You cannot change the contents of the request object');
}
/**
* Access request variables by method and name.
* Examples:
*
* $request->post['myvar']; // Only look for POST variables
* $request->myvar; or $request->{'myvar'}; or $request->{$myvar}
* Looks in the combined GET, POST and urlParams array.
*
* If you access e.g. ->post but the current HTTP request method
* is GET a \LogicException will be thrown.
*
* @param string $name The key to look for.
* @throws \LogicException
* @return mixed|null
*/
public function __get($name) {
switch($name) {
case 'put':
case 'patch':
case 'get':
case 'post':
if($this->method !== strtoupper($name)) {
throw new \LogicException(sprintf('%s cannot be accessed in a %s request.', $name, $this->method));
}
case 'files':
case 'server':
case 'env':
case 'cookies':
case 'parameters':
case 'params':
case 'urlParams':
if(in_array($name, array('put', 'patch'))) {
return $this->getContent($name);
} else {
return isset($this->items[$name])
? $this->items[$name]
: null;
}
break;
case 'method':
return $this->items['method'];
break;
default;
return isset($this[$name])
? $this[$name]
: null;
break;
}
}
public function __isset($name) {
return isset($this->items['parameters'][$name]);
}
public function __unset($id) {
throw new \RunTimeException('You cannot change the contents of the request object');
}
/**
* Returns the value for a specific http header.
*
* This method returns null if the header did not exist.
*
* @param string $name
* @return string
*/
public function getHeader($name) {
$name = strtoupper(str_replace(array('-'),array('_'),$name));
if (isset($this->server['HTTP_' . $name])) {
return $this->server['HTTP_' . $name];
}
// There's a few headers that seem to end up in the top-level
// server array.
switch($name) {
case 'CONTENT_TYPE' :
case 'CONTENT_LENGTH' :
if (isset($this->server[$name])) {
return $this->server[$name];
}
break;
}
return null;
}
/**
* Lets you access post and get parameters by the index
* In case of json requests the encoded json body is accessed
*
* @param string $key the key which you want to access in the URL Parameter
* placeholder, $_POST or $_GET array.
* The priority how they're returned is the following:
* 1. URL parameters
* 2. POST parameters
* 3. GET parameters
* @param mixed $default If the key is not found, this value will be returned
* @return mixed the content of the array
*/
public function getParam($key, $default = null) {
return isset($this->parameters[$key])
? $this->parameters[$key]
: $default;
}
/**
* Returns all params that were received, be it from the request
* (as GET or POST) or throuh the URL by the route
* @return array the array with all parameters
*/
public function getParams() {
return $this->parameters;
}
/**
* Returns the method of the request
* @return string the method of the request (POST, GET, etc)
*/
public function getMethod() {
return $this->method;
}
/**
* Shortcut for accessing an uploaded file through the $_FILES array
* @param string $key the key that will be taken from the $_FILES array
* @return array the file in the $_FILES element
*/
public function getUploadedFile($key) {
return isset($this->files[$key]) ? $this->files[$key] : null;
}
/**
* Shortcut for getting env variables
* @param string $key the key that will be taken from the $_ENV array
* @return array the value in the $_ENV element
*/
public function getEnv($key) {
return isset($this->env[$key]) ? $this->env[$key] : null;
}
/**
* Shortcut for getting cookie variables
* @param string $key the key that will be taken from the $_COOKIE array
* @return array the value in the $_COOKIE element
*/
function getCookie($key) {
return isset($this->cookies[$key]) ? $this->cookies[$key] : null;
}
/**
* Returns the request body content.
*
* If the HTTP request method is PUT and the body
* not application/x-www-form-urlencoded or application/json a stream
* resource is returned, otherwise an array.
*
* @return array|string|resource The request body content or a resource to read the body stream.
*
* @throws \LogicException
*/
protected function getContent() {
if ($this->content === false && $this->method === 'PUT') {
throw new \LogicException(
'"put" can only be accessed once if not '
. 'application/x-www-form-urlencoded or application/json.'
);
}
// If the content can't be parsed into an array then return a stream resource.
if ($this->method === 'PUT'
&& strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') === false
&& strpos($this->getHeader('Content-Type'), 'application/json') === false
) {
$this->content = false;
return fopen($this->inputStream, 'rb');
}
if (is_null($this->content)) {
$this->content = file_get_contents($this->inputStream);
/*
* Normal jquery ajax requests are sent as application/x-www-form-urlencoded
* and in $_GET and $_POST PHP transformes the data into an array.
* The first condition mimics this.
* The second condition allows for sending raw application/json data while
* still getting the result as an array.
*
*/
if (strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') !== false) {
parse_str($this->content, $content);
if(is_array($content)) {
$this->content = $content;
}
} elseif (strpos($this->getHeader('Content-Type'), 'application/json') !== false) {
$content = json_decode($this->content, true);
if(is_array($content)) {
$this->content = $content;
}
}
}
return $this->content;
}
/**
* Checks if the CSRF check was correct
* @return bool true if CSRF check passed
* @see OC_Util::$callLifespan
* @see OC_Util::callRegister()
*/
public function passesCSRFCheck() {
if($this->items['requesttoken'] === false) {
return false;
}
if (isset($this->items['get']['requesttoken'])) {
$token = $this->items['get']['requesttoken'];
} elseif (isset($this->items['post']['requesttoken'])) {
$token = $this->items['post']['requesttoken'];
} elseif (isset($this->items['server']['HTTP_REQUESTTOKEN'])) {
$token = $this->items['server']['HTTP_REQUESTTOKEN'];
} else {
//no token found.
return false;
}
// Check if the token is valid
if($token !== $this->items['requesttoken']) {
// Not valid
return false;
} else {
// Valid token
return true;
}
}}
|