Request & Response Objects

The request and response objects provide an abstraction around HTTP requests andresponses. The request object in CakePHP allows you to introspect an incomingrequest, while the response object allows you to effortlessly create HTTPresponses from your controllers.

Request

  • class Cake\Http\ServerRequest

ServerRequest is the default request object used in CakePHP. It centralizes anumber of features for interrogating and interacting with request data.On each request one Request is created and then passed by reference to thevarious layers of an application that use request data. By default the requestis assigned to $this->request, and is available in Controllers, Cells, Viewsand Helpers. You can also access it in Components using the controllerreference. Some of the duties ServerRequest performs include:

  • Processing the GET, POST, and FILES arrays into the data structures you arefamiliar with.
  • Providing environment introspection pertaining to the request. Informationlike the headers sent, the client’s IP address, and the subdomain/domainnames the server your application is running on.
  • Providing access to request parameters both as array indexes and objectproperties.

CakePHP’s request object implements the PSR-7ServerRequestInterface making it easier touse libraries from outside of CakePHP.

Request Parameters

The request exposes routing parameters through the getParam() method:

  1. $controllerName = $this->request->getParam('controller');

To get all routing parameters as an array use getAttribute():

  1. $parameters = $this->request->getAttribute('params');

All Route Elements are accessed through this interface.

In addition to Route Elements, you also often need access toPassed Arguments. These are both available on the request object aswell:

  1. // Passed arguments
  2. $passedArgs = $this->request->getParam('pass');

Will all provide you access to the passed arguments. Thereare several important/useful parameters that CakePHP uses internally, theseare also all found in the routing parameters:

  • plugin The plugin handling the request. Will be null when there is noplugin.
  • controller The controller handling the current request.
  • action The action handling the current request.
  • prefix The prefix for the current action. See Prefix Routing formore information.

Query String Parameters

  • Cake\Http\ServerRequest::getQuery($name)

Query string parameters can be read using the getQuery() method:

  1. // URL is /posts/index?page=1&sort=title
  2. $page = $this->request->getQuery('page');

You can either directly access the query property, or you can usegetQuery() method to read the URL query array in an error-free manner.Any keys that do not exist will return null:

  1. $foo = $this->request->getQuery('value_that_does_not_exist');
  2. // $foo === null
  3.  
  4. // You can also provide default values
  5. $foo = $this->request->getQuery('does_not_exist', 'default val');

If you want to access all the query parameters you can usegetQueryParams():

  1. $query = $this->request->getQueryParams();

Request Body Data

  • Cake\Http\ServerRequest::getData($name, $default = null)

All POST data can be accessed usingCake\Http\ServerRequest::getData(). Any form data thatcontains a data prefix will have that data prefix removed. For example:

  1. // An input with a name attribute equal to 'MyModel[title]' is accessible at
  2. $title = $this->request->getData('MyModel.title');

Any keys that do not exist will return null:

  1. $foo = $this->request->getData('Value.that.does.not.exist');
  2. // $foo == null

File Uploads

Uploaded files can be accessed through the request body data, using the Cake\Http\ServerRequest::getData()method described above. For example, a file from an input element with a name attribute of MyModel[attachment], canbe accessed like this:

  1. $attachment = $this->request->getData('MyModel.attachment');

By default file uploads are represented in the request data as arrays, with a normalized structure that remains the sameeven for nested inputs/names, which is different from how PHP represents them in the $_FILES superglobal (refer tothe PHP manual for more information), ie the$attachment value would look something like this:

  1. [
  2. 'name' => 'attachment.txt',
  3. 'type' => 'text/plain',
  4. 'size' => 123,
  5. 'tmp_name' => '/tmp/hfz6dbn.tmp'
  6. 'error' => 0
  7. ]

Alternatively it’s possible to have CakePHP provide the uploads in the request data as objects that implement\Psr\Http\Message\UploadedFileInterface. In order toenable this behavior, set the configuration value App.uploadedFilesAsObjects to true, for example in yourconfig/app.php file:

  1. return [
  2. // ...
  3. 'App' => [
  4. // ...
  5. 'uploadedFilesAsObjects' => true,
  6. ],
  7. // ...
  8. ];

In the above example, $attachment would then hold an object, in the current implementation it would by default be aninstance of \Zend\Diactoros\UploadedFile.

