.. 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 Symfony2 HttpFoundation component replaces these default PHP global variables and functions by an object-oriented layer. Installation ------------ You can install the component in 2 different ways: * :doc:`Install it via Composer ` (``symfony/http-foundation`` on `Packagist`_); * Use the official Git repository (https://github.com/symfony/HttpFoundation). .. _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, array(), $_COOKIE, $_FILES, $_SERVER ); 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 `); * ``files``: equivalent of ``$_FILES``; * ``server``: equivalent of ``$_SERVER``; * ``headers``: mostly equivalent to a sub-set 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 its 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::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 takes up to three 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', 'bar'); // returns 'bar' When PHP imports the request query, it handles request parameters like ``foo[bar]=bar`` 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. But sometimes, you might want to get the value for the "original" parameter name: ``foo[bar]``. This is possible with all the ``ParameterBag`` getters like :method:`Symfony\\Component\\HttpFoundation\\Request::get` via the third argument:: // the query string is '?foo[bar]=bar' $request->query->get('foo'); // returns array('bar' => 'bar') $request->query->get('foo[bar]'); // returns null $request->query->get('foo[bar]', null, true); // returns 'bar' .. _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. For information on how this is used in the Symfony2 framework, see :ref:`the Symfony2 book `. 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', array('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. Accessing `Accept-*` Headers Data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can easily 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 charsets ordered by descending quality; .. versionadded:: 2.4 The ``getEncodings()`` method was introduced in Symfony 2.4. 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; $accept = AcceptHeader::fromString($request->headers->get('Accept')); if ($accept->has('text/html')) { $item = $accept->get('text/html'); $charset = $item->getAttribute('charset', 'utf-8'); $quality = $item->getQuality(); } // Accept header items are sorted by descending quality $accepts = AcceptHeader::fromString($request->headers->get('Accept')) ->all(); 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 ` for more information about them. Overriding the Request ~~~~~~~~~~~~~~~~~~~~~~ .. versionadded:: 2.4 The :method:`Symfony\\Component\\HttpFoundation\\Request::setFactory` method was introduced in Symfony 2.4. 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 Symfony\Component\HttpFoundation\Request; Request::setFactory(function ( array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null ) { return SpecialRequest::create( $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, array('content-type' => 'text/html') ); .. versionadded:: 2.4 Support for HTTP status code constants was introduced in Symfony 2.4. These 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 ensure that it is compliant with the HTTP specification by calling the :method:`Symfony\\Component\\HttpFoundation\\Response::prepare` method:: $response->prepare($request); Sending the response to the client is then as simple as calling :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(new Cookie('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. 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`; 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(array( '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. 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 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 () { echo 'Hello World'; flush(); sleep(2); echo '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. Even more, if you use fastcgi, buffering can't be disabled at all. .. _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 easy, using non-ASCII filenames is more involving. The :method:`Symfony\\Component\\HttpFoundation\\Response::makeDisposition` abstracts the hard work behind a simple API:: use Symfony\Component\HttpFoundation\ResponseHeaderBag; $d = $response->headers->makeDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'foo.pdf' ); $response->headers->set('Content-Disposition', $d); 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(); 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' ); .. _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(array( '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; $response = new JsonResponse(); $response->setData(array( 'data' => 123 )); This encodes your array of data to JSON and sets the ``Content-Type`` header to ``application/json``. .. 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`. .. _Packagist: https://packagist.org/packages/symfony/http-foundation .. _Nginx: http://wiki.nginx.org/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