1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
4
|
|
|
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
5
|
|
|
* |
6
|
|
|
* Licensed under The MIT License |
7
|
|
|
* For full copyright and license information, please see the LICENSE.txt |
8
|
|
|
* Redistributions of files must retain the above copyright notice. |
9
|
|
|
* |
10
|
|
|
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
11
|
|
|
* @link https://cakephp.org CakePHP(tm) Project |
12
|
|
|
* @since 2.0.0 |
13
|
|
|
* @license https://opensource.org/licenses/mit-license.php MIT License |
14
|
|
|
*/ |
15
|
|
|
namespace Cake\Http; |
16
|
|
|
|
17
|
|
|
use ArrayAccess; |
18
|
|
|
use BadMethodCallException; |
19
|
|
|
use Cake\Core\Configure; |
20
|
|
|
use Cake\Http\Cookie\CookieCollection; |
21
|
|
|
use Cake\Http\Exception\MethodNotAllowedException; |
22
|
|
|
use Cake\Http\Session; |
23
|
|
|
use Cake\Utility\Hash; |
24
|
|
|
use InvalidArgumentException; |
25
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
26
|
|
|
use Psr\Http\Message\StreamInterface; |
27
|
|
|
use Psr\Http\Message\UploadedFileInterface; |
28
|
|
|
use Psr\Http\Message\UriInterface; |
29
|
|
|
use Zend\Diactoros\PhpInputStream; |
30
|
|
|
use Zend\Diactoros\Stream; |
31
|
|
|
use Zend\Diactoros\UploadedFile; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* A class that helps wrap Request information and particulars about a single request. |
35
|
|
|
* Provides methods commonly used to introspect on the request headers and request body. |
36
|
|
|
*/ |
37
|
|
|
class ServerRequest implements ArrayAccess, ServerRequestInterface |
38
|
|
|
{ |
39
|
|
|
/** |
40
|
|
|
* Array of parameters parsed from the URL. |
41
|
|
|
* |
42
|
|
|
* @var array |
43
|
|
|
* @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getParam() instead. |
44
|
|
|
*/ |
45
|
|
|
protected $params = [ |
46
|
|
|
'plugin' => null, |
47
|
|
|
'controller' => null, |
48
|
|
|
'action' => null, |
49
|
|
|
'_ext' => null, |
50
|
|
|
'pass' => [], |
51
|
|
|
]; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Array of POST data. Will contain form data as well as uploaded files. |
55
|
|
|
* In PUT/PATCH/DELETE requests this property will contain the form-urlencoded |
56
|
|
|
* data. |
57
|
|
|
* |
58
|
|
|
* @var array|object|null |
59
|
|
|
* @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getData() instead. |
60
|
|
|
*/ |
61
|
|
|
protected $data = []; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Array of query string arguments |
65
|
|
|
* |
66
|
|
|
* @var array |
67
|
|
|
* @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead. |
68
|
|
|
*/ |
69
|
|
|
protected $query = []; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Array of cookie data. |
73
|
|
|
* |
74
|
|
|
* @var array |
75
|
|
|
* @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getCookie() instead. |
76
|
|
|
*/ |
77
|
|
|
protected $cookies = []; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Array of environment data. |
81
|
|
|
* |
82
|
|
|
* @var array |
83
|
|
|
*/ |
84
|
|
|
protected $_environment = []; |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* The URL string used for the request. |
88
|
|
|
* |
89
|
|
|
* @var string |
90
|
|
|
* @deprecated 3.6.0 This public property will be removed in 4.0.0. Use getPath() instead. |
91
|
|
|
*/ |
92
|
|
|
protected $url; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Base URL path. |
96
|
|
|
* |
97
|
|
|
* @var string |
98
|
|
|
* @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('base') instead. |
99
|
|
|
*/ |
100
|
|
|
protected $base; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* webroot path segment for the request. |
104
|
|
|
* |
105
|
|
|
* @var string |
106
|
|
|
* @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('webroot') instead. |
107
|
|
|
*/ |
108
|
|
|
protected $webroot = '/'; |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* The full address to the current request |
112
|
|
|
* |
113
|
|
|
* @var string |
114
|
|
|
* @deprecated 3.4.0 This public property will be removed in 4.0.0. Use getAttribute('here') or getUri()->getPath() instead. |
115
|
|
|
*/ |
116
|
|
|
protected $here; |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Whether or not to trust HTTP_X headers set by most load balancers. |
120
|
|
|
* Only set to true if your application runs behind load balancers/proxies |
121
|
|
|
* that you control. |
122
|
|
|
* |
123
|
|
|
* @var bool |
124
|
|
|
*/ |
125
|
|
|
public $trustProxy = false; |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Trusted proxies list |
129
|
|
|
* |
130
|
|
|
* @var string[] |
131
|
|
|
*/ |
132
|
|
|
protected $trustedProxies = []; |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Contents of php://input |
136
|
|
|
* |
137
|
|
|
* @var string |
138
|
|
|
*/ |
139
|
|
|
protected $_input; |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* The built in detectors used with `is()` can be modified with `addDetector()`. |
143
|
|
|
* |
144
|
|
|
* There are several ways to specify a detector, see \Cake\Http\ServerRequest::addDetector() for the |
145
|
|
|
* various formats and ways to define detectors. |
146
|
|
|
* |
147
|
|
|
* @var array |
148
|
|
|
*/ |
149
|
|
|
protected static $_detectors = [ |
150
|
|
|
'get' => ['env' => 'REQUEST_METHOD', 'value' => 'GET'], |
151
|
|
|
'post' => ['env' => 'REQUEST_METHOD', 'value' => 'POST'], |
152
|
|
|
'put' => ['env' => 'REQUEST_METHOD', 'value' => 'PUT'], |
153
|
|
|
'patch' => ['env' => 'REQUEST_METHOD', 'value' => 'PATCH'], |
154
|
|
|
'delete' => ['env' => 'REQUEST_METHOD', 'value' => 'DELETE'], |
155
|
|
|
'head' => ['env' => 'REQUEST_METHOD', 'value' => 'HEAD'], |
156
|
|
|
'options' => ['env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'], |
157
|
|
|
'ssl' => ['env' => 'HTTPS', 'options' => [1, 'on']], |
158
|
|
|
'ajax' => ['env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'], |
159
|
|
|
'flash' => ['env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'], |
160
|
|
|
'requested' => ['param' => 'requested', 'value' => 1], |
161
|
|
|
'json' => ['accept' => ['application/json'], 'param' => '_ext', 'value' => 'json'], |
162
|
|
|
'xml' => ['accept' => ['application/xml', 'text/xml'], 'param' => '_ext', 'value' => 'xml'], |
163
|
|
|
]; |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Instance cache for results of is(something) calls |
167
|
|
|
* |
168
|
|
|
* @var array |
169
|
|
|
*/ |
170
|
|
|
protected $_detectorCache = []; |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Request body stream. Contains php://input unless `input` constructor option is used. |
174
|
|
|
* |
175
|
|
|
* @var \Psr\Http\Message\StreamInterface |
176
|
|
|
*/ |
177
|
|
|
protected $stream; |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Uri instance |
181
|
|
|
* |
182
|
|
|
* @var \Psr\Http\Message\UriInterface |
183
|
|
|
*/ |
184
|
|
|
protected $uri; |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Instance of a Session object relative to this request |
188
|
|
|
* |
189
|
|
|
* @var \Cake\Http\Session |
190
|
|
|
*/ |
191
|
|
|
protected $session; |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Store the additional attributes attached to the request. |
195
|
|
|
* |
196
|
|
|
* @var array |
197
|
|
|
*/ |
198
|
|
|
protected $attributes = []; |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* A list of propertes that emulated by the PSR7 attribute methods. |
202
|
|
|
* |
203
|
|
|
* @var array |
204
|
|
|
*/ |
205
|
|
|
protected $emulatedAttributes = ['session', 'webroot', 'base', 'params', 'here']; |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Array of Psr\Http\Message\UploadedFileInterface objects. |
209
|
|
|
* |
210
|
|
|
* @var array |
211
|
|
|
*/ |
212
|
|
|
protected $uploadedFiles = []; |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* The HTTP protocol version used. |
216
|
|
|
* |
217
|
|
|
* @var string|null |
218
|
|
|
*/ |
219
|
|
|
protected $protocol; |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* The request target if overridden |
223
|
|
|
* |
224
|
|
|
* @var string|null |
225
|
|
|
*/ |
226
|
|
|
protected $requestTarget; |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* List of deprecated properties that have backwards |
230
|
|
|
* compatibility offered through magic methods. |
231
|
|
|
* |
232
|
|
|
* @var array |
233
|
|
|
*/ |
234
|
|
|
private $deprecatedProperties = [ |
235
|
|
|
'data' => ['get' => 'getData()', 'set' => 'withData()'], |
236
|
|
|
'query' => ['get' => 'getQuery()', 'set' => 'withQueryParams()'], |
237
|
|
|
'params' => ['get' => 'getParam()', 'set' => 'withParam()'], |
238
|
|
|
'cookies' => ['get' => 'getCookie()', 'set' => 'withCookieParams()'], |
239
|
|
|
'url' => ['get' => 'getPath()', 'set' => 'withRequestTarget()'], |
240
|
|
|
'base' => ['get' => 'getAttribute("base")', 'set' => 'withAttribute("base")'], |
241
|
|
|
'webroot' => ['get' => 'getAttribute("webroot")', 'set' => 'withAttribute("webroot")'], |
242
|
|
|
'here' => ['get' => 'getAttribute("here")', 'set' => 'withAttribute("here")'], |
243
|
|
|
]; |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Wrapper method to create a new request from PHP superglobals. |
247
|
|
|
* |
248
|
|
|
* Uses the $_GET, $_POST, $_FILES, $_COOKIE, $_SERVER, $_ENV and php://input data to construct |
249
|
|
|
* the request. |
250
|
|
|
* |
251
|
|
|
* @return self |
252
|
|
|
* @deprecated 3.4.0 Use `Cake\Http\ServerRequestFactory` instead. |
253
|
|
|
*/ |
254
|
|
|
public static function createFromGlobals() |
255
|
|
|
{ |
256
|
|
|
deprecationWarning( |
257
|
|
|
'ServerRequest::createFromGlobals() is deprecated. ' . |
258
|
|
|
'Use `Cake\Http\ServerRequestFactory` instead.' |
259
|
|
|
); |
260
|
|
|
|
261
|
|
|
return ServerRequestFactory::fromGlobals(); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* Create a new request object. |
266
|
|
|
* |
267
|
|
|
* You can supply the data as either an array or as a string. If you use |
268
|
|
|
* a string you can only supply the URL for the request. Using an array will |
269
|
|
|
* let you provide the following keys: |
270
|
|
|
* |
271
|
|
|
* - `post` POST data or non query string data |
272
|
|
|
* - `query` Additional data from the query string. |
273
|
|
|
* - `files` Uploaded file data formatted like $_FILES. |
274
|
|
|
* - `cookies` Cookies for this request. |
275
|
|
|
* - `environment` $_SERVER and $_ENV data. |
276
|
|
|
* - `url` The URL without the base path for the request. |
277
|
|
|
* - `uri` The PSR7 UriInterface object. If null, one will be created. |
278
|
|
|
* - `base` The base URL for the request. |
279
|
|
|
* - `webroot` The webroot directory for the request. |
280
|
|
|
* - `input` The data that would come from php://input this is useful for simulating |
281
|
|
|
* requests with put, patch or delete data. |
282
|
|
|
* - `session` An instance of a Session object |
283
|
|
|
* |
284
|
|
|
* @param string|array $config An array of request data to create a request with. |
285
|
|
|
* The string version of this argument is *deprecated* and will be removed in 4.0.0 |
286
|
|
|
*/ |
287
|
|
|
public function __construct($config = []) |
288
|
|
|
{ |
289
|
|
|
if (is_string($config)) { |
290
|
|
|
$config = ['url' => $config]; |
291
|
|
|
} |
292
|
|
|
$config += [ |
293
|
|
|
'params' => $this->params, |
|
|
|
|
294
|
|
|
'query' => [], |
295
|
|
|
'post' => [], |
296
|
|
|
'files' => [], |
297
|
|
|
'cookies' => [], |
298
|
|
|
'environment' => [], |
299
|
|
|
'url' => '', |
300
|
|
|
'uri' => null, |
301
|
|
|
'base' => '', |
302
|
|
|
'webroot' => '', |
303
|
|
|
'input' => null, |
304
|
|
|
]; |
305
|
|
|
|
306
|
|
|
$this->_setConfig($config); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Process the config/settings data into properties. |
311
|
|
|
* |
312
|
|
|
* @param array $config The config data to use. |
313
|
|
|
* @return void |
314
|
|
|
*/ |
315
|
|
|
protected function _setConfig($config) |
316
|
|
|
{ |
317
|
|
|
if (strlen($config['url']) > 1 && $config['url'][0] === '/') { |
318
|
|
|
$config['url'] = substr($config['url'], 1); |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
if (empty($config['session'])) { |
322
|
|
|
$config['session'] = new Session([ |
323
|
|
|
'cookiePath' => $config['base'], |
324
|
|
|
]); |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
$this->_environment = $config['environment']; |
328
|
|
|
$this->cookies = $config['cookies']; |
|
|
|
|
329
|
|
|
|
330
|
|
|
if (isset($config['uri']) && $config['uri'] instanceof UriInterface) { |
331
|
|
|
$uri = $config['uri']; |
332
|
|
|
} else { |
333
|
|
|
$uri = ServerRequestFactory::createUri($config['environment']); |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
// Extract a query string from config[url] if present. |
337
|
|
|
// This is required for backwards compatibility and keeping |
338
|
|
|
// UriInterface implementations happy. |
339
|
|
|
$querystr = ''; |
340
|
|
|
if (strpos($config['url'], '?') !== false) { |
341
|
|
|
list($config['url'], $querystr) = explode('?', $config['url']); |
342
|
|
|
} |
343
|
|
|
if (strlen($config['url'])) { |
344
|
|
|
$uri = $uri->withPath('/' . $config['url']); |
345
|
|
|
} |
346
|
|
|
if (strlen($querystr)) { |
347
|
|
|
$uri = $uri->withQuery($querystr); |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
$this->uri = $uri; |
351
|
|
|
$this->base = $config['base']; |
|
|
|
|
352
|
|
|
$this->webroot = $config['webroot']; |
|
|
|
|
353
|
|
|
|
354
|
|
|
$this->url = substr($uri->getPath(), 1); |
|
|
|
|
355
|
|
|
$this->here = $this->base . '/' . $this->url; |
|
|
|
|
356
|
|
|
|
357
|
|
View Code Duplication |
if (isset($config['input'])) { |
358
|
|
|
$stream = new Stream('php://memory', 'rw'); |
359
|
|
|
$stream->write($config['input']); |
360
|
|
|
$stream->rewind(); |
361
|
|
|
} else { |
362
|
|
|
$stream = new PhpInputStream(); |
363
|
|
|
} |
364
|
|
|
$this->stream = $stream; |
365
|
|
|
|
366
|
|
|
$config['post'] = $this->_processPost($config['post']); |
367
|
|
|
$this->data = $this->_processFiles($config['post'], $config['files']); |
|
|
|
|
368
|
|
|
$this->query = $this->_processGet($config['query'], $querystr); |
|
|
|
|
369
|
|
|
$this->params = $config['params']; |
|
|
|
|
370
|
|
|
$this->session = $config['session']; |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
/** |
374
|
|
|
* Sets the REQUEST_METHOD environment variable based on the simulated _method |
375
|
|
|
* HTTP override value. The 'ORIGINAL_REQUEST_METHOD' is also preserved, if you |
376
|
|
|
* want the read the non-simulated HTTP method the client used. |
377
|
|
|
* |
378
|
|
|
* @param array $data Array of post data. |
379
|
|
|
* @return array |
380
|
|
|
*/ |
381
|
|
|
protected function _processPost($data) |
382
|
|
|
{ |
383
|
|
|
$method = $this->getEnv('REQUEST_METHOD'); |
384
|
|
|
$override = false; |
385
|
|
|
|
386
|
|
|
if ( |
387
|
|
|
in_array($method, ['PUT', 'DELETE', 'PATCH'], true) && |
388
|
|
|
strpos($this->contentType(), 'application/x-www-form-urlencoded') === 0 |
389
|
|
|
) { |
390
|
|
|
$data = $this->input(); |
391
|
|
|
parse_str($data, $data); |
392
|
|
|
} |
393
|
|
|
if ($this->hasHeader('X-Http-Method-Override')) { |
394
|
|
|
$data['_method'] = $this->getHeaderLine('X-Http-Method-Override'); |
395
|
|
|
$override = true; |
396
|
|
|
} |
397
|
|
|
$this->_environment['ORIGINAL_REQUEST_METHOD'] = $method; |
398
|
|
|
if (isset($data['_method'])) { |
399
|
|
|
$this->_environment['REQUEST_METHOD'] = $data['_method']; |
400
|
|
|
unset($data['_method']); |
401
|
|
|
$override = true; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
if ($override && !in_array($this->_environment['REQUEST_METHOD'], ['PUT', 'POST', 'DELETE', 'PATCH'], true)) { |
405
|
|
|
$data = []; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
return $data; |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
/** |
412
|
|
|
* Process the GET parameters and move things into the object. |
413
|
|
|
* |
414
|
|
|
* @param array $query The array to which the parsed keys/values are being added. |
415
|
|
|
* @param string $queryString A query string from the URL if provided |
416
|
|
|
* @return array An array containing the parsed query string as keys/values. |
417
|
|
|
*/ |
418
|
|
|
protected function _processGet($query, $queryString = '') |
419
|
|
|
{ |
420
|
|
|
$unsetUrl = '/' . str_replace(['.', ' '], '_', urldecode($this->url)); |
|
|
|
|
421
|
|
|
unset($query[$unsetUrl], $query[$this->base . $unsetUrl]); |
422
|
|
|
if (strlen($queryString)) { |
423
|
|
|
parse_str($queryString, $queryArgs); |
424
|
|
|
$query += $queryArgs; |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
return $query; |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
/** |
431
|
|
|
* Process uploaded files and move things onto the post data. |
432
|
|
|
* |
433
|
|
|
* @param array $post Post data to merge files onto. |
434
|
|
|
* @param array $files Uploaded files to merge in. |
435
|
|
|
* @return array merged post + file data. |
436
|
|
|
*/ |
437
|
|
|
protected function _processFiles($post, $files) |
438
|
|
|
{ |
439
|
|
|
if (!is_array($files)) { |
440
|
|
|
return $post; |
441
|
|
|
} |
442
|
|
|
$fileData = []; |
443
|
|
|
foreach ($files as $key => $value) { |
444
|
|
|
if ($value instanceof UploadedFileInterface) { |
445
|
|
|
$fileData[$key] = $value; |
446
|
|
|
continue; |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
if (is_array($value) && isset($value['tmp_name'])) { |
450
|
|
|
$fileData[$key] = $this->_createUploadedFile($value); |
451
|
|
|
continue; |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
throw new InvalidArgumentException(sprintf( |
455
|
|
|
'Invalid value in FILES "%s"', |
456
|
|
|
json_encode($value) |
457
|
|
|
)); |
458
|
|
|
} |
459
|
|
|
$this->uploadedFiles = $fileData; |
460
|
|
|
|
461
|
|
|
// Make a flat map that can be inserted into $post for BC. |
462
|
|
|
$fileMap = Hash::flatten($fileData); |
463
|
|
|
foreach ($fileMap as $key => $file) { |
464
|
|
|
$error = $file->getError(); |
465
|
|
|
$tmpName = ''; |
466
|
|
|
if ($error === UPLOAD_ERR_OK) { |
467
|
|
|
$tmpName = $file->getStream()->getMetadata('uri'); |
468
|
|
|
} |
469
|
|
|
$post = Hash::insert($post, $key, [ |
470
|
|
|
'tmp_name' => $tmpName, |
471
|
|
|
'error' => $error, |
472
|
|
|
'name' => $file->getClientFilename(), |
473
|
|
|
'type' => $file->getClientMediaType(), |
474
|
|
|
'size' => $file->getSize(), |
475
|
|
|
]); |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
return $post; |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* Create an UploadedFile instance from a $_FILES array. |
483
|
|
|
* |
484
|
|
|
* If the value represents an array of values, this method will |
485
|
|
|
* recursively process the data. |
486
|
|
|
* |
487
|
|
|
* @param array $value $_FILES struct |
488
|
|
|
* @return array|UploadedFileInterface |
489
|
|
|
*/ |
490
|
|
|
protected function _createUploadedFile(array $value) |
491
|
|
|
{ |
492
|
|
|
if (is_array($value['tmp_name'])) { |
493
|
|
|
return $this->_normalizeNestedFiles($value); |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
return new UploadedFile( |
497
|
|
|
$value['tmp_name'], |
498
|
|
|
$value['size'], |
499
|
|
|
$value['error'], |
500
|
|
|
$value['name'], |
501
|
|
|
$value['type'] |
502
|
|
|
); |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
/** |
506
|
|
|
* Normalize an array of file specifications. |
507
|
|
|
* |
508
|
|
|
* Loops through all nested files and returns a normalized array of |
509
|
|
|
* UploadedFileInterface instances. |
510
|
|
|
* |
511
|
|
|
* @param array $files The file data to normalize & convert. |
512
|
|
|
* @return array An array of UploadedFileInterface objects. |
513
|
|
|
*/ |
514
|
|
|
protected function _normalizeNestedFiles(array $files = []) |
515
|
|
|
{ |
516
|
|
|
$normalizedFiles = []; |
517
|
|
|
foreach (array_keys($files['tmp_name']) as $key) { |
518
|
|
|
$spec = [ |
519
|
|
|
'tmp_name' => $files['tmp_name'][$key], |
520
|
|
|
'size' => $files['size'][$key], |
521
|
|
|
'error' => $files['error'][$key], |
522
|
|
|
'name' => $files['name'][$key], |
523
|
|
|
'type' => $files['type'][$key], |
524
|
|
|
]; |
525
|
|
|
$normalizedFiles[$key] = $this->_createUploadedFile($spec); |
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
return $normalizedFiles; |
529
|
|
|
} |
530
|
|
|
|
531
|
|
|
/** |
532
|
|
|
* Get the content type used in this request. |
533
|
|
|
* |
534
|
|
|
* @return string |
535
|
|
|
*/ |
536
|
|
|
public function contentType() |
537
|
|
|
{ |
538
|
|
|
$type = $this->getEnv('CONTENT_TYPE'); |
539
|
|
|
if ($type) { |
540
|
|
|
return $type; |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
return $this->getEnv('HTTP_CONTENT_TYPE'); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* Returns the instance of the Session object for this request |
548
|
|
|
* |
549
|
|
|
* @return \Cake\Http\Session |
550
|
|
|
*/ |
551
|
|
|
public function getSession() |
552
|
|
|
{ |
553
|
|
|
return $this->session; |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
/** |
557
|
|
|
* Returns the instance of the Session object for this request |
558
|
|
|
* |
559
|
|
|
* If a session object is passed as first argument it will be set as |
560
|
|
|
* the session to use for this request |
561
|
|
|
* |
562
|
|
|
* @deprecated 3.5.0 Use getSession() instead. The setter part will be removed. |
563
|
|
|
* @param \Cake\Http\Session|null $session the session object to use |
564
|
|
|
* @return \Cake\Http\Session |
565
|
|
|
*/ |
566
|
|
|
public function session(Session $session = null) |
567
|
|
|
{ |
568
|
|
|
deprecationWarning( |
569
|
|
|
'ServerRequest::session() is deprecated. ' . |
570
|
|
|
'Use getSession() instead. The setter part will be removed.' |
571
|
|
|
); |
572
|
|
|
|
573
|
|
|
if ($session === null) { |
574
|
|
|
return $this->session; |
575
|
|
|
} |
576
|
|
|
|
577
|
|
|
return $this->session = $session; |
578
|
|
|
} |
579
|
|
|
|
580
|
|
|
/** |
581
|
|
|
* Get the IP the client is using, or says they are using. |
582
|
|
|
* |
583
|
|
|
* @return string The client IP. |
584
|
|
|
*/ |
585
|
|
|
public function clientIp() |
586
|
|
|
{ |
587
|
|
|
if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_FOR')) { |
588
|
|
|
$addresses = array_map('trim', explode(',', $this->getEnv('HTTP_X_FORWARDED_FOR'))); |
589
|
|
|
$trusted = (count($this->trustedProxies) > 0); |
590
|
|
|
$n = count($addresses); |
591
|
|
|
|
592
|
|
|
if ($trusted) { |
593
|
|
|
$trusted = array_diff($addresses, $this->trustedProxies); |
594
|
|
|
$trusted = (count($trusted) === 1); |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
if ($trusted) { |
598
|
|
|
return $addresses[0]; |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
return $addresses[$n - 1]; |
602
|
|
|
} |
603
|
|
|
|
604
|
|
|
if ($this->trustProxy && $this->getEnv('HTTP_X_REAL_IP')) { |
605
|
|
|
$ipaddr = $this->getEnv('HTTP_X_REAL_IP'); |
606
|
|
|
} elseif ($this->trustProxy && $this->getEnv('HTTP_CLIENT_IP')) { |
607
|
|
|
$ipaddr = $this->getEnv('HTTP_CLIENT_IP'); |
608
|
|
|
} else { |
609
|
|
|
$ipaddr = $this->getEnv('REMOTE_ADDR'); |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
return trim($ipaddr); |
613
|
|
|
} |
614
|
|
|
|
615
|
|
|
/** |
616
|
|
|
* register trusted proxies |
617
|
|
|
* |
618
|
|
|
* @param string[] $proxies ips list of trusted proxies |
619
|
|
|
* @return void |
620
|
|
|
*/ |
621
|
|
|
public function setTrustedProxies(array $proxies) |
622
|
|
|
{ |
623
|
|
|
$this->trustedProxies = $proxies; |
624
|
|
|
$this->trustProxy = true; |
625
|
|
|
} |
626
|
|
|
|
627
|
|
|
/** |
628
|
|
|
* Get trusted proxies |
629
|
|
|
* |
630
|
|
|
* @return string[] |
631
|
|
|
*/ |
632
|
|
|
public function getTrustedProxies() |
633
|
|
|
{ |
634
|
|
|
return $this->trustedProxies; |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
/** |
638
|
|
|
* Returns the referer that referred this request. |
639
|
|
|
* |
640
|
|
|
* @param bool $local Attempt to return a local address. |
641
|
|
|
* Local addresses do not contain hostnames. |
642
|
|
|
* @return string The referring address for this request. |
643
|
|
|
*/ |
644
|
|
|
public function referer($local = false) |
645
|
|
|
{ |
646
|
|
|
$ref = $this->getEnv('HTTP_REFERER'); |
647
|
|
|
|
648
|
|
|
$base = Configure::read('App.fullBaseUrl') . $this->webroot; |
|
|
|
|
649
|
|
|
if (!empty($ref) && !empty($base)) { |
650
|
|
|
if ($local && strpos($ref, $base) === 0) { |
651
|
|
|
$ref = substr($ref, strlen($base)); |
652
|
|
|
if (!strlen($ref) || strpos($ref, '//') === 0) { |
653
|
|
|
$ref = '/'; |
654
|
|
|
} |
655
|
|
|
if ($ref[0] !== '/') { |
656
|
|
|
$ref = '/' . $ref; |
657
|
|
|
} |
658
|
|
|
|
659
|
|
|
return $ref; |
660
|
|
|
} |
661
|
|
|
if (!$local) { |
662
|
|
|
return $ref; |
663
|
|
|
} |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
return '/'; |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
/** |
670
|
|
|
* Missing method handler, handles wrapping older style isAjax() type methods |
671
|
|
|
* |
672
|
|
|
* @param string $name The method called |
673
|
|
|
* @param array $params Array of parameters for the method call |
674
|
|
|
* @return mixed |
675
|
|
|
* @throws \BadMethodCallException when an invalid method is called. |
676
|
|
|
*/ |
677
|
|
|
public function __call($name, $params) |
678
|
|
|
{ |
679
|
|
|
if (strpos($name, 'is') === 0) { |
680
|
|
|
$type = strtolower(substr($name, 2)); |
681
|
|
|
|
682
|
|
|
array_unshift($params, $type); |
683
|
|
|
|
684
|
|
|
return $this->is(...$params); |
685
|
|
|
} |
686
|
|
|
throw new BadMethodCallException(sprintf('Method "%s()" does not exist', $name)); |
687
|
|
|
} |
688
|
|
|
|
689
|
|
|
/** |
690
|
|
|
* Magic set method allows backward compatibility for former public properties |
691
|
|
|
* |
692
|
|
|
* |
693
|
|
|
* @param string $name The property being accessed. |
694
|
|
|
* @param mixed $value The property value. |
695
|
|
|
* @return mixed Either the value of the parameter or null. |
696
|
|
|
* @deprecated 3.6.0 Public properties will be removed in 4.0.0. |
697
|
|
|
* Use appropriate setters instead. |
698
|
|
|
*/ |
699
|
|
|
public function __set($name, $value) |
700
|
|
|
{ |
701
|
|
View Code Duplication |
if (isset($this->deprecatedProperties[$name])) { |
702
|
|
|
$method = $this->deprecatedProperties[$name]['set']; |
703
|
|
|
deprecationWarning( |
704
|
|
|
"Setting {$name} as a property will be removed in 4.0.0. " . |
705
|
|
|
"Use {$method} instead." |
706
|
|
|
); |
707
|
|
|
|
708
|
|
|
return $this->{$name} = $value; |
709
|
|
|
} |
710
|
|
|
throw new BadMethodCallException("Cannot set {$name} it is not a known property."); |
711
|
|
|
} |
712
|
|
|
|
713
|
|
|
/** |
714
|
|
|
* Magic get method allows access to parsed routing parameters directly on the object. |
715
|
|
|
* |
716
|
|
|
* Allows access to `$this->params['controller']` via `$this->controller` |
717
|
|
|
* |
718
|
|
|
* @param string $name The property being accessed. |
719
|
|
|
* @return mixed Either the value of the parameter or null. |
720
|
|
|
* @deprecated 3.4.0 Accessing routing parameters through __get will removed in 4.0.0. |
721
|
|
|
* Use getParam() instead. |
722
|
|
|
*/ |
723
|
|
|
public function &__get($name) |
724
|
|
|
{ |
725
|
|
View Code Duplication |
if (isset($this->deprecatedProperties[$name])) { |
726
|
|
|
$method = $this->deprecatedProperties[$name]['get']; |
727
|
|
|
deprecationWarning( |
728
|
|
|
"Accessing `{$name}` as a property will be removed in 4.0.0. " . |
729
|
|
|
"Use request->{$method} instead." |
730
|
|
|
); |
731
|
|
|
|
732
|
|
|
return $this->{$name}; |
733
|
|
|
} |
734
|
|
|
|
735
|
|
|
deprecationWarning(sprintf( |
736
|
|
|
'Accessing routing parameters through `%s` will removed in 4.0.0. ' . |
737
|
|
|
'Use `getParam()` instead.', |
738
|
|
|
$name |
739
|
|
|
)); |
740
|
|
|
|
741
|
|
|
if (isset($this->params[$name])) { |
|
|
|
|
742
|
|
|
return $this->params[$name]; |
|
|
|
|
743
|
|
|
} |
744
|
|
|
$value = null; |
745
|
|
|
|
746
|
|
|
return $value; |
747
|
|
|
} |
748
|
|
|
|
749
|
|
|
/** |
750
|
|
|
* Magic isset method allows isset/empty checks |
751
|
|
|
* on routing parameters. |
752
|
|
|
* |
753
|
|
|
* @param string $name The property being accessed. |
754
|
|
|
* @return bool Existence |
755
|
|
|
* @deprecated 3.4.0 Accessing routing parameters through __isset will removed in 4.0.0. |
756
|
|
|
* Use getParam() instead. |
757
|
|
|
*/ |
758
|
|
|
public function __isset($name) |
759
|
|
|
{ |
760
|
|
View Code Duplication |
if (isset($this->deprecatedProperties[$name])) { |
761
|
|
|
$method = $this->deprecatedProperties[$name]['get']; |
762
|
|
|
deprecationWarning( |
763
|
|
|
"Accessing {$name} as a property will be removed in 4.0.0. " . |
764
|
|
|
"Use {$method} instead." |
765
|
|
|
); |
766
|
|
|
|
767
|
|
|
return isset($this->{$name}); |
768
|
|
|
} |
769
|
|
|
|
770
|
|
|
deprecationWarning( |
771
|
|
|
'Accessing routing parameters through __isset will removed in 4.0.0. ' . |
772
|
|
|
'Use getParam() instead.' |
773
|
|
|
); |
774
|
|
|
|
775
|
|
|
return isset($this->params[$name]); |
|
|
|
|
776
|
|
|
} |
777
|
|
|
|
778
|
|
|
/** |
779
|
|
|
* Check whether or not a Request is a certain type. |
780
|
|
|
* |
781
|
|
|
* Uses the built in detection rules as well as additional rules |
782
|
|
|
* defined with Cake\Http\ServerRequest::addDetector(). Any detector can be called |
783
|
|
|
* as `is($type)` or `is$Type()`. |
784
|
|
|
* |
785
|
|
|
* @param string|array $type The type of request you want to check. If an array |
786
|
|
|
* this method will return true if the request matches any type. |
787
|
|
|
* @param array ...$args List of arguments |
788
|
|
|
* @return bool Whether or not the request is the type you are checking. |
789
|
|
|
*/ |
790
|
|
|
public function is($type, ...$args) |
791
|
|
|
{ |
792
|
|
|
if (is_array($type)) { |
793
|
|
|
$result = array_map([$this, 'is'], $type); |
794
|
|
|
|
795
|
|
|
return count(array_filter($result)) > 0; |
796
|
|
|
} |
797
|
|
|
|
798
|
|
|
$type = strtolower($type); |
799
|
|
|
if (!isset(static::$_detectors[$type])) { |
800
|
|
|
return false; |
801
|
|
|
} |
802
|
|
|
if ($args) { |
|
|
|
|
803
|
|
|
return $this->_is($type, $args); |
804
|
|
|
} |
805
|
|
|
if (!isset($this->_detectorCache[$type])) { |
806
|
|
|
$this->_detectorCache[$type] = $this->_is($type, $args); |
807
|
|
|
} |
808
|
|
|
|
809
|
|
|
return $this->_detectorCache[$type]; |
810
|
|
|
} |
811
|
|
|
|
812
|
|
|
/** |
813
|
|
|
* Clears the instance detector cache, used by the is() function |
814
|
|
|
* |
815
|
|
|
* @return void |
816
|
|
|
*/ |
817
|
|
|
public function clearDetectorCache() |
818
|
|
|
{ |
819
|
|
|
$this->_detectorCache = []; |
820
|
|
|
} |
821
|
|
|
|
822
|
|
|
/** |
823
|
|
|
* Worker for the public is() function |
824
|
|
|
* |
825
|
|
|
* @param string $type The type of request you want to check. |
826
|
|
|
* @param array $args Array of custom detector arguments. |
827
|
|
|
* @return bool Whether or not the request is the type you are checking. |
828
|
|
|
*/ |
829
|
|
|
protected function _is($type, $args) |
830
|
|
|
{ |
831
|
|
|
$detect = static::$_detectors[$type]; |
832
|
|
|
if (is_callable($detect)) { |
833
|
|
|
array_unshift($args, $this); |
834
|
|
|
|
835
|
|
|
return $detect(...$args); |
836
|
|
|
} |
837
|
|
|
if (isset($detect['env']) && $this->_environmentDetector($detect)) { |
838
|
|
|
return true; |
839
|
|
|
} |
840
|
|
|
if (isset($detect['header']) && $this->_headerDetector($detect)) { |
841
|
|
|
return true; |
842
|
|
|
} |
843
|
|
|
if (isset($detect['accept']) && $this->_acceptHeaderDetector($detect)) { |
844
|
|
|
return true; |
845
|
|
|
} |
846
|
|
|
if (isset($detect['param']) && $this->_paramDetector($detect)) { |
847
|
|
|
return true; |
848
|
|
|
} |
849
|
|
|
|
850
|
|
|
return false; |
851
|
|
|
} |
852
|
|
|
|
853
|
|
|
/** |
854
|
|
|
* Detects if a specific accept header is present. |
855
|
|
|
* |
856
|
|
|
* @param array $detect Detector options array. |
857
|
|
|
* @return bool Whether or not the request is the type you are checking. |
858
|
|
|
*/ |
859
|
|
|
protected function _acceptHeaderDetector($detect) |
860
|
|
|
{ |
861
|
|
|
$acceptHeaders = explode(',', $this->getEnv('HTTP_ACCEPT')); |
862
|
|
|
foreach ($detect['accept'] as $header) { |
863
|
|
|
if (in_array($header, $acceptHeaders)) { |
864
|
|
|
return true; |
865
|
|
|
} |
866
|
|
|
} |
867
|
|
|
|
868
|
|
|
return false; |
869
|
|
|
} |
870
|
|
|
|
871
|
|
|
/** |
872
|
|
|
* Detects if a specific header is present. |
873
|
|
|
* |
874
|
|
|
* @param array $detect Detector options array. |
875
|
|
|
* @return bool Whether or not the request is the type you are checking. |
876
|
|
|
*/ |
877
|
|
|
protected function _headerDetector($detect) |
878
|
|
|
{ |
879
|
|
|
foreach ($detect['header'] as $header => $value) { |
880
|
|
|
$header = $this->getEnv('http_' . $header); |
881
|
|
|
if ($header !== null) { |
882
|
|
|
if (!is_string($value) && !is_bool($value) && is_callable($value)) { |
883
|
|
|
return call_user_func($value, $header); |
884
|
|
|
} |
885
|
|
|
|
886
|
|
|
return ($header === $value); |
887
|
|
|
} |
888
|
|
|
} |
889
|
|
|
|
890
|
|
|
return false; |
891
|
|
|
} |
892
|
|
|
|
893
|
|
|
/** |
894
|
|
|
* Detects if a specific request parameter is present. |
895
|
|
|
* |
896
|
|
|
* @param array $detect Detector options array. |
897
|
|
|
* @return bool Whether or not the request is the type you are checking. |
898
|
|
|
*/ |
899
|
|
|
protected function _paramDetector($detect) |
900
|
|
|
{ |
901
|
|
|
$key = $detect['param']; |
902
|
|
View Code Duplication |
if (isset($detect['value'])) { |
903
|
|
|
$value = $detect['value']; |
904
|
|
|
|
905
|
|
|
return isset($this->params[$key]) ? $this->params[$key] == $value : false; |
|
|
|
|
906
|
|
|
} |
907
|
|
View Code Duplication |
if (isset($detect['options'])) { |
908
|
|
|
return isset($this->params[$key]) ? in_array($this->params[$key], $detect['options']) : false; |
|
|
|
|
909
|
|
|
} |
910
|
|
|
|
911
|
|
|
return false; |
912
|
|
|
} |
913
|
|
|
|
914
|
|
|
/** |
915
|
|
|
* Detects if a specific environment variable is present. |
916
|
|
|
* |
917
|
|
|
* @param array $detect Detector options array. |
918
|
|
|
* @return bool Whether or not the request is the type you are checking. |
919
|
|
|
*/ |
920
|
|
|
protected function _environmentDetector($detect) |
921
|
|
|
{ |
922
|
|
|
if (isset($detect['env'])) { |
923
|
|
|
if (isset($detect['value'])) { |
924
|
|
|
return $this->getEnv($detect['env']) == $detect['value']; |
925
|
|
|
} |
926
|
|
|
if (isset($detect['pattern'])) { |
927
|
|
|
return (bool)preg_match($detect['pattern'], $this->getEnv($detect['env'])); |
928
|
|
|
} |
929
|
|
|
if (isset($detect['options'])) { |
930
|
|
|
$pattern = '/' . implode('|', $detect['options']) . '/i'; |
931
|
|
|
|
932
|
|
|
return (bool)preg_match($pattern, $this->getEnv($detect['env'])); |
933
|
|
|
} |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
return false; |
937
|
|
|
} |
938
|
|
|
|
939
|
|
|
/** |
940
|
|
|
* Check that a request matches all the given types. |
941
|
|
|
* |
942
|
|
|
* Allows you to test multiple types and union the results. |
943
|
|
|
* See Request::is() for how to add additional types and the |
944
|
|
|
* built-in types. |
945
|
|
|
* |
946
|
|
|
* @param string[] $types The types to check. |
947
|
|
|
* @return bool Success. |
948
|
|
|
* @see \Cake\Http\ServerRequest::is() |
949
|
|
|
*/ |
950
|
|
|
public function isAll(array $types) |
951
|
|
|
{ |
952
|
|
|
$result = array_filter(array_map([$this, 'is'], $types)); |
953
|
|
|
|
954
|
|
|
return count($result) === count($types); |
955
|
|
|
} |
956
|
|
|
|
957
|
|
|
/** |
958
|
|
|
* Add a new detector to the list of detectors that a request can use. |
959
|
|
|
* There are several different types of detectors that can be set. |
960
|
|
|
* |
961
|
|
|
* ### Callback comparison |
962
|
|
|
* |
963
|
|
|
* Callback detectors allow you to provide a callable to handle the check. |
964
|
|
|
* The callback will receive the request object as its only parameter. |
965
|
|
|
* |
966
|
|
|
* ``` |
967
|
|
|
* addDetector('custom', function ($request) { //Return a boolean }); |
968
|
|
|
* ``` |
969
|
|
|
* |
970
|
|
|
* ### Environment value comparison |
971
|
|
|
* |
972
|
|
|
* An environment value comparison, compares a value fetched from `env()` to a known value |
973
|
|
|
* the environment value is equality checked against the provided value. |
974
|
|
|
* |
975
|
|
|
* ``` |
976
|
|
|
* addDetector('post', ['env' => 'REQUEST_METHOD', 'value' => 'POST']); |
977
|
|
|
* ``` |
978
|
|
|
* |
979
|
|
|
* ### Request parameter comparison |
980
|
|
|
* |
981
|
|
|
* Allows for custom detectors on the request parameters. |
982
|
|
|
* |
983
|
|
|
* ``` |
984
|
|
|
* addDetector('requested', ['param' => 'requested', 'value' => 1]); |
985
|
|
|
* ``` |
986
|
|
|
* |
987
|
|
|
* ### Accept comparison |
988
|
|
|
* |
989
|
|
|
* Allows for detector to compare against Accept header value. |
990
|
|
|
* |
991
|
|
|
* ``` |
992
|
|
|
* addDetector('csv', ['accept' => 'text/csv']); |
993
|
|
|
* ``` |
994
|
|
|
* |
995
|
|
|
* ### Header comparison |
996
|
|
|
* |
997
|
|
|
* Allows for one or more headers to be compared. |
998
|
|
|
* |
999
|
|
|
* ``` |
1000
|
|
|
* addDetector('fancy', ['header' => ['X-Fancy' => 1]); |
1001
|
|
|
* ``` |
1002
|
|
|
* |
1003
|
|
|
* The `param`, `env` and comparison types allow the following |
1004
|
|
|
* value comparison options: |
1005
|
|
|
* |
1006
|
|
|
* ### Pattern value comparison |
1007
|
|
|
* |
1008
|
|
|
* Pattern value comparison allows you to compare a value fetched from `env()` to a regular expression. |
1009
|
|
|
* |
1010
|
|
|
* ``` |
1011
|
|
|
* addDetector('iphone', ['env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i']); |
1012
|
|
|
* ``` |
1013
|
|
|
* |
1014
|
|
|
* ### Option based comparison |
1015
|
|
|
* |
1016
|
|
|
* Option based comparisons use a list of options to create a regular expression. Subsequent calls |
1017
|
|
|
* to add an already defined options detector will merge the options. |
1018
|
|
|
* |
1019
|
|
|
* ``` |
1020
|
|
|
* addDetector('mobile', ['env' => 'HTTP_USER_AGENT', 'options' => ['Fennec']]); |
1021
|
|
|
* ``` |
1022
|
|
|
* |
1023
|
|
|
* You can also make compare against multiple values |
1024
|
|
|
* using the `options` key. This is useful when you want to check |
1025
|
|
|
* if a request value is in a list of options. |
1026
|
|
|
* |
1027
|
|
|
* `addDetector('extension', ['param' => '_ext', 'options' => ['pdf', 'csv']]` |
1028
|
|
|
* |
1029
|
|
|
* @param string $name The name of the detector. |
1030
|
|
|
* @param callable|array $callable A callable or options array for the detector definition. |
1031
|
|
|
* @return void |
1032
|
|
|
*/ |
1033
|
|
|
public static function addDetector($name, $callable) |
1034
|
|
|
{ |
1035
|
|
|
$name = strtolower($name); |
1036
|
|
|
if (is_callable($callable)) { |
1037
|
|
|
static::$_detectors[$name] = $callable; |
1038
|
|
|
|
1039
|
|
|
return; |
1040
|
|
|
} |
1041
|
|
|
if (isset(static::$_detectors[$name], $callable['options'])) { |
1042
|
|
|
$callable = Hash::merge(static::$_detectors[$name], $callable); |
1043
|
|
|
} |
1044
|
|
|
static::$_detectors[$name] = $callable; |
1045
|
|
|
} |
1046
|
|
|
|
1047
|
|
|
/** |
1048
|
|
|
* Add parameters to the request's parsed parameter set. This will overwrite any existing parameters. |
1049
|
|
|
* This modifies the parameters available through `$request->getParam()`. |
1050
|
|
|
* |
1051
|
|
|
* @param array $params Array of parameters to merge in |
1052
|
|
|
* @return $this The current object, you can chain this method. |
1053
|
|
|
* @deprecated 3.6.0 ServerRequest::addParams() is deprecated. Use `withParam()` or |
1054
|
|
|
* `withAttribute('params')` instead. |
1055
|
|
|
*/ |
1056
|
|
|
public function addParams(array $params) |
1057
|
|
|
{ |
1058
|
|
|
deprecationWarning( |
1059
|
|
|
'ServerRequest::addParams() is deprecated. ' . |
1060
|
|
|
'Use `withParam()` or `withAttribute("params", $params)` instead.' |
1061
|
|
|
); |
1062
|
|
|
$this->params = array_merge($this->params, $params); |
|
|
|
|
1063
|
|
|
|
1064
|
|
|
return $this; |
1065
|
|
|
} |
1066
|
|
|
|
1067
|
|
|
/** |
1068
|
|
|
* Add paths to the requests' paths vars. This will overwrite any existing paths. |
1069
|
|
|
* Provides an easy way to modify, here, webroot and base. |
1070
|
|
|
* |
1071
|
|
|
* @param array $paths Array of paths to merge in |
1072
|
|
|
* @return $this The current object, you can chain this method. |
1073
|
|
|
* @deprecated 3.6.0 Mutating a request in place is deprecated. Use `withAttribute()` to modify paths instead. |
1074
|
|
|
*/ |
1075
|
|
|
public function addPaths(array $paths) |
1076
|
|
|
{ |
1077
|
|
|
deprecationWarning( |
1078
|
|
|
'ServerRequest::addPaths() is deprecated. ' . |
1079
|
|
|
'Use `withAttribute($key, $value)` instead.' |
1080
|
|
|
); |
1081
|
|
|
foreach (['webroot', 'here', 'base'] as $element) { |
1082
|
|
|
if (isset($paths[$element])) { |
1083
|
|
|
$this->{$element} = $paths[$element]; |
1084
|
|
|
} |
1085
|
|
|
} |
1086
|
|
|
|
1087
|
|
|
return $this; |
1088
|
|
|
} |
1089
|
|
|
|
1090
|
|
|
/** |
1091
|
|
|
* Get the value of the current requests URL. Will include the query string arguments. |
1092
|
|
|
* |
1093
|
|
|
* @param bool $base Include the base path, set to false to trim the base path off. |
1094
|
|
|
* @return string The current request URL including query string args. |
1095
|
|
|
* @deprecated 3.4.0 This method will be removed in 4.0.0. You should use getRequestTarget() instead. |
1096
|
|
|
*/ |
1097
|
|
|
public function here($base = true) |
1098
|
|
|
{ |
1099
|
|
|
deprecationWarning( |
1100
|
|
|
'ServerRequest::here() will be removed in 4.0.0. You should use getRequestTarget() instead.' |
1101
|
|
|
); |
1102
|
|
|
|
1103
|
|
|
$url = $this->here; |
|
|
|
|
1104
|
|
|
if (!empty($this->query)) { |
|
|
|
|
1105
|
|
|
$url .= '?' . http_build_query($this->query, null, '&'); |
|
|
|
|
1106
|
|
|
} |
1107
|
|
|
if (!$base) { |
1108
|
|
|
$url = preg_replace('/^' . preg_quote($this->base, '/') . '/', '', $url, 1); |
|
|
|
|
1109
|
|
|
} |
1110
|
|
|
|
1111
|
|
|
return $url; |
1112
|
|
|
} |
1113
|
|
|
|
1114
|
|
|
/** |
1115
|
|
|
* Normalize a header name into the SERVER version. |
1116
|
|
|
* |
1117
|
|
|
* @param string $name The header name. |
1118
|
|
|
* @return string The normalized header name. |
1119
|
|
|
*/ |
1120
|
|
|
protected function normalizeHeaderName($name) |
1121
|
|
|
{ |
1122
|
|
|
$name = str_replace('-', '_', strtoupper($name)); |
1123
|
|
|
if (!in_array($name, ['CONTENT_LENGTH', 'CONTENT_TYPE'], true)) { |
1124
|
|
|
$name = 'HTTP_' . $name; |
1125
|
|
|
} |
1126
|
|
|
|
1127
|
|
|
return $name; |
1128
|
|
|
} |
1129
|
|
|
|
1130
|
|
|
/** |
1131
|
|
|
* Read an HTTP header from the Request information. |
1132
|
|
|
* |
1133
|
|
|
* If the header is not defined in the request, this method |
1134
|
|
|
* will fallback to reading data from $_SERVER and $_ENV. |
1135
|
|
|
* This fallback behavior is deprecated, and will be removed in 4.0.0 |
1136
|
|
|
* |
1137
|
|
|
* @param string $name Name of the header you want. |
1138
|
|
|
* @return string|null Either null on no header being set or the value of the header. |
1139
|
|
|
* @deprecated 4.0.0 The automatic fallback to env() will be removed in 4.0.0, see getHeader() |
1140
|
|
|
*/ |
1141
|
|
|
public function header($name) |
1142
|
|
|
{ |
1143
|
|
|
deprecationWarning( |
1144
|
|
|
'ServerRequest::header() is deprecated. ' . |
1145
|
|
|
'The automatic fallback to env() will be removed in 4.0.0, see getHeader()' |
1146
|
|
|
); |
1147
|
|
|
|
1148
|
|
|
$name = $this->normalizeHeaderName($name); |
1149
|
|
|
|
1150
|
|
|
return $this->getEnv($name); |
1151
|
|
|
} |
1152
|
|
|
|
1153
|
|
|
/** |
1154
|
|
|
* Get all headers in the request. |
1155
|
|
|
* |
1156
|
|
|
* Returns an associative array where the header names are |
1157
|
|
|
* the keys and the values are a list of header values. |
1158
|
|
|
* |
1159
|
|
|
* While header names are not case-sensitive, getHeaders() will normalize |
1160
|
|
|
* the headers. |
1161
|
|
|
* |
1162
|
|
|
* @return array An associative array of headers and their values. |
1163
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1164
|
|
|
*/ |
1165
|
|
|
public function getHeaders() |
1166
|
|
|
{ |
1167
|
|
|
$headers = []; |
1168
|
|
|
foreach ($this->_environment as $key => $value) { |
1169
|
|
|
$name = null; |
1170
|
|
|
if (strpos($key, 'HTTP_') === 0) { |
1171
|
|
|
$name = substr($key, 5); |
1172
|
|
|
} |
1173
|
|
|
if (strpos($key, 'CONTENT_') === 0) { |
1174
|
|
|
$name = $key; |
1175
|
|
|
} |
1176
|
|
|
if ($name !== null) { |
1177
|
|
|
$name = str_replace('_', ' ', strtolower($name)); |
1178
|
|
|
$name = str_replace(' ', '-', ucwords($name)); |
1179
|
|
|
$headers[$name] = (array)$value; |
1180
|
|
|
} |
1181
|
|
|
} |
1182
|
|
|
|
1183
|
|
|
return $headers; |
1184
|
|
|
} |
1185
|
|
|
|
1186
|
|
|
/** |
1187
|
|
|
* Check if a header is set in the request. |
1188
|
|
|
* |
1189
|
|
|
* @param string $name The header you want to get (case-insensitive) |
1190
|
|
|
* @return bool Whether or not the header is defined. |
1191
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1192
|
|
|
*/ |
1193
|
|
|
public function hasHeader($name) |
1194
|
|
|
{ |
1195
|
|
|
$name = $this->normalizeHeaderName($name); |
1196
|
|
|
|
1197
|
|
|
return isset($this->_environment[$name]); |
1198
|
|
|
} |
1199
|
|
|
|
1200
|
|
|
/** |
1201
|
|
|
* Get a single header from the request. |
1202
|
|
|
* |
1203
|
|
|
* Return the header value as an array. If the header |
1204
|
|
|
* is not present an empty array will be returned. |
1205
|
|
|
* |
1206
|
|
|
* @param string $name The header you want to get (case-insensitive) |
1207
|
|
|
* @return array An associative array of headers and their values. |
1208
|
|
|
* If the header doesn't exist, an empty array will be returned. |
1209
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1210
|
|
|
*/ |
1211
|
|
|
public function getHeader($name) |
1212
|
|
|
{ |
1213
|
|
|
$name = $this->normalizeHeaderName($name); |
1214
|
|
|
if (isset($this->_environment[$name])) { |
1215
|
|
|
return (array)$this->_environment[$name]; |
1216
|
|
|
} |
1217
|
|
|
|
1218
|
|
|
return []; |
1219
|
|
|
} |
1220
|
|
|
|
1221
|
|
|
/** |
1222
|
|
|
* Get a single header as a string from the request. |
1223
|
|
|
* |
1224
|
|
|
* @param string $name The header you want to get (case-insensitive) |
1225
|
|
|
* @return string Header values collapsed into a comma separated string. |
1226
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1227
|
|
|
*/ |
1228
|
|
|
public function getHeaderLine($name) |
1229
|
|
|
{ |
1230
|
|
|
$value = $this->getHeader($name); |
1231
|
|
|
|
1232
|
|
|
return implode(', ', $value); |
1233
|
|
|
} |
1234
|
|
|
|
1235
|
|
|
/** |
1236
|
|
|
* Get a modified request with the provided header. |
1237
|
|
|
* |
1238
|
|
|
* @param string $name The header name. |
1239
|
|
|
* @param string|array $value The header value |
1240
|
|
|
* @return static |
1241
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1242
|
|
|
*/ |
1243
|
|
View Code Duplication |
public function withHeader($name, $value) |
1244
|
|
|
{ |
1245
|
|
|
$new = clone $this; |
1246
|
|
|
$name = $this->normalizeHeaderName($name); |
1247
|
|
|
$new->_environment[$name] = $value; |
1248
|
|
|
|
1249
|
|
|
return $new; |
1250
|
|
|
} |
1251
|
|
|
|
1252
|
|
|
/** |
1253
|
|
|
* Get a modified request with the provided header. |
1254
|
|
|
* |
1255
|
|
|
* Existing header values will be retained. The provided value |
1256
|
|
|
* will be appended into the existing values. |
1257
|
|
|
* |
1258
|
|
|
* @param string $name The header name. |
1259
|
|
|
* @param string|array $value The header value |
1260
|
|
|
* @return static |
1261
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1262
|
|
|
*/ |
1263
|
|
|
public function withAddedHeader($name, $value) |
1264
|
|
|
{ |
1265
|
|
|
$new = clone $this; |
1266
|
|
|
$name = $this->normalizeHeaderName($name); |
1267
|
|
|
$existing = []; |
1268
|
|
|
if (isset($new->_environment[$name])) { |
1269
|
|
|
$existing = (array)$new->_environment[$name]; |
1270
|
|
|
} |
1271
|
|
|
$existing = array_merge($existing, (array)$value); |
1272
|
|
|
$new->_environment[$name] = $existing; |
1273
|
|
|
|
1274
|
|
|
return $new; |
1275
|
|
|
} |
1276
|
|
|
|
1277
|
|
|
/** |
1278
|
|
|
* Get a modified request without a provided header. |
1279
|
|
|
* |
1280
|
|
|
* @param string $name The header name to remove. |
1281
|
|
|
* @return static |
1282
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1283
|
|
|
*/ |
1284
|
|
View Code Duplication |
public function withoutHeader($name) |
1285
|
|
|
{ |
1286
|
|
|
$new = clone $this; |
1287
|
|
|
$name = $this->normalizeHeaderName($name); |
1288
|
|
|
unset($new->_environment[$name]); |
1289
|
|
|
|
1290
|
|
|
return $new; |
1291
|
|
|
} |
1292
|
|
|
|
1293
|
|
|
/** |
1294
|
|
|
* Get the HTTP method used for this request. |
1295
|
|
|
* |
1296
|
|
|
* @return string The name of the HTTP method used. |
1297
|
|
|
* @deprecated 3.4.0 This method will be removed in 4.0.0. Use getMethod() instead. |
1298
|
|
|
*/ |
1299
|
|
|
public function method() |
1300
|
|
|
{ |
1301
|
|
|
deprecationWarning( |
1302
|
|
|
'ServerRequest::method() is deprecated. ' . |
1303
|
|
|
'This method will be removed in 4.0.0. Use getMethod() instead.' |
1304
|
|
|
); |
1305
|
|
|
|
1306
|
|
|
return $this->getEnv('REQUEST_METHOD'); |
1307
|
|
|
} |
1308
|
|
|
|
1309
|
|
|
/** |
1310
|
|
|
* Get the HTTP method used for this request. |
1311
|
|
|
* There are a few ways to specify a method. |
1312
|
|
|
* |
1313
|
|
|
* - If your client supports it you can use native HTTP methods. |
1314
|
|
|
* - You can set the HTTP-X-Method-Override header. |
1315
|
|
|
* - You can submit an input with the name `_method` |
1316
|
|
|
* |
1317
|
|
|
* Any of these 3 approaches can be used to set the HTTP method used |
1318
|
|
|
* by CakePHP internally, and will effect the result of this method. |
1319
|
|
|
* |
1320
|
|
|
* @return string The name of the HTTP method used. |
1321
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1322
|
|
|
*/ |
1323
|
|
|
public function getMethod() |
1324
|
|
|
{ |
1325
|
|
|
return $this->getEnv('REQUEST_METHOD'); |
1326
|
|
|
} |
1327
|
|
|
|
1328
|
|
|
/** |
1329
|
|
|
* Update the request method and get a new instance. |
1330
|
|
|
* |
1331
|
|
|
* @param string $method The HTTP method to use. |
1332
|
|
|
* @return static A new instance with the updated method. |
1333
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1334
|
|
|
*/ |
1335
|
|
|
public function withMethod($method) |
1336
|
|
|
{ |
1337
|
|
|
$new = clone $this; |
1338
|
|
|
|
1339
|
|
|
if ( |
1340
|
|
|
!is_string($method) || |
1341
|
|
|
!preg_match('/^[!#$%&\'*+.^_`\|~0-9a-z-]+$/i', $method) |
1342
|
|
|
) { |
1343
|
|
|
throw new InvalidArgumentException(sprintf( |
1344
|
|
|
'Unsupported HTTP method "%s" provided', |
1345
|
|
|
$method |
1346
|
|
|
)); |
1347
|
|
|
} |
1348
|
|
|
$new->_environment['REQUEST_METHOD'] = $method; |
1349
|
|
|
|
1350
|
|
|
return $new; |
1351
|
|
|
} |
1352
|
|
|
|
1353
|
|
|
/** |
1354
|
|
|
* Get all the server environment parameters. |
1355
|
|
|
* |
1356
|
|
|
* Read all of the 'environment' or 'server' data that was |
1357
|
|
|
* used to create this request. |
1358
|
|
|
* |
1359
|
|
|
* @return array |
1360
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1361
|
|
|
*/ |
1362
|
|
|
public function getServerParams() |
1363
|
|
|
{ |
1364
|
|
|
return $this->_environment; |
1365
|
|
|
} |
1366
|
|
|
|
1367
|
|
|
/** |
1368
|
|
|
* Get all the query parameters in accordance to the PSR-7 specifications. To read specific query values |
1369
|
|
|
* use the alternative getQuery() method. |
1370
|
|
|
* |
1371
|
|
|
* @return array |
1372
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1373
|
|
|
*/ |
1374
|
|
|
public function getQueryParams() |
1375
|
|
|
{ |
1376
|
|
|
return $this->query; |
|
|
|
|
1377
|
|
|
} |
1378
|
|
|
|
1379
|
|
|
/** |
1380
|
|
|
* Update the query string data and get a new instance. |
1381
|
|
|
* |
1382
|
|
|
* @param array $query The query string data to use |
1383
|
|
|
* @return static A new instance with the updated query string data. |
1384
|
|
|
* @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. |
1385
|
|
|
*/ |
1386
|
|
|
public function withQueryParams(array $query) |
1387
|
|
|
{ |
1388
|
|
|
$new = clone $this; |
1389
|
|
|
$new->query = $query; |
|
|
|
|
1390
|
|
|
|
1391
|
|
|
return $new; |
1392
|
|
|
} |
1393
|
|
|
|
1394
|
|
|
/** |
1395
|
|
|
* Get the host that the request was handled on. |
1396
|
|
|
* |
1397
|
|
|
* @return string |
1398
|
|
|
*/ |
1399
|
|
|
public function host() |
1400
|
|
|
{ |
1401
|
|
|
if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_HOST')) { |
1402
|
|
|
return $this->getEnv('HTTP_X_FORWARDED_HOST'); |
1403
|
|
|
} |
1404
|
|
|
|
1405
|
|
|
return $this->getEnv('HTTP_HOST'); |
1406
|
|
|
} |
1407
|
|
|
|
1408
|
|
|
/** |
1409
|
|
|
* Get the port the request was handled on. |
1410
|
|
|
* |
1411
|
|
|
* @return string |
1412
|
|
|
*/ |
1413
|
|
|
public function port() |
1414
|
|
|
{ |
1415
|
|
|
if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_PORT')) { |
1416
|
|
|
return $this->getEnv('HTTP_X_FORWARDED_PORT'); |
1417
|
|
|
} |
1418
|
|
|
|
1419
|
|
|
return $this->getEnv('SERVER_PORT'); |
1420
|
|
|
} |
1421
|
|
|
|
1422
|
|
|
/** |
1423
|
|
|
* Get the current url scheme used for the request. |
1424
|
|
|
* |
1425
|
|
|
* e.g. 'http', or 'https' |
1426
|
|
|
* |
1427
|
|
|
* @return string The scheme used for the request. |
1428
|
|
|
*/ |
1429
|
|
|
public function scheme() |
1430
|
|
|
{ |
1431
|
|
|
if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_PROTO')) { |
1432
|
|
|
return $this->getEnv('HTTP_X_FORWARDED_PROTO'); |
1433
|
|
|
} |
1434
|
|
|
|
1435
|
|
|
return $this->getEnv('HTTPS') ? 'https' : 'http'; |
1436
|
|
|
} |
1437
|
|
|
|
1438
|
|
|
/** |
1439
|
|
|
* Get the domain name and include $tldLength segments of the tld. |
1440
|
|
|
* |
1441
|
|
|
* @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld. |
1442
|
|
|
* While `example.co.uk` contains 2. |
1443
|
|
|
* @return string Domain name without subdomains. |
1444
|
|
|
*/ |
1445
|
|
|
public function domain($tldLength = 1) |
1446
|
|
|
{ |
1447
|
|
|
$segments = explode('.', $this->host()); |
1448
|
|
|
$domain = array_slice($segments, -1 * ($tldLength + 1)); |
1449
|
|
|
|
1450
|
|
|
return implode('.', $domain); |
1451
|
|
|
} |
1452
|
|
|
|
1453
|
|
|
/** |
1454
|
|
|
* Get the subdomains for a host. |
1455
|
|
|
* |
1456
|
|
|
* @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld. |
1457
|
|
|
* While `example.co.uk` contains 2. |
1458
|
|
|
* @return array An array of subdomains. |
1459
|
|
|
*/ |
1460
|
|
|
public function subdomains($tldLength = 1) |
1461
|
|
|
{ |
1462
|
|
|
$segments = explode('.', $this->host()); |
1463
|
|
|
|
1464
|
|
|
return array_slice($segments, 0, -1 * ($tldLength + 1)); |
1465
|
|
|
} |
1466
|
|
|
|
1467
|
|
|
/** |
1468
|
|
|
* Find out which content types the client accepts or check if they accept a |
1469
|
|
|
* particular type of content. |
1470
|
|
|
* |
1471
|
|
|
* #### Get all types: |
1472
|
|
|
* |
1473
|
|
|
* ``` |
1474
|
|
|
* $this->request->accepts(); |
1475
|
|
|
* ``` |
1476
|
|
|
* |
1477
|
|
|
* #### Check for a single type: |
1478
|
|
|
* |
1479
|
|
|
* ``` |
1480
|
|
|
* $this->request->accepts('application/json'); |
1481
|
|
|
* ``` |
1482
|
|
|
* |
1483
|
|
|
* This method will order the returned content types by the preference values indicated |
1484
|
|
|
* by the client. |
1485
|
|
|
* |
1486
|
|
|
* @param string|null $type The content type to check for. Leave null to get all types a client accepts. |
1487
|
|
|
* @return array|bool Either an array of all the types the client accepts or a boolean if they accept the |
1488
|
|
|
* provided type. |
1489
|
|
|
*/ |
1490
|
|
|
public function accepts($type = null) |
1491
|
|
|
{ |
1492
|
|
|
$raw = $this->parseAccept(); |
1493
|
|
|
$accept = []; |
1494
|
|
|
foreach ($raw as $types) { |
1495
|
|
|
$accept = array_merge($accept, $types); |
1496
|
|
|
} |
1497
|
|
|
if ($type === null) { |
1498
|
|
|
return $accept; |
1499
|
|
|
} |
1500
|
|
|
|
1501
|
|
|
return in_array($type, $accept, true); |
1502
|
|
|
} |
1503
|
|
|
|
1504
|
|
|
/** |
1505
|
|
|
* Parse the HTTP_ACCEPT header and return a sorted array with content types |
1506
|
|
|
* as the keys, and pref values as the values. |
1507
|
|
|
* |
1508
|
|
|
* Generally you want to use Cake\Http\ServerRequest::accept() to get a simple list |
1509
|
|
|
* of the accepted content types. |
1510
|
|
|
* |
1511
|
|
|
* @return array An array of prefValue => [content/types] |
1512
|
|
|
*/ |
1513
|
|
|
public function parseAccept() |
1514
|
|
|
{ |
1515
|
|
|
return $this->_parseAcceptWithQualifier($this->getHeaderLine('Accept')); |
1516
|
|
|
} |
1517
|
|
|
|
1518
|
|
|
/** |
1519
|
|
|
* Get the languages accepted by the client, or check if a specific language is accepted. |
1520
|
|
|
* |
1521
|
|
|
* Get the list of accepted languages: |
1522
|
|
|
* |
1523
|
|
|
* ``` \Cake\Http\ServerRequest::acceptLanguage(); ``` |
1524
|
|
|
* |
1525
|
|
|
* Check if a specific language is accepted: |
1526
|
|
|
* |
1527
|
|
|
* ``` \Cake\Http\ServerRequest::acceptLanguage('es-es'); ``` |
1528
|
|
|
* |
1529
|
|
|
* @param string|null $language The language to test. |
1530
|
|
|
* @return array|bool If a $language is provided, a boolean. Otherwise the array of accepted languages. |
1531
|
|
|
*/ |
1532
|
|
|
public function acceptLanguage($language = null) |
1533
|
|
|
{ |
1534
|
|
|
$raw = $this->_parseAcceptWithQualifier($this->getHeaderLine('Accept-Language')); |
1535
|
|
|
$accept = []; |
1536
|
|
|
foreach ($raw as $languages) { |
1537
|
|
|
foreach ($languages as &$lang) { |
1538
|
|
|
if (strpos($lang, '_')) { |
1539
|
|
|
$lang = str_replace('_', '-', $lang); |
1540
|
|
|
} |
1541
|
|
|
$lang = strtolower($lang); |
1542
|
|
|
} |
1543
|
|
|
$accept = array_merge($accept, $languages); |
1544
|
|
|
} |
1545
|
|
|
if ($language === null) { |
1546
|
|
|
return $accept; |
1547
|
|
|
} |
1548
|
|
|
|
1549
|
|
|
return in_array(strtolower($language), $accept, true); |
1550
|
|
|
} |
1551
|
|
|
|
1552
|
|
|
/** |
1553
|
|
|
* Parse Accept* headers with qualifier options. |
1554
|
|
|
* |
1555
|
|
|
* Only qualifiers will be extracted, any other accept extensions will be |
1556
|
|
|
* discarded as they are not frequently used. |
1557
|
|
|
* |
1558
|
|
|
* @param string $header Header to parse. |
1559
|
|
|
* @return array |
1560
|
|
|
*/ |
1561
|
|
|
protected function _parseAcceptWithQualifier($header) |
1562
|
|
|
{ |
1563
|
|
|
$accept = []; |
1564
|
|
|
$headers = explode(',', $header); |
1565
|
|
|
foreach (array_filter($headers) as $value) { |
1566
|
|
|
$prefValue = '1.0'; |
1567
|
|
|
$value = trim($value); |
1568
|
|
|
|
1569
|
|
|
$semiPos = strpos($value, ';'); |
1570
|
|
|
if ($semiPos !== false) { |
1571
|
|
|
$params = explode(';', $value); |
1572
|
|
|
$value = trim($params[0]); |
1573
|
|
|
foreach ($params as $param) { |
1574
|
|
|
$qPos = strpos($param, 'q='); |
1575
|
|
|
if ($qPos !== false) { |
1576
|
|
|
$prefValue = substr($param, $qPos + 2); |
1577
|
|
|
} |
1578
|
|
|
} |
1579
|
|
|
} |
1580
|
|
|
|
1581
|
|
|
if (!isset($accept[$prefValue])) { |
1582
|
|
|
$accept[$prefValue] = []; |
1583
|
|
|
} |
1584
|
|
|
if ($prefValue) { |
1585
|
|
|
$accept[$prefValue][] = $value; |
1586
|
|
|
} |
1587
|
|
|
} |
1588
|
|
|
krsort($accept); |
1589
|
|
|
|
1590
|
|
|
return $accept; |
1591
|
|
|
} |
1592
|
|
|
|
1593
|
|
|
/** |
1594
|
|
|
* Provides a read accessor for `$this->query`. |
1595
|
|
|
* Allows you to use a `Hash::get()` compatible syntax for reading post data. |
1596
|
|
|
* |
1597
|
|
|
* @param string|null $name Query string variable name or null to read all. |
1598
|
|
|
* @return string|array|null The value being read |
1599
|
|
|
* @deprecated 3.4.0 Use getQuery() or the PSR-7 getQueryParams() and withQueryParams() methods instead. |
1600
|
|
|
*/ |
1601
|
|
|
public function query($name = null) |
1602
|
|
|
{ |
1603
|
|
|
deprecationWarning( |
1604
|
|
|
'ServerRequest::query() is deprecated. ' . |
1605
|
|
|
'Use getQuery() or the PSR-7 getQueryParams() and withQueryParams() methods instead.' |
1606
|
|
|
); |
1607
|
|
|
|
1608
|
|
|
if ($name === null) { |
1609
|
|
|
return $this->query; |
|
|
|
|
1610
|
|
|
} |
1611
|
|
|
|
1612
|
|
|
return $this->getQuery($name); |
1613
|
|
|
} |
1614
|
|
|
|
1615
|
|
|
/** |
1616
|
|
|
* Read a specific query value or dotted path. |
1617
|
|
|
* |
1618
|
|
|
* Developers are encouraged to use getQueryParams() when possible as it is PSR-7 compliant, and this method |
1619
|
|
|
* is not. |
1620
|
|
|
* |
1621
|
|
|
* ### PSR-7 Alternative |
1622
|
|
|
* |
1623
|
|
|
* ``` |
1624
|
|
|
* $value = Hash::get($request->getQueryParams(), 'Post.id', null); |
1625
|
|
|
* ``` |
1626
|
|
|
* |
1627
|
|
|
* @param string|null $name The name or dotted path to the query param or null to read all. |
1628
|
|
|
* @param mixed $default The default value if the named parameter is not set, and $name is not null. |
1629
|
|
|
* @return array|string|null Query data. |
1630
|
|
|
* @see ServerRequest::getQueryParams() |
1631
|
|
|
*/ |
1632
|
|
|
public function getQuery($name = null, $default = null) |
1633
|
|
|
{ |
1634
|
|
|
if ($name === null) { |
1635
|
|
|
return $this->query; |
|
|
|
|
1636
|
|
|
} |
1637
|
|
|
|
1638
|
|
|
return Hash::get($this->query, $name, $default); |
|
|
|
|
1639
|
|
|
} |
1640
|
|
|
|
1641
|
|
|
/** |
1642
|
|
|
* Provides a read/write accessor for `$this->data`. |
1643
|
|
|
* Allows you to use a `Hash::get()` compatible syntax for reading post data. |
1644
|
|
|
* |
1645
|
|
|
* ### Reading values. |
1646
|
|
|
* |
1647
|
|
|
* ``` |
1648
|
|
|
* $request->data('Post.title'); |
1649
|
|
|
* ``` |
1650
|
|
|
* |
1651
|
|
|
* When reading values you will get `null` for keys/values that do not exist. |
1652
|
|
|
* |
1653
|
|
|
* ### Writing values |
1654
|
|
|
* |
1655
|
|
|
* ``` |
1656
|
|
|
* $request->data('Post.title', 'New post!'); |
1657
|
|
|
* ``` |
1658
|
|
|
* |
1659
|
|
|
* You can write to any value, even paths/keys that do not exist, and the arrays |
1660
|
|
|
* will be created for you. |
1661
|
|
|
* |
1662
|
|
|
* @param string|null $name Dot separated name of the value to read/write |
1663
|
|
|
* @param mixed ...$args The data to set (deprecated) |
1664
|
|
|
* @return mixed|$this Either the value being read, or this so you can chain consecutive writes. |
1665
|
|
|
* @deprecated 3.4.0 Use withData() and getData() or getParsedBody() instead. |
1666
|
|
|
*/ |
1667
|
|
|
public function data($name = null, ...$args) |
1668
|
|
|
{ |
1669
|
|
|
deprecationWarning( |
1670
|
|
|
'ServerRequest::data() is deprecated. ' . |
1671
|
|
|
'Use withData() and getData() or getParsedBody() instead.' |
1672
|
|
|
); |
1673
|
|
|
|
1674
|
|
View Code Duplication |
if (count($args) === 1) { |
1675
|
|
|
$this->data = Hash::insert($this->data, $name, $args[0]); |
|
|
|
|
1676
|
|
|
|
1677
|
|
|
return $this; |
1678
|
|
|
} |
1679
|
|
|
if ($name !== null) { |
1680
|
|
|
return Hash::get($this->data, $name); |
|
|
|
|
1681
|
|
|
} |
1682
|
|
|
|
1683
|
|
|
return $this->data; |
|
|
|
|
1684
|
|
|
} |
1685
|
|
|
|
1686
|
|
|
/** |
1687
|
|
|
* Provides a safe accessor for request data. Allows |
1688
|
|
|
* you to use Hash::get() compatible paths. |
1689
|
|
|
* |
1690
|
|
|
* ### Reading values. |
1691
|
|
|
* |
1692
|
|
|
* ``` |
1693
|
|
|
* // get all data |
1694
|
|
|
* $request->getData(); |
1695
|
|
|
* |
1696
|
|
|
* // Read a specific field. |
1697
|
|
|
* $request->getData('Post.title'); |
1698
|
|
|
* |
1699
|
|
|
* // With a default value. |
1700
|
|
|
* $request->getData('Post.not there', 'default value'); |
1701
|
|
|
* ``` |
1702
|
|
|
* |
1703
|
|
|
* When reading values you will get `null` for keys/values that do not exist. |
1704
|
|
|
* |
1705
|
|
|
* @param string|null $name Dot separated name of the value to read. Or null to read all data. |
1706
|
|
|
* @param mixed $default The default data. |
1707
|
|
|
* @return array|string|null The value being read. |
1708
|
|
|
*/ |
1709
|
|
|
public function getData($name = null, $default = null) |
1710
|
|
|
{ |
1711
|
|
|
if ($name === null) { |
1712
|
|
|
return $this->data; |
|
|
|
|
1713
|
|
|
} |
1714
|
|
|
if (!is_array($this->data) && $name) { |
|
|
|
|
1715
|
|
|
return $default; |
1716
|
|
|
} |
1717
|
|
|
|
1718
|
|
|
return Hash::get($this->data, $name, $default); |
|
|
|
|
1719
|
|
|
} |
1720
|
|
|
|
1721
|
|
|
/** |
1722
|
|
|
* Safely access the values in $this->params. |
1723
|
|
|
* |
1724
|
|
|
* @param string $name The name of the parameter to get. |
1725
|
|
|
* @param mixed ...$args Value to set (deprecated). |
1726
|
|
|
* @return mixed|$this The value of the provided parameter. Will |
1727
|
|
|
* return false if the parameter doesn't exist or is falsey. |
1728
|
|
|
* @deprecated 3.4.0 Use getParam() and withParam() instead. |
1729
|
|
|
*/ |
1730
|
|
|
public function param($name, ...$args) |
1731
|
|
|
{ |
1732
|
|
|
deprecationWarning( |
1733
|
|
|
'ServerRequest::param() is deprecated. ' . |
1734
|
|
|
'Use getParam() and withParam() instead.' |
1735
|
|
|
); |
1736
|
|
|
|
1737
|
|
View Code Duplication |
if (count($args) === 1) { |
1738
|
|
|
$this->params = Hash::insert($this->params, $name, $args[0]); |
|
|
|
|
1739
|
|
|
|
1740
|
|
|
return $this; |
1741
|
|
|
} |
1742
|
|
|
|
1743
|
|
|
return $this->getParam($name); |
1744
|
|
|
} |
1745
|
|
|
|
1746
|
|
|
/** |
1747
|
|
|
* Read data from `php://input`. Useful when interacting with XML or JSON |
1748
|
|
|
* request body content. |
1749
|
|
|
* |
1750
|
|
|
* Getting input with a decoding function: |
1751
|
|
|
* |
1752
|
|
|
* ``` |
1753
|
|
|
* $this->request->input('json_decode'); |
1754
|
|
|
* ``` |
1755
|
|
|
* |
1756
|
|
|
* Getting input using a decoding function, and additional params: |
1757
|
|
|
* |
1758
|
|
|
* ``` |
1759
|
|
|
* $this->request->input('Xml::build', ['return' => 'DOMDocument']); |
1760
|
|
|
* ``` |
1761
|
|
|
* |
1762
|
|
|
* Any additional parameters are applied to the callback in the order they are given. |
1763
|
|
|
* |
1764
|
|
|
* @param string|null $callback A decoding callback that will convert the string data to another |
1765
|
|
|
* representation. Leave empty to access the raw input data. You can also |
1766
|
|
|
* supply additional parameters for the decoding callback using var args, see above. |
1767
|
|
|
* @param array ...$args The additional arguments |
1768
|
|
|
* @return string The decoded/processed request data. |
1769
|
|
|
*/ |
1770
|
|
|
public function input($callback = null, ...$args) |
1771
|
|
|
{ |
1772
|
|
|
$this->stream->rewind(); |
1773
|
|
|
$input = $this->stream->getContents(); |
1774
|
|
|
if ($callback) { |
1775
|
|
|
array_unshift($args, $input); |
1776
|
|
|
|
1777
|
|
|
return call_user_func_array($callback, $args); |
1778
|
|
|
} |
1779
|
|
|
|
1780
|
|
|
return $input; |
1781
|
|
|
} |
1782
|
|
|
|
1783
|
|
|
/** |
1784
|
|
|
* Read cookie data from the request's cookie data. |
1785
|
|
|
* |
1786
|
|
|
* @param string $key The key you want to read. |
1787
|
|
|
* @return string|null Either the cookie value, or null if the value doesn't exist. |
1788
|
|
|
* @deprecated 3.4.0 Use getCookie() instead. |
1789
|
|
|
*/ |
1790
|
|
|
public function cookie($key) |
1791
|
|
|
{ |
1792
|
|
|
deprecationWarning( |
1793
|
|
|
'ServerRequest::cookie() is deprecated. ' . |
1794
|
|
|
'Use getCookie() instead.' |
1795
|
|
|
); |
1796
|
|
|
|
1797
|
|
|
if (isset($this->cookies[$key])) { |
|
|
|
|
1798
|
|
|
return $this->cookies[$key]; |
|
|
|
|
1799
|
|
|
} |
1800
|
|
|
|
1801
|
|
|
return null; |
1802
|
|
|
} |
1803
|
|
|
|
1804
|
|
|
/** |
1805
|
|
|
* Read cookie data from the request's cookie data. |
1806
|
|
|
* |
1807
|
|
|
* @param string $key The key or dotted path you want to read. |
1808
|
|
|
* @param string $default The default value if the cookie is not set. |
1809
|
|
|
* @return string|array|null Either the cookie value, or null if the value doesn't exist. |
1810
|
|
|
*/ |
1811
|
|
|
public function getCookie($key, $default = null) |
1812
|
|
|
{ |
1813
|
|
|
return Hash::get($this->cookies, $key, $default); |
|
|
|
|
1814
|
|
|
} |
1815
|
|
|
|
1816
|
|
|
/** |
1817
|
|
|
* Get a cookie collection based on the request's cookies |
1818
|
|
|
* |
1819
|
|
|
* The CookieCollection lets you interact with request cookies using |
1820
|
|
|
* `\Cake\Http\Cookie\Cookie` objects and can make converting request cookies |
1821
|
|
|
* into response cookies easier. |
1822
|
|
|
* |
1823
|
|
|
* This method will create a new cookie collection each time it is called. |
1824
|
|
|
* This is an optimization that allows fewer objects to be allocated until |
1825
|
|
|
* the more complex CookieCollection is needed. In general you should prefer |
1826
|
|
|
* `getCookie()` and `getCookieParams()` over this method. Using a CookieCollection |
1827
|
|
|
* is ideal if your cookies contain complex JSON encoded data. |
1828
|
|
|
* |
1829
|
|
|
* @return \Cake\Http\Cookie\CookieCollection |
1830
|
|
|
*/ |
1831
|
|
|
public function getCookieCollection() |
1832
|
|
|
{ |
1833
|
|
|
return CookieCollection::createFromServerRequest($this); |
1834
|
|
|
} |
1835
|
|
|
|
1836
|
|
|
/** |
1837
|
|
|
* Replace the cookies in the request with those contained in |
1838
|
|
|
* the provided CookieCollection. |
1839
|
|
|
* |
1840
|
|
|
* @param \Cake\Http\Cookie\CookieCollection $cookies The cookie collection |
1841
|
|
|
* @return static |
1842
|
|
|
*/ |
1843
|
|
|
public function withCookieCollection(CookieCollection $cookies) |
1844
|
|
|
{ |
1845
|
|
|
$new = clone $this; |
1846
|
|
|
$values = []; |
1847
|
|
|
foreach ($cookies as $cookie) { |
1848
|
|
|
$values[$cookie->getName()] = $cookie->getValue(); |
1849
|
|
|
} |
1850
|
|
|
$new->cookies = $values; |
|
|
|
|
1851
|
|
|
|
1852
|
|
|
return $new; |
1853
|
|
|
} |
1854
|
|
|
|
1855
|
|
|
/** |
1856
|
|
|
* Get all the cookie data from the request. |
1857
|
|
|
* |
1858
|
|
|
* @return array An array of cookie data. |
1859
|
|
|
*/ |
1860
|
|
|
public function getCookieParams() |
1861
|
|
|
{ |
1862
|
|
|
return $this->cookies; |
|
|
|
|
1863
|
|
|
} |
1864
|
|
|
|
1865
|
|
|
/** |
1866
|
|
|
* Replace the cookies and get a new request instance. |
1867
|
|
|
* |
1868
|
|
|
* @param array $cookies The new cookie data to use. |
1869
|
|
|
* @return static |
1870
|
|
|
*/ |
1871
|
|
|
public function withCookieParams(array $cookies) |
1872
|
|
|
{ |
1873
|
|
|
$new = clone $this; |
1874
|
|
|
$new->cookies = $cookies; |
|
|
|
|
1875
|
|
|
|
1876
|
|
|
return $new; |
1877
|
|
|
} |
1878
|
|
|
|
1879
|
|
|
/** |
1880
|
|
|
* Get the parsed request body data. |
1881
|
|
|
* |
1882
|
|
|
* If the request Content-Type is either application/x-www-form-urlencoded |
1883
|
|
|
* or multipart/form-data, and the request method is POST, this will be the |
1884
|
|
|
* post data. For other content types, it may be the deserialized request |
1885
|
|
|
* body. |
1886
|
|
|
* |
1887
|
|
|
* @return object|array|null The deserialized body parameters, if any. |
1888
|
|
|
* These will typically be an array or object. |
1889
|
|
|
*/ |
1890
|
|
|
public function getParsedBody() |
1891
|
|
|
{ |
1892
|
|
|
return $this->data; |
|
|
|
|
1893
|
|
|
} |
1894
|
|
|
|
1895
|
|
|
/** |
1896
|
|
|
* Update the parsed body and get a new instance. |
1897
|
|
|
* |
1898
|
|
|
* @param object|array|null $data The deserialized body data. This will |
1899
|
|
|
* typically be in an array or object. |
1900
|
|
|
* @return static |
1901
|
|
|
*/ |
1902
|
|
|
public function withParsedBody($data) |
1903
|
|
|
{ |
1904
|
|
|
$new = clone $this; |
1905
|
|
|
$new->data = $data; |
|
|
|
|
1906
|
|
|
|
1907
|
|
|
return $new; |
1908
|
|
|
} |
1909
|
|
|
|
1910
|
|
|
/** |
1911
|
|
|
* Retrieves the HTTP protocol version as a string. |
1912
|
|
|
* |
1913
|
|
|
* @return string HTTP protocol version. |
1914
|
|
|
*/ |
1915
|
|
|
public function getProtocolVersion() |
1916
|
|
|
{ |
1917
|
|
|
if ($this->protocol) { |
1918
|
|
|
return $this->protocol; |
1919
|
|
|
} |
1920
|
|
|
|
1921
|
|
|
// Lazily populate this data as it is generally not used. |
1922
|
|
|
preg_match('/^HTTP\/([\d.]+)$/', $this->getEnv('SERVER_PROTOCOL'), $match); |
1923
|
|
|
$protocol = '1.1'; |
1924
|
|
|
if (isset($match[1])) { |
1925
|
|
|
$protocol = $match[1]; |
1926
|
|
|
} |
1927
|
|
|
$this->protocol = $protocol; |
1928
|
|
|
|
1929
|
|
|
return $this->protocol; |
1930
|
|
|
} |
1931
|
|
|
|
1932
|
|
|
/** |
1933
|
|
|
* Return an instance with the specified HTTP protocol version. |
1934
|
|
|
* |
1935
|
|
|
* The version string MUST contain only the HTTP version number (e.g., |
1936
|
|
|
* "1.1", "1.0"). |
1937
|
|
|
* |
1938
|
|
|
* @param string $version HTTP protocol version |
1939
|
|
|
* @return static |
1940
|
|
|
*/ |
1941
|
|
|
public function withProtocolVersion($version) |
1942
|
|
|
{ |
1943
|
|
|
if (!preg_match('/^(1\.[01]|2)$/', $version)) { |
1944
|
|
|
throw new InvalidArgumentException("Unsupported protocol version '{$version}' provided"); |
1945
|
|
|
} |
1946
|
|
|
$new = clone $this; |
1947
|
|
|
$new->protocol = $version; |
1948
|
|
|
|
1949
|
|
|
return $new; |
1950
|
|
|
} |
1951
|
|
|
|
1952
|
|
|
/** |
1953
|
|
|
* Get a value from the request's environment data. |
1954
|
|
|
* Fallback to using env() if the key is not set in the $environment property. |
1955
|
|
|
* |
1956
|
|
|
* @param string $key The key you want to read from. |
1957
|
|
|
* @param string|null $default Default value when trying to retrieve an environment |
1958
|
|
|
* variable's value that does not exist. |
1959
|
|
|
* @return string|null Either the environment value, or null if the value doesn't exist. |
1960
|
|
|
*/ |
1961
|
|
|
public function getEnv($key, $default = null) |
1962
|
|
|
{ |
1963
|
|
|
$key = strtoupper($key); |
1964
|
|
|
if (!array_key_exists($key, $this->_environment)) { |
1965
|
|
|
$this->_environment[$key] = env($key); |
1966
|
|
|
} |
1967
|
|
|
|
1968
|
|
|
return $this->_environment[$key] !== null ? $this->_environment[$key] : $default; |
1969
|
|
|
} |
1970
|
|
|
|
1971
|
|
|
/** |
1972
|
|
|
* Update the request with a new environment data element. |
1973
|
|
|
* |
1974
|
|
|
* Returns an updated request object. This method returns |
1975
|
|
|
* a *new* request object and does not mutate the request in-place. |
1976
|
|
|
* |
1977
|
|
|
* @param string $key The key you want to write to. |
1978
|
|
|
* @param string $value Value to set |
1979
|
|
|
* @return static |
1980
|
|
|
*/ |
1981
|
|
|
public function withEnv($key, $value) |
1982
|
|
|
{ |
1983
|
|
|
$new = clone $this; |
1984
|
|
|
$new->_environment[$key] = $value; |
1985
|
|
|
$new->clearDetectorCache(); |
1986
|
|
|
|
1987
|
|
|
return $new; |
1988
|
|
|
} |
1989
|
|
|
|
1990
|
|
|
/** |
1991
|
|
|
* Get/Set value from the request's environment data. |
1992
|
|
|
* Fallback to using env() if key not set in $environment property. |
1993
|
|
|
* |
1994
|
|
|
* @deprecated 3.5.0 Use getEnv()/withEnv() instead. |
1995
|
|
|
* @param string $key The key you want to read/write from/to. |
1996
|
|
|
* @param string|null $value Value to set. Default null. |
1997
|
|
|
* @param string|null $default Default value when trying to retrieve an environment |
1998
|
|
|
* variable's value that does not exist. The value parameter must be null. |
1999
|
|
|
* @return $this|string|null This instance if used as setter, |
2000
|
|
|
* if used as getter either the environment value, or null if the value doesn't exist. |
2001
|
|
|
*/ |
2002
|
|
|
public function env($key, $value = null, $default = null) |
2003
|
|
|
{ |
2004
|
|
|
deprecationWarning( |
2005
|
|
|
'ServerRequest::env() is deprecated. ' . |
2006
|
|
|
'Use getEnv()/withEnv() instead.' |
2007
|
|
|
); |
2008
|
|
|
|
2009
|
|
|
if ($value !== null) { |
2010
|
|
|
$this->_environment[$key] = $value; |
2011
|
|
|
$this->clearDetectorCache(); |
2012
|
|
|
|
2013
|
|
|
return $this; |
2014
|
|
|
} |
2015
|
|
|
|
2016
|
|
|
$key = strtoupper($key); |
2017
|
|
|
if (!array_key_exists($key, $this->_environment)) { |
2018
|
|
|
$this->_environment[$key] = env($key); |
2019
|
|
|
} |
2020
|
|
|
|
2021
|
|
|
return $this->_environment[$key] !== null ? $this->_environment[$key] : $default; |
2022
|
|
|
} |
2023
|
|
|
|
2024
|
|
|
/** |
2025
|
|
|
* Allow only certain HTTP request methods, if the request method does not match |
2026
|
|
|
* a 405 error will be shown and the required "Allow" response header will be set. |
2027
|
|
|
* |
2028
|
|
|
* Example: |
2029
|
|
|
* |
2030
|
|
|
* $this->request->allowMethod('post'); |
2031
|
|
|
* or |
2032
|
|
|
* $this->request->allowMethod(['post', 'delete']); |
2033
|
|
|
* |
2034
|
|
|
* If the request would be GET, response header "Allow: POST, DELETE" will be set |
2035
|
|
|
* and a 405 error will be returned. |
2036
|
|
|
* |
2037
|
|
|
* @param string|array $methods Allowed HTTP request methods. |
2038
|
|
|
* @return bool true |
2039
|
|
|
* @throws \Cake\Http\Exception\MethodNotAllowedException |
2040
|
|
|
*/ |
2041
|
|
|
public function allowMethod($methods) |
2042
|
|
|
{ |
2043
|
|
|
$methods = (array)$methods; |
2044
|
|
|
foreach ($methods as $method) { |
2045
|
|
|
if ($this->is($method)) { |
2046
|
|
|
return true; |
2047
|
|
|
} |
2048
|
|
|
} |
2049
|
|
|
$allowed = strtoupper(implode(', ', $methods)); |
2050
|
|
|
$e = new MethodNotAllowedException(); |
2051
|
|
|
$e->responseHeader('Allow', $allowed); |
2052
|
|
|
throw $e; |
2053
|
|
|
} |
2054
|
|
|
|
2055
|
|
|
/** |
2056
|
|
|
* Read data from php://input, mocked in tests. |
2057
|
|
|
* |
2058
|
|
|
* @return string contents of php://input |
2059
|
|
|
*/ |
2060
|
|
|
protected function _readInput() |
2061
|
|
|
{ |
2062
|
|
|
if (empty($this->_input)) { |
2063
|
|
|
$fh = fopen('php://input', 'rb'); |
2064
|
|
|
$content = stream_get_contents($fh); |
2065
|
|
|
fclose($fh); |
2066
|
|
|
$this->_input = $content; |
2067
|
|
|
} |
2068
|
|
|
|
2069
|
|
|
return $this->_input; |
2070
|
|
|
} |
2071
|
|
|
|
2072
|
|
|
/** |
2073
|
|
|
* Modify data originally from `php://input`. Useful for altering json/xml data |
2074
|
|
|
* in middleware or DispatcherFilters before it gets to RequestHandlerComponent |
2075
|
|
|
* |
2076
|
|
|
* @param string $input A string to replace original parsed data from input() |
2077
|
|
|
* @return void |
2078
|
|
|
* @deprecated 3.4.0 This method will be removed in 4.0.0. Use withBody() instead. |
2079
|
|
|
*/ |
2080
|
|
|
public function setInput($input) |
2081
|
|
|
{ |
2082
|
|
|
deprecationWarning( |
2083
|
|
|
'This method will be removed in 4.0.0.' . |
2084
|
|
|
'Use withBody() instead.' |
2085
|
|
|
); |
2086
|
|
|
|
2087
|
|
|
$stream = new Stream('php://memory', 'rw'); |
2088
|
|
|
$stream->write($input); |
2089
|
|
|
$stream->rewind(); |
2090
|
|
|
$this->stream = $stream; |
2091
|
|
|
} |
2092
|
|
|
|
2093
|
|
|
/** |
2094
|
|
|
* Update the request with a new request data element. |
2095
|
|
|
* |
2096
|
|
|
* Returns an updated request object. This method returns |
2097
|
|
|
* a *new* request object and does not mutate the request in-place. |
2098
|
|
|
* |
2099
|
|
|
* Use `withParsedBody()` if you need to replace the all request data. |
2100
|
|
|
* |
2101
|
|
|
* @param string $name The dot separated path to insert $value at. |
2102
|
|
|
* @param mixed $value The value to insert into the request data. |
2103
|
|
|
* @return static |
2104
|
|
|
*/ |
2105
|
|
|
public function withData($name, $value) |
2106
|
|
|
{ |
2107
|
|
|
$copy = clone $this; |
2108
|
|
|
$copy->data = Hash::insert($copy->data, $name, $value); |
|
|
|
|
2109
|
|
|
|
2110
|
|
|
return $copy; |
2111
|
|
|
} |
2112
|
|
|
|
2113
|
|
|
/** |
2114
|
|
|
* Update the request removing a data element. |
2115
|
|
|
* |
2116
|
|
|
* Returns an updated request object. This method returns |
2117
|
|
|
* a *new* request object and does not mutate the request in-place. |
2118
|
|
|
* |
2119
|
|
|
* @param string $name The dot separated path to remove. |
2120
|
|
|
* @return static |
2121
|
|
|
*/ |
2122
|
|
|
public function withoutData($name) |
2123
|
|
|
{ |
2124
|
|
|
$copy = clone $this; |
2125
|
|
|
$copy->data = Hash::remove($copy->data, $name); |
|
|
|
|
2126
|
|
|
|
2127
|
|
|
return $copy; |
2128
|
|
|
} |
2129
|
|
|
|
2130
|
|
|
/** |
2131
|
|
|
* Update the request with a new routing parameter |
2132
|
|
|
* |
2133
|
|
|
* Returns an updated request object. This method returns |
2134
|
|
|
* a *new* request object and does not mutate the request in-place. |
2135
|
|
|
* |
2136
|
|
|
* @param string $name The dot separated path to insert $value at. |
2137
|
|
|
* @param mixed $value The value to insert into the the request parameters. |
2138
|
|
|
* @return static |
2139
|
|
|
*/ |
2140
|
|
|
public function withParam($name, $value) |
2141
|
|
|
{ |
2142
|
|
|
$copy = clone $this; |
2143
|
|
|
$copy->params = Hash::insert($copy->params, $name, $value); |
|
|
|
|
2144
|
|
|
|
2145
|
|
|
return $copy; |
2146
|
|
|
} |
2147
|
|
|
|
2148
|
|
|
/** |
2149
|
|
|
* Safely access the values in $this->params. |
2150
|
|
|
* |
2151
|
|
|
* @param string $name The name or dotted path to parameter. |
2152
|
|
|
* @param mixed $default The default value if `$name` is not set. Default `false`. |
2153
|
|
|
* @return mixed |
2154
|
|
|
*/ |
2155
|
|
|
public function getParam($name, $default = false) |
2156
|
|
|
{ |
2157
|
|
|
return Hash::get($this->params, $name, $default); |
|
|
|
|
2158
|
|
|
} |
2159
|
|
|
|
2160
|
|
|
/** |
2161
|
|
|
* Return an instance with the specified request attribute. |
2162
|
|
|
* |
2163
|
|
|
* @param string $name The attribute name. |
2164
|
|
|
* @param mixed $value The value of the attribute. |
2165
|
|
|
* @return static |
2166
|
|
|
*/ |
2167
|
|
|
public function withAttribute($name, $value) |
2168
|
|
|
{ |
2169
|
|
|
$new = clone $this; |
2170
|
|
|
if (in_array($name, $this->emulatedAttributes, true)) { |
2171
|
|
|
$new->{$name} = $value; |
2172
|
|
|
} else { |
2173
|
|
|
$new->attributes[$name] = $value; |
2174
|
|
|
} |
2175
|
|
|
|
2176
|
|
|
return $new; |
2177
|
|
|
} |
2178
|
|
|
|
2179
|
|
|
/** |
2180
|
|
|
* Return an instance without the specified request attribute. |
2181
|
|
|
* |
2182
|
|
|
* @param string $name The attribute name. |
2183
|
|
|
* @return static |
2184
|
|
|
* @throws \InvalidArgumentException |
2185
|
|
|
*/ |
2186
|
|
|
public function withoutAttribute($name) |
2187
|
|
|
{ |
2188
|
|
|
$new = clone $this; |
2189
|
|
|
if (in_array($name, $this->emulatedAttributes, true)) { |
2190
|
|
|
throw new InvalidArgumentException( |
2191
|
|
|
"You cannot unset '$name'. It is a required CakePHP attribute." |
2192
|
|
|
); |
2193
|
|
|
} |
2194
|
|
|
unset($new->attributes[$name]); |
2195
|
|
|
|
2196
|
|
|
return $new; |
2197
|
|
|
} |
2198
|
|
|
|
2199
|
|
|
/** |
2200
|
|
|
* Read an attribute from the request, or get the default |
2201
|
|
|
* |
2202
|
|
|
* @param string $name The attribute name. |
2203
|
|
|
* @param mixed|null $default The default value if the attribute has not been set. |
2204
|
|
|
* @return mixed |
2205
|
|
|
*/ |
2206
|
|
|
public function getAttribute($name, $default = null) |
2207
|
|
|
{ |
2208
|
|
|
if (in_array($name, $this->emulatedAttributes, true)) { |
2209
|
|
|
return $this->{$name}; |
2210
|
|
|
} |
2211
|
|
|
if (array_key_exists($name, $this->attributes)) { |
2212
|
|
|
return $this->attributes[$name]; |
2213
|
|
|
} |
2214
|
|
|
|
2215
|
|
|
return $default; |
2216
|
|
|
} |
2217
|
|
|
|
2218
|
|
|
/** |
2219
|
|
|
* Get all the attributes in the request. |
2220
|
|
|
* |
2221
|
|
|
* This will include the params, webroot, base, and here attributes that CakePHP |
2222
|
|
|
* provides. |
2223
|
|
|
* |
2224
|
|
|
* @return array |
2225
|
|
|
*/ |
2226
|
|
|
public function getAttributes() |
2227
|
|
|
{ |
2228
|
|
|
$emulated = [ |
2229
|
|
|
'params' => $this->params, |
|
|
|
|
2230
|
|
|
'webroot' => $this->webroot, |
|
|
|
|
2231
|
|
|
'base' => $this->base, |
|
|
|
|
2232
|
|
|
'here' => $this->here, |
|
|
|
|
2233
|
|
|
]; |
2234
|
|
|
|
2235
|
|
|
return $this->attributes + $emulated; |
2236
|
|
|
} |
2237
|
|
|
|
2238
|
|
|
/** |
2239
|
|
|
* Get the uploaded file from a dotted path. |
2240
|
|
|
* |
2241
|
|
|
* @param string $path The dot separated path to the file you want. |
2242
|
|
|
* @return \Psr\Http\Message\UploadedFileInterface|null |
2243
|
|
|
*/ |
2244
|
|
|
public function getUploadedFile($path) |
2245
|
|
|
{ |
2246
|
|
|
$file = Hash::get($this->uploadedFiles, $path); |
2247
|
|
|
if (!$file instanceof UploadedFile) { |
2248
|
|
|
return null; |
2249
|
|
|
} |
2250
|
|
|
|
2251
|
|
|
return $file; |
2252
|
|
|
} |
2253
|
|
|
|
2254
|
|
|
/** |
2255
|
|
|
* Get the array of uploaded files from the request. |
2256
|
|
|
* |
2257
|
|
|
* @return array |
2258
|
|
|
*/ |
2259
|
|
|
public function getUploadedFiles() |
2260
|
|
|
{ |
2261
|
|
|
return $this->uploadedFiles; |
2262
|
|
|
} |
2263
|
|
|
|
2264
|
|
|
/** |
2265
|
|
|
* Update the request replacing the files, and creating a new instance. |
2266
|
|
|
* |
2267
|
|
|
* @param array $files An array of uploaded file objects. |
2268
|
|
|
* @return static |
2269
|
|
|
* @throws \InvalidArgumentException when $files contains an invalid object. |
2270
|
|
|
*/ |
2271
|
|
|
public function withUploadedFiles(array $files) |
2272
|
|
|
{ |
2273
|
|
|
$this->validateUploadedFiles($files, ''); |
2274
|
|
|
$new = clone $this; |
2275
|
|
|
$new->uploadedFiles = $files; |
2276
|
|
|
|
2277
|
|
|
return $new; |
2278
|
|
|
} |
2279
|
|
|
|
2280
|
|
|
/** |
2281
|
|
|
* Recursively validate uploaded file data. |
2282
|
|
|
* |
2283
|
|
|
* @param array $uploadedFiles The new files array to validate. |
2284
|
|
|
* @param string $path The path thus far. |
2285
|
|
|
* @return void |
2286
|
|
|
* @throws \InvalidArgumentException If any leaf elements are not valid files. |
2287
|
|
|
*/ |
2288
|
|
|
protected function validateUploadedFiles(array $uploadedFiles, $path) |
2289
|
|
|
{ |
2290
|
|
|
foreach ($uploadedFiles as $key => $file) { |
2291
|
|
|
if (is_array($file)) { |
2292
|
|
|
$this->validateUploadedFiles($file, $key . '.'); |
2293
|
|
|
continue; |
2294
|
|
|
} |
2295
|
|
|
|
2296
|
|
|
if (!$file instanceof UploadedFileInterface) { |
2297
|
|
|
throw new InvalidArgumentException("Invalid file at '{$path}{$key}'"); |
2298
|
|
|
} |
2299
|
|
|
} |
2300
|
|
|
} |
2301
|
|
|
|
2302
|
|
|
/** |
2303
|
|
|
* Gets the body of the message. |
2304
|
|
|
* |
2305
|
|
|
* @return \Psr\Http\Message\StreamInterface Returns the body as a stream. |
2306
|
|
|
*/ |
2307
|
|
|
public function getBody() |
2308
|
|
|
{ |
2309
|
|
|
return $this->stream; |
2310
|
|
|
} |
2311
|
|
|
|
2312
|
|
|
/** |
2313
|
|
|
* Return an instance with the specified message body. |
2314
|
|
|
* |
2315
|
|
|
* @param \Psr\Http\Message\StreamInterface $body The new request body |
2316
|
|
|
* @return static |
2317
|
|
|
*/ |
2318
|
|
|
public function withBody(StreamInterface $body) |
2319
|
|
|
{ |
2320
|
|
|
$new = clone $this; |
2321
|
|
|
$new->stream = $body; |
2322
|
|
|
|
2323
|
|
|
return $new; |
2324
|
|
|
} |
2325
|
|
|
|
2326
|
|
|
/** |
2327
|
|
|
* Retrieves the URI instance. |
2328
|
|
|
* |
2329
|
|
|
* @return \Psr\Http\Message\UriInterface Returns a UriInterface instance |
2330
|
|
|
* representing the URI of the request. |
2331
|
|
|
*/ |
2332
|
|
|
public function getUri() |
2333
|
|
|
{ |
2334
|
|
|
return $this->uri; |
2335
|
|
|
} |
2336
|
|
|
|
2337
|
|
|
/** |
2338
|
|
|
* Return an instance with the specified uri |
2339
|
|
|
* |
2340
|
|
|
* *Warning* Replacing the Uri will not update the `base`, `webroot`, |
2341
|
|
|
* and `url` attributes. |
2342
|
|
|
* |
2343
|
|
|
* @param \Psr\Http\Message\UriInterface $uri The new request uri |
2344
|
|
|
* @param bool $preserveHost Whether or not the host should be retained. |
2345
|
|
|
* @return static |
2346
|
|
|
*/ |
2347
|
|
|
public function withUri(UriInterface $uri, $preserveHost = false) |
2348
|
|
|
{ |
2349
|
|
|
$new = clone $this; |
2350
|
|
|
$new->uri = $uri; |
2351
|
|
|
|
2352
|
|
|
if ($preserveHost && $this->hasHeader('Host')) { |
2353
|
|
|
return $new; |
2354
|
|
|
} |
2355
|
|
|
|
2356
|
|
|
$host = $uri->getHost(); |
2357
|
|
|
if (!$host) { |
2358
|
|
|
return $new; |
2359
|
|
|
} |
2360
|
|
|
if ($uri->getPort()) { |
|
|
|
|
2361
|
|
|
$host .= ':' . $uri->getPort(); |
2362
|
|
|
} |
2363
|
|
|
$new->_environment['HTTP_HOST'] = $host; |
2364
|
|
|
|
2365
|
|
|
return $new; |
2366
|
|
|
} |
2367
|
|
|
|
2368
|
|
|
/** |
2369
|
|
|
* Create a new instance with a specific request-target. |
2370
|
|
|
* |
2371
|
|
|
* You can use this method to overwrite the request target that is |
2372
|
|
|
* inferred from the request's Uri. This also lets you change the request |
2373
|
|
|
* target's form to an absolute-form, authority-form or asterisk-form |
2374
|
|
|
* |
2375
|
|
|
* @link https://tools.ietf.org/html/rfc7230#section-2.7 (for the various |
2376
|
|
|
* request-target forms allowed in request messages) |
2377
|
|
|
* @param string $target The request target. |
2378
|
|
|
* @return static |
2379
|
|
|
*/ |
2380
|
|
|
public function withRequestTarget($target) |
2381
|
|
|
{ |
2382
|
|
|
$new = clone $this; |
2383
|
|
|
$new->requestTarget = $target; |
2384
|
|
|
|
2385
|
|
|
return $new; |
2386
|
|
|
} |
2387
|
|
|
|
2388
|
|
|
/** |
2389
|
|
|
* Retrieves the request's target. |
2390
|
|
|
* |
2391
|
|
|
* Retrieves the message's request-target either as it was requested, |
2392
|
|
|
* or as set with `withRequestTarget()`. By default this will return the |
2393
|
|
|
* application relative path without base directory, and the query string |
2394
|
|
|
* defined in the SERVER environment. |
2395
|
|
|
* |
2396
|
|
|
* @return string |
2397
|
|
|
*/ |
2398
|
|
|
public function getRequestTarget() |
2399
|
|
|
{ |
2400
|
|
|
if ($this->requestTarget !== null) { |
2401
|
|
|
return $this->requestTarget; |
2402
|
|
|
} |
2403
|
|
|
|
2404
|
|
|
$target = $this->uri->getPath(); |
2405
|
|
|
if ($this->uri->getQuery()) { |
2406
|
|
|
$target .= '?' . $this->uri->getQuery(); |
2407
|
|
|
} |
2408
|
|
|
|
2409
|
|
|
if (empty($target)) { |
2410
|
|
|
$target = '/'; |
2411
|
|
|
} |
2412
|
|
|
|
2413
|
|
|
return $target; |
2414
|
|
|
} |
2415
|
|
|
|
2416
|
|
|
/** |
2417
|
|
|
* Get the path of current request. |
2418
|
|
|
* |
2419
|
|
|
* @return string |
2420
|
|
|
* @since 3.6.1 |
2421
|
|
|
*/ |
2422
|
|
|
public function getPath() |
2423
|
|
|
{ |
2424
|
|
|
if ($this->requestTarget === null) { |
2425
|
|
|
return $this->uri->getPath(); |
2426
|
|
|
} |
2427
|
|
|
|
2428
|
|
|
list($path) = explode('?', $this->requestTarget); |
2429
|
|
|
|
2430
|
|
|
return $path; |
2431
|
|
|
} |
2432
|
|
|
|
2433
|
|
|
/** |
2434
|
|
|
* Array access read implementation |
2435
|
|
|
* |
2436
|
|
|
* @param string $name Name of the key being accessed. |
2437
|
|
|
* @return mixed |
2438
|
|
|
* @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use getParam(), getData() and getQuery() instead. |
2439
|
|
|
*/ |
2440
|
|
|
public function offsetGet($name) |
2441
|
|
|
{ |
2442
|
|
|
deprecationWarning( |
2443
|
|
|
'The ArrayAccess methods will be removed in 4.0.0.' . |
2444
|
|
|
'Use getParam(), getData() and getQuery() instead.' |
2445
|
|
|
); |
2446
|
|
|
|
2447
|
|
|
if (isset($this->params[$name])) { |
|
|
|
|
2448
|
|
|
return $this->params[$name]; |
|
|
|
|
2449
|
|
|
} |
2450
|
|
|
if ($name === 'url') { |
2451
|
|
|
return $this->query; |
|
|
|
|
2452
|
|
|
} |
2453
|
|
|
if ($name === 'data') { |
2454
|
|
|
return $this->data; |
|
|
|
|
2455
|
|
|
} |
2456
|
|
|
|
2457
|
|
|
return null; |
2458
|
|
|
} |
2459
|
|
|
|
2460
|
|
|
/** |
2461
|
|
|
* Array access write implementation |
2462
|
|
|
* |
2463
|
|
|
* @param string $name Name of the key being written |
2464
|
|
|
* @param mixed $value The value being written. |
2465
|
|
|
* @return void |
2466
|
|
|
* @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use withParam() instead. |
2467
|
|
|
*/ |
2468
|
|
|
public function offsetSet($name, $value) |
2469
|
|
|
{ |
2470
|
|
|
deprecationWarning( |
2471
|
|
|
'The ArrayAccess methods will be removed in 4.0.0.' . |
2472
|
|
|
'Use withParam() instead.' |
2473
|
|
|
); |
2474
|
|
|
|
2475
|
|
|
$this->params[$name] = $value; |
|
|
|
|
2476
|
|
|
} |
2477
|
|
|
|
2478
|
|
|
/** |
2479
|
|
|
* Array access isset() implementation |
2480
|
|
|
* |
2481
|
|
|
* @param string $name thing to check. |
2482
|
|
|
* @return bool |
2483
|
|
|
* @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use getParam() instead. |
2484
|
|
|
*/ |
2485
|
|
|
public function offsetExists($name) |
2486
|
|
|
{ |
2487
|
|
|
deprecationWarning( |
2488
|
|
|
'The ArrayAccess methods will be removed in 4.0.0.' . |
2489
|
|
|
'Use getParam() instead.' |
2490
|
|
|
); |
2491
|
|
|
|
2492
|
|
|
if ($name === 'url' || $name === 'data') { |
2493
|
|
|
return true; |
2494
|
|
|
} |
2495
|
|
|
|
2496
|
|
|
return isset($this->params[$name]); |
|
|
|
|
2497
|
|
|
} |
2498
|
|
|
|
2499
|
|
|
/** |
2500
|
|
|
* Array access unset() implementation |
2501
|
|
|
* |
2502
|
|
|
* @param string $name Name to unset. |
2503
|
|
|
* @return void |
2504
|
|
|
* @deprecated 3.4.0 The ArrayAccess methods will be removed in 4.0.0. Use withParam() instead. |
2505
|
|
|
*/ |
2506
|
|
|
public function offsetUnset($name) |
2507
|
|
|
{ |
2508
|
|
|
deprecationWarning( |
2509
|
|
|
'The ArrayAccess methods will be removed in 4.0.0.' . |
2510
|
|
|
'Use withParam() instead.' |
2511
|
|
|
); |
2512
|
|
|
|
2513
|
|
|
unset($this->params[$name]); |
2514
|
|
|
} |
2515
|
|
|
} |
2516
|
|
|
|
2517
|
|
|
// @deprecated 3.4.0 Add backwards compat alias. |
2518
|
|
|
class_alias('Cake\Http\ServerRequest', 'Cake\Network\Request'); |
2519
|
|
|
|
This property has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.