Furthermore uploaded files can be accessed as objects separately from the request data via theCake\Http\ServerRequest::getUploadedFile() andCake\Http\ServerRequest::getUploadedFiles() methods. These methods will always return objects,irrespectively of the App.uploadedFilesAsObjects configuration.

  • Cake\Http\ServerRequest::getUploadedFile($path)

Returns the uploaded file at a specific path. The path uses the same dot syntax as theCake\Http\ServerRequest::getData() method:

  1. $attachment = $this->request->getUploadedFile('MyModel.attachment');

Unlike Cake\Http\ServerRequest::getData(), Cake\Http\ServerRequest::getUploadedFile() wouldonly return data when an actual file upload exists for the given path, if there is regular, non-file request body datapresent at the given path, then this method will return null, just like it would for any non-existent path.

  • Cake\Http\ServerRequest::getUploadedFiles()

Returns all uploaded files in a normalized array structure. For the above example with the file input name ofMyModel[attachment], the structure would look like:

  1. [
  2. 'MyModel' => [
  3. 'attachment' => object(Zend\Diactoros\UploadedFile) {
  4. // ...
  5. }
  6. ]
  7. ]
  • Cake\Http\ServerRequest::withUploadedFiles(array $files)

This method sets the uploaded files of the request object, it accepts an array of objects that implement\Psr\Http\Message\UploadedFileInterface. It willreplace all possibly existing uploaded files:

  1. $files = [
  2. 'MyModel' => [
  3. 'attachment' => new \Zend\Diactoros\UploadedFile(
  4. $streamOrFile,
  5. $size,
  6. $errorStatus,
  7. $clientFilename,
  8. $clientMediaType
  9. ),
  10. 'anotherAttachment' => new \Zend\Diactoros\UploadedFile(
  11. '/tmp/hfz6dbn.tmp',
  12. 123,
  13. \UPLOAD_ERR_OK,
  14. 'attachment.txt',
  15. 'text/plain'
  16. ),
  17. ],
  18. ];
  19.  
  20. $this->request = $this->request->withUploadedFiles($files);

Note

Uploaded files that have been added to the request via this method, will not be available in the request bodydata, ie you cannot retrieve them via Cake\Http\ServerRequest::getData()! If you need them in therequest data (too), then you have to set them via Cake\Http\ServerRequest::withData() orCake\Http\ServerRequest::withParsedBody().

PUT, PATCH or DELETE Data

  • Cake\Http\ServerRequest::input($callback[, $options])

When building REST services, you often accept request data on PUT andDELETE requests. Any application/x-www-form-urlencoded request body datawill automatically be parsed and set to $this->data for PUT andDELETE requests. If you are accepting JSON or XML data, see below for howyou can access those request bodies.

When accessing the input data, you can decode it with an optional function.This is useful when interacting with XML or JSON request body content.Additional parameters for the decoding function can be passed as arguments toinput():

  1. $jsonData = $this->request->input('json_decode');

Environment Variables (from $_SERVER and $_ENV)

  • Cake\Http\ServerRequest::env($key, $value = null)

ServerRequest::env() is a wrapper for env() global function and acts asa getter/setter for environment variables without having to modify globals$_SERVER and $_ENV:

  1. // Get the host
  2. $host = $this->request->env('HTTP_HOST');
  3.  
  4. // Set a value, generally helpful in testing.
  5. $this->request->env('REQUEST_METHOD', 'POST');

To access all the environment variables in a request use getServerParams():

  1. $env = $this->request->getServerParams();

XML or JSON Data

Applications employing REST often exchange data innon-URL-encoded post bodies. You can read input data in any format usingHttp\ServerRequest::input(). By providing a decoding function,you can receive the content in a deserialized format:

  1. // Get JSON encoded data submitted to a PUT/POST action
  2. $jsonData = $this->request->input('json_decode');

Some deserializing methods require additional parameters when called, such asthe ‘as array’ parameter on json_decode. If you want XML converted into aDOMDocument object, Http\ServerRequest::input() supportspassing in additional parameters as well:

  1. // Get XML encoded data submitted to a PUT/POST action
  2. $data = $this->request->input('Cake\Utility\Xml::build', ['return' => 'domdocument']);

Path Information

