ServerRequest.php 66 KB

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