mirror of
https://github.com/symfony/symfony-docs.git
synced 2026-03-24 00:32:14 +01:00
707 lines
24 KiB
ReStructuredText
707 lines
24 KiB
ReStructuredText
.. index::
|
|
single: HTTP
|
|
single: HttpFoundation
|
|
single: Components; HttpFoundation
|
|
|
|
The HttpFoundation Component
|
|
============================
|
|
|
|
The HttpFoundation component defines an object-oriented layer for the HTTP
|
|
specification.
|
|
|
|
In PHP, the request is represented by some global variables (``$_GET``,
|
|
``$_POST``, ``$_FILES``, ``$_COOKIE``, ``$_SESSION``, ...) and the response is
|
|
generated by some functions (``echo``, ``header()``, ``setcookie()``, ...).
|
|
|
|
The Symfony HttpFoundation component replaces these default PHP global
|
|
variables and functions by an object-oriented layer.
|
|
|
|
Installation
|
|
------------
|
|
|
|
.. code-block:: terminal
|
|
|
|
$ composer require symfony/http-foundation
|
|
|
|
.. include:: /components/require_autoload.rst.inc
|
|
|
|
.. seealso::
|
|
|
|
This article explains how to use the HttpFoundation features as an
|
|
independent component in any PHP application. In Symfony applications
|
|
everything is already configured and ready to use. Read the :doc:`/controller`
|
|
article to learn about how to use these features when creating controllers.
|
|
|
|
.. _component-http-foundation-request:
|
|
|
|
Request
|
|
-------
|
|
|
|
The most common way to create a request is to base it on the current PHP global
|
|
variables with
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::createFromGlobals`::
|
|
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
|
|
$request = Request::createFromGlobals();
|
|
|
|
which is almost equivalent to the more verbose, but also more flexible,
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::__construct` call::
|
|
|
|
$request = new Request(
|
|
$_GET,
|
|
$_POST,
|
|
[],
|
|
$_COOKIE,
|
|
$_FILES,
|
|
$_SERVER
|
|
);
|
|
|
|
.. _accessing-request-data:
|
|
|
|
Accessing Request Data
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
A Request object holds information about the client request. This information
|
|
can be accessed via several public properties:
|
|
|
|
* ``request``: equivalent of ``$_POST``;
|
|
|
|
* ``query``: equivalent of ``$_GET`` (``$request->query->get('name')``);
|
|
|
|
* ``cookies``: equivalent of ``$_COOKIE``;
|
|
|
|
* ``attributes``: no equivalent - used by your app to store other data (see :ref:`below <component-foundation-attributes>`);
|
|
|
|
* ``files``: equivalent of ``$_FILES``;
|
|
|
|
* ``server``: equivalent of ``$_SERVER``;
|
|
|
|
* ``headers``: mostly equivalent to a subset of ``$_SERVER``
|
|
(``$request->headers->get('User-Agent')``).
|
|
|
|
Each property is a :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`
|
|
instance (or a sub-class of), which is a data holder class:
|
|
|
|
* ``request``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`;
|
|
|
|
* ``query``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`;
|
|
|
|
* ``cookies``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`;
|
|
|
|
* ``attributes``: :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`;
|
|
|
|
* ``files``: :class:`Symfony\\Component\\HttpFoundation\\FileBag`;
|
|
|
|
* ``server``: :class:`Symfony\\Component\\HttpFoundation\\ServerBag`;
|
|
|
|
* ``headers``: :class:`Symfony\\Component\\HttpFoundation\\HeaderBag`.
|
|
|
|
All :class:`Symfony\\Component\\HttpFoundation\\ParameterBag` instances have
|
|
methods to retrieve and update their data:
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::all`
|
|
Returns the parameters.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::keys`
|
|
Returns the parameter keys.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::replace`
|
|
Replaces the current parameters by a new set.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::add`
|
|
Adds parameters.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::get`
|
|
Returns a parameter by name.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::set`
|
|
Sets a parameter by name.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::has`
|
|
Returns ``true`` if the parameter is defined.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::remove`
|
|
Removes a parameter.
|
|
|
|
The :class:`Symfony\\Component\\HttpFoundation\\ParameterBag` instance also
|
|
has some methods to filter the input values:
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getAlpha`
|
|
Returns the alphabetic characters of the parameter value;
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getAlnum`
|
|
Returns the alphabetic characters and digits of the parameter value;
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getBoolean`
|
|
Returns the parameter value converted to boolean;
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getDigits`
|
|
Returns the digits of the parameter value;
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getInt`
|
|
Returns the parameter value converted to integer;
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\ParameterBag::filter`
|
|
Filters the parameter by using the PHP :phpfunction:`filter_var` function.
|
|
|
|
All getters take up to two arguments: the first one is the parameter name
|
|
and the second one is the default value to return if the parameter does not
|
|
exist::
|
|
|
|
// the query string is '?foo=bar'
|
|
|
|
$request->query->get('foo');
|
|
// returns 'bar'
|
|
|
|
$request->query->get('bar');
|
|
// returns null
|
|
|
|
$request->query->get('bar', 'baz');
|
|
// returns 'baz'
|
|
|
|
When PHP imports the request query, it handles request parameters like
|
|
``foo[bar]=baz`` in a special way as it creates an array. So you can get the
|
|
``foo`` parameter and you will get back an array with a ``bar`` element::
|
|
|
|
// the query string is '?foo[bar]=baz'
|
|
|
|
$request->query->get('foo');
|
|
// returns ['bar' => 'baz']
|
|
|
|
$request->query->get('foo[bar]');
|
|
// returns null
|
|
|
|
$request->query->get('foo')['bar'];
|
|
// returns 'baz'
|
|
|
|
.. _component-foundation-attributes:
|
|
|
|
Thanks to the public ``attributes`` property, you can store additional data
|
|
in the request, which is also an instance of
|
|
:class:`Symfony\\Component\\HttpFoundation\\ParameterBag`. This is mostly used
|
|
to attach information that belongs to the Request and that needs to be
|
|
accessed from many different points in your application.
|
|
|
|
Finally, the raw data sent with the request body can be accessed using
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::getContent`::
|
|
|
|
$content = $request->getContent();
|
|
|
|
For instance, this may be useful to process a JSON string sent to the
|
|
application by a remote service using the HTTP POST method.
|
|
|
|
Identifying a Request
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
In your application, you need a way to identify a request; most of the time,
|
|
this is done via the "path info" of the request, which can be accessed via the
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::getPathInfo` method::
|
|
|
|
// for a request to http://example.com/blog/index.php/post/hello-world
|
|
// the path info is "/post/hello-world"
|
|
$request->getPathInfo();
|
|
|
|
Simulating a Request
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Instead of creating a request based on the PHP globals, you can also simulate
|
|
a request::
|
|
|
|
$request = Request::create(
|
|
'/hello-world',
|
|
'GET',
|
|
['name' => 'Fabien']
|
|
);
|
|
|
|
The :method:`Symfony\\Component\\HttpFoundation\\Request::create` method
|
|
creates a request based on a URI, a method and some parameters (the
|
|
query parameters or the request ones depending on the HTTP method); and of
|
|
course, you can also override all other variables as well (by default, Symfony
|
|
creates sensible defaults for all the PHP global variables).
|
|
|
|
Based on such a request, you can override the PHP global variables via
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::overrideGlobals`::
|
|
|
|
$request->overrideGlobals();
|
|
|
|
.. tip::
|
|
|
|
You can also duplicate an existing request via
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::duplicate` or
|
|
change a bunch of parameters with a single call to
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::initialize`.
|
|
|
|
Accessing the Session
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
If you have a session attached to the request, you can access it via the
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::getSession` method;
|
|
the
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::hasPreviousSession`
|
|
method tells you if the request contains a session which was started in one of
|
|
the previous requests.
|
|
|
|
Processing HTTP Headers
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Processing HTTP headers is not a trivial task because of the escaping and white
|
|
space handling of their contents. Symfony provides a
|
|
:class:`Symfony\\Component\\HttpFoundation\\HeaderUtils` class that abstracts
|
|
this complexity and defines some methods for the most common tasks::
|
|
|
|
use Symfony\Component\HttpFoundation\HeaderUtils;
|
|
|
|
// Splits an HTTP header by one or more separators
|
|
HeaderUtils::split('da, en-gb;q=0.8', ',;');
|
|
// => [['da'], ['en-gb','q=0.8']]
|
|
|
|
// Combines an array of arrays into one associative array
|
|
HeaderUtils::combine([['foo', 'abc'], ['bar']]);
|
|
// => ['foo' => 'abc', 'bar' => true]
|
|
|
|
// Joins an associative array into a string for use in an HTTP header
|
|
HeaderUtils::toString(['foo' => 'abc', 'bar' => true, 'baz' => 'a b c'], ',');
|
|
// => 'foo=abc, bar, baz="a b c"'
|
|
|
|
// Encodes a string as a quoted string, if necessary
|
|
HeaderUtils::quote('foo "bar"');
|
|
// => '"foo \"bar\""'
|
|
|
|
// Decodes a quoted string
|
|
HeaderUtils::unquote('"foo \"bar\""');
|
|
// => 'foo "bar"'
|
|
|
|
Accessing ``Accept-*`` Headers Data
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
You can access basic data extracted from ``Accept-*`` headers
|
|
by using the following methods:
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::getAcceptableContentTypes`
|
|
Returns the list of accepted content types ordered by descending quality.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::getLanguages`
|
|
Returns the list of accepted languages ordered by descending quality.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::getCharsets`
|
|
Returns the list of accepted charsets ordered by descending quality.
|
|
|
|
:method:`Symfony\\Component\\HttpFoundation\\Request::getEncodings`
|
|
Returns the list of accepted encodings ordered by descending quality.
|
|
|
|
If you need to get full access to parsed data from ``Accept``, ``Accept-Language``,
|
|
``Accept-Charset`` or ``Accept-Encoding``, you can use
|
|
:class:`Symfony\\Component\\HttpFoundation\\AcceptHeader` utility class::
|
|
|
|
use Symfony\Component\HttpFoundation\AcceptHeader;
|
|
|
|
$acceptHeader = AcceptHeader::fromString($request->headers->get('Accept'));
|
|
if ($acceptHeader->has('text/html')) {
|
|
$item = $acceptHeader->get('text/html');
|
|
$charset = $item->getAttribute('charset', 'utf-8');
|
|
$quality = $item->getQuality();
|
|
}
|
|
|
|
// Accept header items are sorted by descending quality
|
|
$acceptHeaders = AcceptHeader::fromString($request->headers->get('Accept'))
|
|
->all();
|
|
|
|
The default values that can be optionally included in the ``Accept-*`` headers
|
|
are also supported::
|
|
|
|
$acceptHeader = 'text/plain;q=0.5, text/html, text/*;q=0.8, */*;q=0.3';
|
|
$accept = AcceptHeader::fromString($acceptHeader);
|
|
|
|
$quality = $accept->get('text/xml')->getQuality(); // $quality = 0.8
|
|
$quality = $accept->get('application/xml')->getQuality(); // $quality = 0.3
|
|
|
|
Accessing other Data
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The ``Request`` class has many other methods that you can use to access the
|
|
request information. Have a look at
|
|
:class:`the Request API <Symfony\\Component\\HttpFoundation\\Request>`
|
|
for more information about them.
|
|
|
|
Overriding the Request
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The ``Request`` class should not be overridden as it is a data object that
|
|
represents an HTTP message. But when moving from a legacy system, adding
|
|
methods or changing some default behavior might help. In that case, register a
|
|
PHP callable that is able to create an instance of your ``Request`` class::
|
|
|
|
use App\Http\SpecialRequest;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
|
|
Request::setFactory(function (
|
|
array $query = [],
|
|
array $request = [],
|
|
array $attributes = [],
|
|
array $cookies = [],
|
|
array $files = [],
|
|
array $server = [],
|
|
$content = null
|
|
) {
|
|
return new SpecialRequest(
|
|
$query,
|
|
$request,
|
|
$attributes,
|
|
$cookies,
|
|
$files,
|
|
$server,
|
|
$content
|
|
);
|
|
});
|
|
|
|
$request = Request::createFromGlobals();
|
|
|
|
.. _component-http-foundation-response:
|
|
|
|
Response
|
|
--------
|
|
|
|
A :class:`Symfony\\Component\\HttpFoundation\\Response` object holds all the
|
|
information that needs to be sent back to the client from a given request. The
|
|
constructor takes up to three arguments: the response content, the status
|
|
code, and an array of HTTP headers::
|
|
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
$response = new Response(
|
|
'Content',
|
|
Response::HTTP_OK,
|
|
['content-type' => 'text/html']
|
|
);
|
|
|
|
This information can also be manipulated after the Response object creation::
|
|
|
|
$response->setContent('Hello World');
|
|
|
|
// the headers public attribute is a ResponseHeaderBag
|
|
$response->headers->set('Content-Type', 'text/plain');
|
|
|
|
$response->setStatusCode(Response::HTTP_NOT_FOUND);
|
|
|
|
When setting the ``Content-Type`` of the Response, you can set the charset,
|
|
but it is better to set it via the
|
|
:method:`Symfony\\Component\\HttpFoundation\\Response::setCharset` method::
|
|
|
|
$response->setCharset('ISO-8859-1');
|
|
|
|
Note that by default, Symfony assumes that your Responses are encoded in
|
|
UTF-8.
|
|
|
|
Sending the Response
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Before sending the Response, you can optionally call the
|
|
:method:`Symfony\\Component\\HttpFoundation\\Response::prepare` method to fix any
|
|
incompatibility with the HTTP specification (e.g. a wrong ``Content-Type`` header)::
|
|
|
|
$response->prepare($request);
|
|
|
|
Sending the response to the client is done by calling the method
|
|
:method:`Symfony\\Component\\HttpFoundation\\Response::send`::
|
|
|
|
$response->send();
|
|
|
|
Setting Cookies
|
|
~~~~~~~~~~~~~~~
|
|
|
|
The response cookies can be manipulated through the ``headers`` public
|
|
attribute::
|
|
|
|
use Symfony\Component\HttpFoundation\Cookie;
|
|
|
|
$response->headers->setCookie(Cookie::create('foo', 'bar'));
|
|
|
|
The
|
|
:method:`Symfony\\Component\\HttpFoundation\\ResponseHeaderBag::setCookie`
|
|
method takes an instance of
|
|
:class:`Symfony\\Component\\HttpFoundation\\Cookie` as an argument.
|
|
|
|
You can clear a cookie via the
|
|
:method:`Symfony\\Component\\HttpFoundation\\ResponseHeaderBag::clearCookie` method.
|
|
|
|
Note you can create a
|
|
:class:`Symfony\\Component\\HttpFoundation\\Cookie` object from a raw header
|
|
value using :method:`Symfony\\Component\\HttpFoundation\\Cookie::fromString`.
|
|
|
|
Managing the HTTP Cache
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The :class:`Symfony\\Component\\HttpFoundation\\Response` class has a rich set
|
|
of methods to manipulate the HTTP headers related to the cache:
|
|
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setPublic`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setPrivate`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::expire`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setExpires`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setMaxAge`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setSharedMaxAge`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setTtl`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setClientTtl`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setLastModified`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setEtag`;
|
|
* :method:`Symfony\\Component\\HttpFoundation\\Response::setVary`;
|
|
|
|
.. note::
|
|
|
|
The methods :method:`Symfony\\Component\\HttpFoundation\\Response::setExpires`,
|
|
:method:`Symfony\\Component\\HttpFoundation\\Response::setLastModified` and
|
|
:method:`Symfony\\Component\\HttpFoundation\\Response::setDate` accept any
|
|
object that implements ``\DateTimeInterface``, including immutable date objects.
|
|
|
|
The :method:`Symfony\\Component\\HttpFoundation\\Response::setCache` method
|
|
can be used to set the most commonly used cache information in one method
|
|
call::
|
|
|
|
$response->setCache([
|
|
'etag' => 'abcdef',
|
|
'last_modified' => new \DateTime(),
|
|
'max_age' => 600,
|
|
's_maxage' => 600,
|
|
'private' => false,
|
|
'public' => true,
|
|
]);
|
|
|
|
To check if the Response validators (``ETag``, ``Last-Modified``) match a
|
|
conditional value specified in the client Request, use the
|
|
:method:`Symfony\\Component\\HttpFoundation\\Response::isNotModified`
|
|
method::
|
|
|
|
if ($response->isNotModified($request)) {
|
|
$response->send();
|
|
}
|
|
|
|
If the Response is not modified, it sets the status code to 304 and removes the
|
|
actual response content.
|
|
|
|
.. _redirect-response:
|
|
|
|
Redirecting the User
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
To redirect the client to another URL, you can use the
|
|
:class:`Symfony\\Component\\HttpFoundation\\RedirectResponse` class::
|
|
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
|
|
$response = new RedirectResponse('http://example.com/');
|
|
|
|
.. _streaming-response:
|
|
|
|
Streaming a Response
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The :class:`Symfony\\Component\\HttpFoundation\\StreamedResponse` class allows
|
|
you to stream the Response back to the client. The response content is
|
|
represented by a PHP callable instead of a string::
|
|
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
$response = new StreamedResponse();
|
|
$response->setCallback(function () {
|
|
var_dump('Hello World');
|
|
flush();
|
|
sleep(2);
|
|
var_dump('Hello World');
|
|
flush();
|
|
});
|
|
$response->send();
|
|
|
|
.. note::
|
|
|
|
The ``flush()`` function does not flush buffering. If ``ob_start()`` has
|
|
been called before or the ``output_buffering`` ``php.ini`` option is enabled,
|
|
you must call ``ob_flush()`` before ``flush()``.
|
|
|
|
Additionally, PHP isn't the only layer that can buffer output. Your web
|
|
server might also buffer based on its configuration. Some servers, such as
|
|
Nginx, let you disable buffering at the config level or by adding a special HTTP
|
|
header in the response::
|
|
|
|
// disables FastCGI buffering in Nginx only for this response
|
|
$response->headers->set('X-Accel-Buffering', 'no')
|
|
|
|
.. _component-http-foundation-serving-files:
|
|
|
|
Serving Files
|
|
~~~~~~~~~~~~~
|
|
|
|
When sending a file, you must add a ``Content-Disposition`` header to your
|
|
response. While creating this header for basic file downloads is straightforward,
|
|
using non-ASCII filenames is more involving. The
|
|
:method:`Symfony\\Component\\HttpFoundation\\HeaderUtils::makeDisposition`
|
|
abstracts the hard work behind a simple API::
|
|
|
|
use Symfony\Component\HttpFoundation\HeaderUtils;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
|
|
|
$fileContent = ...; // the generated file content
|
|
$response = new Response($fileContent);
|
|
|
|
$disposition = HeaderUtils::makeDisposition(
|
|
HeaderUtils::DISPOSITION_ATTACHMENT,
|
|
'foo.pdf'
|
|
);
|
|
|
|
$response->headers->set('Content-Disposition', $disposition);
|
|
|
|
Alternatively, if you are serving a static file, you can use a
|
|
:class:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse`::
|
|
|
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
|
|
|
$file = 'path/to/file.txt';
|
|
$response = new BinaryFileResponse($file);
|
|
|
|
The ``BinaryFileResponse`` will automatically handle ``Range`` and
|
|
``If-Range`` headers from the request. It also supports ``X-Sendfile``
|
|
(see for `Nginx`_ and `Apache`_). To make use of it, you need to determine
|
|
whether or not the ``X-Sendfile-Type`` header should be trusted and call
|
|
:method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::trustXSendfileTypeHeader`
|
|
if it should::
|
|
|
|
BinaryFileResponse::trustXSendfileTypeHeader();
|
|
|
|
.. note::
|
|
|
|
The ``BinaryFileResponse`` will only handle ``X-Sendfile`` if the particular header is present.
|
|
For Apache, this is not the default case.
|
|
|
|
To add the header use the ``mod_headers`` Apache module and add the following to the Apache configuration:
|
|
|
|
.. code-block:: apache
|
|
|
|
<IfModule mod_xsendfile.c>
|
|
# This is already present somewhere...
|
|
XSendFile on
|
|
XSendFilePath ...some path...
|
|
|
|
# This needs to be added:
|
|
<IfModule mod_headers.c>
|
|
RequestHeader set X-Sendfile-Type X-Sendfile
|
|
</IfModule>
|
|
</IfModule>
|
|
|
|
With the ``BinaryFileResponse``, you can still set the ``Content-Type`` of the sent file,
|
|
or change its ``Content-Disposition``::
|
|
|
|
// ...
|
|
$response->headers->set('Content-Type', 'text/plain');
|
|
$response->setContentDisposition(
|
|
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
|
'filename.txt'
|
|
);
|
|
|
|
It is possible to delete the file after the request is sent with the
|
|
:method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::deleteFileAfterSend` method.
|
|
Please note that this will not work when the ``X-Sendfile`` header is set.
|
|
|
|
If the size of the served file is unknown (e.g. because it's being generated on the fly,
|
|
or because a PHP stream filter is registered on it, etc.), you can pass a ``Stream``
|
|
instance to ``BinaryFileResponse``. This will disable ``Range`` and ``Content-Length``
|
|
handling, switching to chunked encoding instead::
|
|
|
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
|
use Symfony\Component\HttpFoundation\File\Stream;
|
|
|
|
$stream = new Stream('path/to/stream');
|
|
$response = new BinaryFileResponse($stream);
|
|
|
|
.. note::
|
|
|
|
If you *just* created the file during this same request, the file *may* be sent
|
|
without any content. This may be due to cached file stats that return zero for
|
|
the size of the file. To fix this issue, call ``clearstatcache(true, $file)``
|
|
with the path to the binary file.
|
|
|
|
.. _component-http-foundation-json-response:
|
|
|
|
Creating a JSON Response
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Any type of response can be created via the
|
|
:class:`Symfony\\Component\\HttpFoundation\\Response` class by setting the
|
|
right content and headers. A JSON response might look like this::
|
|
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
$response = new Response();
|
|
$response->setContent(json_encode([
|
|
'data' => 123,
|
|
]));
|
|
$response->headers->set('Content-Type', 'application/json');
|
|
|
|
There is also a helpful :class:`Symfony\\Component\\HttpFoundation\\JsonResponse`
|
|
class, which can make this even easier::
|
|
|
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
|
|
// if you know the data to send when creating the response
|
|
$response = new JsonResponse(['data' => 123]);
|
|
|
|
// if you don't know the data to send when creating the response
|
|
$response = new JsonResponse();
|
|
// ...
|
|
$response->setData(['data' => 123]);
|
|
|
|
// if the data to send is already encoded in JSON
|
|
$response = JsonResponse::fromJsonString('{ "data": 123 }');
|
|
|
|
The ``JsonResponse`` class sets the ``Content-Type`` header to
|
|
``application/json`` and encodes your data to JSON when needed.
|
|
|
|
.. caution::
|
|
|
|
To avoid XSSI `JSON Hijacking`_, you should pass an associative array
|
|
as the outer-most array to ``JsonResponse`` and not an indexed array so
|
|
that the final result is an object (e.g. ``{"object": "not inside an array"}``)
|
|
instead of an array (e.g. ``[{"object": "inside an array"}]``). Read
|
|
the `OWASP guidelines`_ for more information.
|
|
|
|
Only methods that respond to GET requests are vulnerable to XSSI 'JSON Hijacking'.
|
|
Methods responding to POST requests only remain unaffected.
|
|
|
|
JSONP Callback
|
|
~~~~~~~~~~~~~~
|
|
|
|
If you're using JSONP, you can set the callback function that the data should
|
|
be passed to::
|
|
|
|
$response->setCallback('handleResponse');
|
|
|
|
In this case, the ``Content-Type`` header will be ``text/javascript`` and
|
|
the response content will look like this:
|
|
|
|
.. code-block:: javascript
|
|
|
|
handleResponse({'data': 123});
|
|
|
|
Session
|
|
-------
|
|
|
|
The session information is in its own document: :doc:`/components/http_foundation/sessions`.
|
|
|
|
Learn More
|
|
----------
|
|
|
|
.. toctree::
|
|
:maxdepth: 1
|
|
:glob:
|
|
|
|
/components/http_foundation/*
|
|
/controller
|
|
/controller/*
|
|
/session/*
|
|
/http_cache/*
|
|
|
|
.. _Nginx: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/
|
|
.. _Apache: https://tn123.org/mod_xsendfile/
|
|
.. _`JSON Hijacking`: http://haacked.com/archive/2009/06/25/json-hijacking.aspx
|
|
.. _OWASP guidelines: https://www.owasp.org/index.php/OWASP_AJAX_Security_Guidelines#Always_return_JSON_with_an_Object_on_the_outside
|