The request object also provides useful information about the paths in yourapplication. The base and webroot attributes are useful forgenerating URLs, and determining whether or not your application is in asubdirectory. The attributes you can use are:

  1. // Assume the current request URL is /subdir/articles/edit/1?page=1
  2.  
  3. // Holds /subdir/articles/edit/1?page=1
  4. $here = $request->getRequestTarget();
  5.  
  6. // Holds /subdir
  7. $base = $request->getAttribute('base');
  8.  
  9. // Holds /subdir/
  10. $base = $request->getAttribute('webroot');

Checking Request Conditions

  • Cake\Http\ServerRequest::is($type, $args…)

The request object provides an easy way to inspect certain conditions in a givenrequest. By using the is() method you can check a number of commonconditions, as well as inspect other application specific request criteria:

  1. $isPost = $this->request->is('post');

You can also extend the request detectors that are available, by usingCake\Http\ServerRequest::addDetector() to create new kinds ofdetectors. There are different types of detectors that you can create:

  • Environment value comparison - Compares a value fetched from env()for equality with the provided value.
  • Header value comparison - If the specified header exists with the specifiedvalue, or if the callable returns true.
  • Pattern value comparison - Pattern value comparison allows you to compare avalue fetched from env() to a regular expression.
  • Option based comparison - Option based comparisons use a list of options tocreate a regular expression. Subsequent calls to add an already definedoptions detector will merge the options.
  • Callback detectors - Callback detectors allow you to provide a ‘callback’ typeto handle the check. The callback will receive the request object as its onlyparameter.
  • Cake\Http\ServerRequest::addDetector($name, $options)

Some examples would be:

  1. // Add an environment detector.
  2. $this->request->addDetector(
  3. 'post',
  4. ['env' => 'REQUEST_METHOD', 'value' => 'POST']
  5. );
  6.  
  7. // Add a pattern value detector.
  8. $this->request->addDetector(
  9. 'iphone',
  10. ['env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i']
  11. );
  12.  
  13. // Add an option detector
  14. $this->request->addDetector('internalIp', [
  15. 'env' => 'CLIENT_IP',
  16. 'options' => ['192.168.0.101', '192.168.0.100']
  17. ]);
  18.  
  19.  
  20. // Add a header detector with value comparison
  21. $this->request->addDetector('fancy', [
  22. 'env' => 'CLIENT_IP',
  23. 'header' => ['X-Fancy' => 1]
  24. ]);
  25.  
  26. // Add a header detector with callable comparison
  27. $this->request->addDetector('fancy', [
  28. 'env' => 'CLIENT_IP',
  29. 'header' => ['X-Fancy' => function ($value, $header) {
  30. return in_array($value, ['1', '0', 'yes', 'no'], true);
  31. }]
  32. ]);
  33.  
  34. // Add a callback detector. Must be a valid callable.
  35. $this->request->addDetector(
  36. 'awesome',
  37. function ($request) {
  38. return $request->getParam('awesome');
  39. }
  40. );
  41.  
  42. // Add a detector that uses additional arguments.
  43. $this->request->addDetector(
  44. 'csv',
  45. [
  46. 'accept' => ['text/csv'],
  47. 'param' => '_ext',
  48. 'value' => 'csv',
  49. ]
  50. );

There are several built-in detectors that you can use:

  • is('get') Check to see whether the current request is a GET.
  • is('put') Check to see whether the current request is a PUT.
  • is('patch') Check to see whether the current request is a PATCH.
  • is('post') Check to see whether the current request is a POST.
  • is('delete') Check to see whether the current request is a DELETE.
  • is('head') Check to see whether the current request is HEAD.
  • is('options') Check to see whether the current request is OPTIONS.
  • is('ajax') Check to see whether the current request came withX-Requested-With = XMLHttpRequest.
  • is('ssl') Check to see whether the request is via SSL.
  • is('flash') Check to see whether the request has a User-Agent of Flash.
  • is('json') Check to see whether the request has ‘json’ extension andaccept ‘application/json’ mimetype.
  • is('xml') Check to see whether the request has ‘xml’ extension and accept‘application/xml’ or ‘text/xml’ mimetype.

ServerRequest also includes methods likeCake\Http\ServerRequest::domain(),Cake\Http\ServerRequest::subdomains() andCake\Http\ServerRequest::host() to make applications that usesubdomains simpler.

Session Data

To access the session for a given request use the getSession() method or use the session attribute:

  1. $session = $this->request->getSession();
  2. $session = $this->request->getAttribute('session');
  3.  
  4. $userName = $session->read('Auth.User.name');

For more information, see the Sessions documentation for howto use the session object.

Host and Domain Name

  • Cake\Http\ServerRequest::domain($tldLength = 1)

Returns the domain name your application is running on:

  1. // Prints 'example.org'
  2. echo $request->domain();
  • Cake\Http\ServerRequest::subdomains($tldLength = 1)

Returns the subdomains your application is running on as an array:

  1. // Returns ['my', 'dev'] for 'my.dev.example.org'
  2. $subdomains = $request->subdomains();
  • Cake\Http\ServerRequest::host()

Returns the host your application is on:

  1. // Prints 'my.dev.example.org'
  2. echo $request->host();

Reading the HTTP Method

  • Cake\Http\ServerRequest::getMethod()

Returns the HTTP method the request was made with:

  1. // Output POST
  2. echo $request->getMethod();

Restricting Which HTTP method an Action Accepts

  • Cake\Http\ServerRequest::allowMethod($methods)

Set allowed HTTP methods. If not matched, will throwMethodNotAllowedException. The 405 response will include the requiredAllow header with the passed methods:

  1. public function delete()
  2. {
  3. // Only accept POST and DELETE requests
  4. $this->request->allowMethod(['post', 'delete']);
  5. ...
  6. }

Reading HTTP Headers

Allows you to access any of the HTTP_* headers that were usedfor the request. For example:

  1. // Get the header as a string
  2. $userAgent = $this->request->getHeaderLine('User-Agent');
  3.  
  4. // Get an array of all values.
  5. $acceptHeader = $this->request->getHeader('Accept');
  6.  
  7. // Check if a header exists
  8. $hasAcceptHeader = $this->request->hasHeader('Accept');

While some apache installs don’t make the Authorization header accessible,CakePHP will make it available through apache specific methods as required.

  • Cake\Http\ServerRequest::referer($local = true)

Returns the referring address for the request.

  • Cake\Http\ServerRequest::clientIp()

Returns the current visitor’s IP address.

Trusting Proxy Headers

If your application is behind a load balancer or running on a cloud service, youwill often get the load balancer host, port and scheme in your requests. Oftenload balancers will also send HTTP-X-Forwarded-* headers with the originalvalues. The forwarded headers will not be used by CakePHP out of the box. Tohave the request object use these headers set the trustProxy property totrue:

  1. $this->request->trustProxy = true;
  2.  
  3. // These methods will now use the proxied headers.
  4. $port = $this->request->port();
  5. $host = $this->request->host();
  6. $scheme = $this->request->scheme();
  7. $clientIp = $this->request->clientIp();

Once proxies are trusted the clientIp() method will use the last IPaddress in the X-Forwarded-For header. If your application is behindmultiple proxies, you can use setTrustedProxies() to define the IP addressesof proxies in your control:

  1. $request->setTrustedProxies(['127.1.1.1', '127.8.1.3']);

After proxies are trusted clientIp() will use the first IP address in theX-Forwarded-For header providing it is the only value that isn’t from a trustedproxy.

Checking Accept Headers

  • Cake\Http\ServerRequest::accepts($type = null)

Find out which content types the client accepts, or check whether it accepts aparticular type of content.

Get all types:

  1. $accepts = $this->request->accepts();

Check for a single type:

  1. $acceptsJson = $this->request->accepts('application/json');
  • Cake\Http\ServerRequest::acceptLanguage($language = null)

Get all the languages accepted by the client,or check whether a specific language is accepted.

Get the list of accepted languages:

  1. $acceptsLanguages = $this->request->acceptLanguage();

Check whether a specific language is accepted:

  1. $acceptsSpanish = $this->request->acceptLanguage('es-es');

Cookies

Request cookies can be read through a number of methods:

  1. // Get the cookie value, or null if the cookie is missing.
  2. $rememberMe = $this->request->getCookie('remember_me');
  3.  
  4. // Read the value, or get the default of 0
  5. $rememberMe = $this->request->getCookie('remember_me', 0);
  6.  
  7. // Get all cookies as an hash
  8. $cookies = $this->request->getCookieParams();
  9.  
  10. // Get a CookieCollection instance
  11. $cookies = $this->request->getCookieCollection()

See the Cake\Http\Cookie\CookieCollection documentation for howto work with cookie collection.

Uploaded Files

Requests expose the uploaded file data in getData() orgetUploadedFiles() as UploadedFileInterface objects:

  1. // Get a list of UploadedFile objects
  2. $files = $request->getUploadedFiles();
  3.  
  4. // Read the file data.
  5. $files[0]->getStream();
  6. $files[0]->getSize();
  7. $files[0]->getClientFileName();
  8.  
  9. // Move the file.
  10. $files[0]->moveTo($targetPath);

Manipulating URIs

Requests contain a URI object, which contains methods for interacting with therequested URI:

  1. // Get the URI
  2. $uri = $request->getUri();
  3.  
  4. // Read data out of the URI.
  5. $path = $uri->getPath();
  6. $query = $uri->getQuery();
  7. $host = $uri->getHost();

Response

  • class Cake\Http\Response

Cake\Http\Response is the default response class in CakePHP.It encapsulates a number of features and functionality for generating HTTPresponses in your application. It also assists in testing, as it can bemocked/stubbed allowing you to inspect headers that will be sent.Like Cake\Http\ServerRequest, Cake\Http\Responseconsolidates a number of methods previously found on Controller,RequestHandlerComponent and Dispatcher. The oldmethods are deprecated in favour of using Cake\Http\Response.

Response provides an interface to wrap the common response-relatedtasks such as:

  • Sending headers for redirects.
  • Sending content type headers.
  • Sending any header.
  • Sending the response body.

Dealing with Content Types

  • Cake\Http\Response::withType($contentType = null)

You can control the Content-Type of your application’s responses withCake\Http\Response::withType(). If your application needs to dealwith content types that are not built into Response, you can map them withtype() as well:

  1. // Add a vCard type
  2. $this->response->type(['vcf' => 'text/v-card']);
  3.  
  4. // Set the response Content-Type to vcard.
  5. $this->response = $this->response->withType('vcf');

Usually, you’ll want to map additional content types in your controller’sbeforeFilter() callback, so you can leverage theautomatic view switching features of RequestHandlerComponent if youare using it.

Sending Files

  • Cake\Http\Response::withFile($path, $options = [])

There are times when you want to send files as responses for your requests.You can accomplish that by using Cake\Http\Response::withFile():

  1. public function sendFile($id)
  2. {
  3. $file = $this->Attachments->getFile($id);
  4. $response = $this->response->withFile($file['path']);
  5. // Return the response to prevent controller from trying to render
  6. // a view.
  7. return $response;
  8. }

As shown in the above example, you must pass the file path to the method.CakePHP will send a proper content type header if it’s a known file type listedin Cake\Http\Response::$_mimeTypes. You can add new types prior to callingCake\Http\Response::withFile() by using theCake\Http\Response::withType() method.

If you want, you can also force a file to be downloaded instead of displayed inthe browser by specifying the options:

  1. $response = $this->response->withFile(
  2. $file['path'],
  3. ['download' => true, 'name' => 'foo']
  4. );

The supported options are:

  • name
  • The name allows you to specify an alternate file name to be sent tothe user.
  • download
  • A boolean value indicating whether headers should be set to forcedownload.

Sending a String as File

You can respond with a file that does not exist on the disk, such as a pdf or anics generated on the fly from a string:

  1. public function sendIcs()
  2. {
  3. $icsString = $this->Calendars->generateIcs();
  4. $response = $this->response;
  5.  
  6. // Inject string content into response body
  7. $response = $response->withStringBody($icsString);
  8.  
  9. $response = $response->withType('ics');
  10.  
  11. // Optionally force file download
  12. $response = $response->withDownload('filename_for_download.ics');
  13.  
  14. // Return response object to prevent controller from trying to render
  15. // a view.
  16. return $response;
  17. }

Callbacks can also return the body as a string:

  1. $path = '/some/file.png';
  2. $this->response->body(function () use ($path) {
  3. return file_get_contents($path);
  4. });

Setting Headers

  • Cake\Http\Response::withHeader($header, $value)

Setting headers is done with the Cake\Http\Response::withHeader()method. Like all of the PSR-7 interface methods, this method returns a _new_instance with the new header:

  1. // Add/replace a header
  2. $response = $response->withHeader('X-Extra', 'My header');
  3.  
  4. // Set multiple headers
  5. $response = $response->withHeader('X-Extra', 'My header')
  6. ->withHeader('Location', 'http://example.com');
  7.  
  8. // Append a value to an existing header
  9. $response = $response->withAddedHeader('Set-Cookie', 'remember_me=1');

Headers are not sent when set. Instead, they are held until the response isemitted by Cake\Http\Server.

You can now use the convenience methodCake\Http\Response::withLocation() to directly set or get theredirect location header.

Setting the Body

  • Cake\Http\Response::withStringBody($string)

To set a string as the response body, do the following:

  1. // Set a string into the body
  2. $response = $response->withStringBody('My Body');
  3.  
  4. // If you want a json response
  5. $response = $response->withType('application/json')
  6. ->withStringBody(json_encode(['Foo' => 'bar']));
  • Cake\Http\Response::withBody($body)

To set the response body, use the withBody() method, which is provided by theZend\Diactoros\MessageTrait:

  1. $response = $response->withBody($stream);

Be sure that $stream is a Psr\Http\Message\StreamInterface object.See below on how to create a new stream.

You can also stream responses from files using Zend\Diactoros\Stream streams:

  1. // To stream from a file
  2. use Zend\Diactoros\Stream;
  3.  
  4. $stream = new Stream('/path/to/file', 'rb');
  5. $response = $response->withBody($stream);

You can also stream responses from a callback using the CallbackStream. Thisis useful when you have resources like images, CSV files or PDFs you need tostream to the client:

  1. // Streaming from a callback
  2. use Cake\Http\CallbackStream;
  3.  
  4. // Create an image.
  5. $img = imagecreate(100, 100);
  6. // ...
  7.  
  8. $stream = new CallbackStream(function () use ($img) {
  9. imagepng($img);
  10. });
  11. $response = $response->withBody($stream);

Setting the Character Set

  • Cake\Http\Response::withCharset($charset)

Sets the charset that will be used in the response:

  1. $this->response = $this->response->withCharset('UTF-8');

Interacting with Browser Caching

  • Cake\Http\Response::withDisabledCache()

You sometimes need to force browsers not to cache the results of a controlleraction. Cake\Http\Response::withDisabledCache() is intended for justthat:

  1. public function index()
  2. {
  3. // Disable caching
  4. $this->response = $this->response->withDisabledCache();
  5. }

Warning

Disabling caching from SSL domains while trying to sendfiles to Internet Explorer can result in errors.

  • Cake\Http\Response::withCache($since, $time = '+1 day')

You can also tell clients that you want them to cache responses. By usingCake\Http\Response::withCache():

  1. public function index()
  2. {
  3. // Enable caching
  4. $this->response = $this->response->withCache('-1 minute', '+5 days');
  5. }

The above would tell clients to cache the resulting response for 5 days,hopefully speeding up your visitors’ experience.The withCache() method sets the Last-Modified value to the firstargument. Expires header and the max-age directive are set based on thesecond parameter. Cache-Control’s public directive is set as well.

Fine Tuning HTTP Cache

One of the best and easiest ways of speeding up your application is to use HTTPcache. Under this caching model, you are only required to help clients decide ifthey should use a cached copy of the response by setting a few headers such asmodified time and response entity tag.

Rather than forcing you to code the logic for caching and for invalidating(refreshing) it once the data has changed, HTTP uses two models, expiration andvalidation, which usually are much simpler to use.

Apart from using Cake\Http\Response::withCache(), you can also usemany other methods to fine-tune HTTP cache headers to take advantage of browseror reverse proxy caching.

The Cache Control Header

  • Cake\Http\Response::withSharable($public, $time = null)

Used under the expiration model, this header contains multiple indicators thatcan change the way browsers or proxies use the cached content. ACache-Control header can look like this:

  1. Cache-Control: private, max-age=3600, must-revalidate

Response class helps you set this header with some utility methods that willproduce a final valid Cache-Control header. The first is thewithSharable() method, which indicates whether a response is to beconsidered sharable across different users or clients. This method actuallycontrols the public or private part of this header. Setting a responseas private indicates that all or part of it is intended for a single user. Totake advantage of shared caches, the control directive must be set as public.

The second parameter of this method is used to specify a max-age for thecache, which is the number of seconds after which the response is no longerconsidered fresh:

  1. public function view()
  2. {
  3. // ...
  4. // Set the Cache-Control as public for 3600 seconds
  5. $this->response = $this->response->withSharable(true, 3600);
  6. }
  7.  
  8. public function my_data()
  9. {
  10. // ...
  11. // Set the Cache-Control as private for 3600 seconds
  12. $this->response = $this->response->withSharable(false, 3600);
  13. }

Response exposes separate methods for setting each of the directives inthe Cache-Control header.

The Expiration Header

  • Cake\Http\Response::withExpires($time)

You can set the Expires header to a date and time after which the responseis no longer considered fresh. This header can be set using thewithExpires() method:

  1. public function view()
  2. {
  3. $this->response = $this->response->withExpires('+5 days');
  4. }

This method also accepts a DateTime instance or any string that canbe parsed by the DateTime class.

The Etag Header

  • Cake\Http\Response::withEtag($tag, $weak = false)

Cache validation in HTTP is often used when content is constantly changing, andasks the application to only generate the response contents if the cache is nolonger fresh. Under this model, the client continues to store pages in thecache, but it asks the application every timewhether the resource has changed, instead of using it directly.This is commonly used with static resources such as images and other assets.

The withEtag() method (called entity tag) is a stringthat uniquely identifies the requested resource, as a checksum does for a file,in order to determine whether it matches a cached resource.

To take advantage of this header, you must either call thecheckNotModified() method manually or include theRequest Handling in your controller:

  1. public function index()
  2. {
  3. $articles = $this->Articles->find('all');
  4.  
  5. // Simple checksum of the article contents.
  6. // You should use a more efficient implementation
  7. // in a real world application.
  8. $checksum = md5(json_encode($articles));
  9.  
  10. $response = $this->response->withEtag($checksum);
  11. if ($response->checkNotModified($this->request)) {
  12. return $response;
  13. }
  14.  
  15. $this->response = $response;
  16. // ...
  17. }

Note

Most proxy users should probably consider using the Last Modified Headerinstead of Etags for performance and compatibility reasons.

The Last Modified Header

  • Cake\Http\Response::withModified($time)

Also, under the HTTP cache validation model, you can set the Last-Modifiedheader to indicate the date and time at which the resource was modified for thelast time. Setting this header helps CakePHP tell caching clients whether theresponse was modified or not based on their cache.

To take advantage of this header, you must either call thecheckNotModified() method manually or include theRequest Handling in your controller:

  1. public function view()
  2. {
  3. $article = $this->Articles->find()->first();
  4. $response = $this->response->withModified($article->modified);
  5. if ($response->checkNotModified($this->request)) {
  6. return $response;
  7. }
  8. $this->response;
  9. // ...
  10. }

The Vary Header

  • Cake\Http\Response::withVary($header)

In some cases, you might want to serve different content using the same URL.This is often the case if you have a multilingual page or respond with differentHTML depending on the browser. Under such circumstances you can use the Varyheader:

  1. $response = $this->response->withVary('User-Agent');
  2. $response = $this->response->withVary('Accept-Encoding', 'User-Agent');
  3. $response = $this->response->withVary('Accept-Language');

Sending Not-Modified Responses

  • Cake\Http\Response::checkNotModified(Request $request)

Compares the cache headers for the request object with the cache header from theresponse and determines whether it can still be considered fresh. If so, deletesthe response content, and sends the 304 Not Modified header:

  1. // In a controller action.
  2. if ($this->response->checkNotModified($this->request)) {
  3. return $this->response;
  4. }

Setting Cookies

Cookies can be added to response using either an array or a Cake\Http\Cookie\Cookieobject:

  1. use Cake\Http\Cookie\Cookie;
  2. use DateTime;
  3.  
  4. // Add a cookie
  5. $this->response = $this->response->withCookie(Cookie::create(
  6. 'remember_me',
  7. 'yes',
  8. // All keys are optional
  9. [
  10. 'expires' => new DateTime('+1 year'),
  11. 'path' => '',
  12. 'domain' => '',
  13. 'secure' => false,
  14. 'http' => false,
  15. ]
  16. ]);

See the Creating Cookies section for how to use the cookie object. Youcan use withExpiredCookie() to send an expired cookie in the response. Thiswill make the browser remove its local cookie:

  1. $this->response = $this->response->withExpiredCookie('remember_me');

Setting Cross Origin Request Headers (CORS)

The cors() method is used to define HTTP Access Controlrelated headers with a fluent interface:

  1. $this->response = $this->response->cors($this->request)
  2. ->allowOrigin(['*.cakephp.org'])
  3. ->allowMethods(['GET', 'POST'])
  4. ->allowHeaders(['X-CSRF-Token'])
  5. ->allowCredentials()
  6. ->exposeHeaders(['Link'])
  7. ->maxAge(300)
  8. ->build();

CORS related headers will only be applied to the response if the followingcriteria are met:

  • The request has an Origin header.
  • The request’s Origin value matches one of the allowed Origin values.

Common Mistakes with Immutable Responses

Response objects offer a number of methods that treatresponses as immutable objects. Immutable objects help prevent difficult totrack accidental side-effects, and reduce mistakes caused by method calls causedby refactoring that change ordering. While they offer a number of benefits,immutable objects can take some getting used to. Any method that starts withwith operates on the response in an immutable fashion, and will alwaysreturn a new instance. Forgetting to retain the modified instance is the mostfrequent mistake people make when working with immutable objects:

  1. $this->response->withHeader('X-CakePHP', 'yes!');

In the above code, the response will be lacking the X-CakePHP header, as thereturn value of the withHeader() method was not retained. To correct theabove code you would write:

  1. $this->response = $this->response->withHeader('X-CakePHP', 'yes!');
  • class Cake\Http\Cookie\CookieCollection

CookieCollection objects are accessible from the request and response objects.They let you interact with groups of cookies using immutable patterns, whichallow the immutability of the request and response to be preserved.

Creating Cookies

  • class Cake\Http\Cookie\Cookie

Cookie objects can be defined through constructor objects, or by using thefluent interface that follows immutable patterns:

  1. use Cake\Http\Cookie\Cookie;
  2.  
  3. // All arguments in the constructor
  4. $cookie = new Cookie(
  5. 'remember_me', // name
  6. 1, // value
  7. new DateTime('+1 year'), // expiration time, if applicable
  8. '/', // path, if applicable
  9. 'example.com', // domain, if applicable
  10. false, // secure only?
  11. true // http only ?
  12. );
  13.  
  14. // Using the builder methods
  15. $cookie = (new Cookie('remember_me'))
  16. ->withValue('1')
  17. ->withExpiry(new DateTime('+1 year'))
  18. ->withPath('/')
  19. ->withDomain('example.com')
  20. ->withSecure(false)
  21. ->withHttpOnly(true);

Once you have created a cookie, you can add it to a new or existingCookieCollection:

  1. use Cake\Http\Cookie\CookieCollection;
  2.  
  3. // Create a new collection
  4. $cookies = new CookieCollection([$cookie]);
  5.  
  6. // Add to an existing collection
  7. $cookies = $cookies->add($cookie);
  8.  
  9. // Remove a cookie by name
  10. $cookies = $cookies->remove('remember_me');

Note

Remember that collections are immutable and adding cookies into, or removingcookies from a collection, creates a new collection object.

Cookie objects can be added to responses:

  1. // Add one cookie
  2. $response = $this->response->withCookie($cookie);
  3.  
  4. // Replace the entire cookie collection
  5. $response = $this->response->withCookieCollection($cookies);

Cookies set to responses can be encrypted using theEncrypted Cookie Middleware.

Reading Cookies

Once you have a CookieCollection instance, you can access the cookies itcontains:

  1. // Check if a cookie exists
  2. $cookies->has('remember_me');
  3.  
  4. // Get the number of cookies in the collection
  5. count($cookies);
  6.  
  7. // Get a cookie instance
  8. $cookie = $cookies->get('remember_me');

Once you have a Cookie object you can interact with it’s state and modifyit. Keep in mind that cookies are immutable, so you’ll need to update thecollection if you modify a cookie:

  1. // Get the value
  2. $value = $cookie->getValue()
  3.  
  4. // Access data inside a JSON value
  5. $id = $cookie->read('User.id');
  6.  
  7. // Check state
  8. $cookie->isHttpOnly();
  9. $cookie->isSecure();