The HttpFoundation Component ¶
The HttpFoundation component defines an object-oriented layer for the HTTP specification.
HttpFoundation コンポーネントは、HTTP 仕様のオブジェクト指向レイヤーを定義します。
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 ¶
1 |
$ composer require symfony/http-foundation
|
Note
If you install this component outside of a Symfony application, you must
require the vendor/autoload.php
file in your code to enable the class
autoloading mechanism provided by Composer. Read
this article for more details.
See also
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 Controller article to learn about how to use these features when creating controllers.
Request ¶
The most common way to create a request is to base it on the current PHP global variables with createFromGlobals():
1 2 3 |
use Symfony\Component\HttpFoundation\Request;
$request = Request::createFromGlobals();
|
which is almost equivalent to the more verbose, but also more flexible, __construct() call:
1 2 3 4 5 6 7 8 |
$request = new Request(
$_GET,
$_POST,
[],
$_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
;request: $_POST と同等。query
: equivalent of$_GET
($request->query->get('name')
);クエリ: $_GET ($request->query->get('name')); と同等cookies
: equivalent of$_COOKIE
;クッキー: $_COOKIE と同等。attributes
: no equivalent - used by your app to store other data (see below);attributes: 同等のものはありません - アプリで他のデータを保存するために使用されます (以下を参照)。files
: equivalent of$_FILES
;ファイル: $_FILES と同等。server
: equivalent of$_SERVER
;サーバー: $_SERVER と同等。headers
: mostly equivalent to a subset of$_SERVER
($request->headers->get('User-Agent')
).headers: ほとんど $_SERVER($request->headers->get('User-Agent')) のサブセットと同等です。
Each property is a ParameterBag instance (or a subclass of), which is a data holder class:
request
: ParameterBag or InputBag if the data is coming from$_POST
parameters;request: データが $_POST パラメーターから来ている場合は ParameterBag または InputBag。query
: InputBag;クエリ: 入力バッグ;cookies
: InputBag;クッキー: 入力バッグ;attributes
: ParameterBag;属性: ParameterBag;files
: FileBag;ファイル: FileBag;server
: ServerBag;サーバー: ServerBag;headers
: HeaderBag.ヘッダー: ヘッダーバッグ。
All ParameterBag instances have methods to retrieve and update their data:
- all()
-
Returns the parameters.
パラメータを返します。
- keys()
-
Returns the parameter keys.
パラメータ キーを返します。
- replace()
-
Replaces the current parameters by a new set.
現在のパラメータを新しいセットに置き換えます。
- add()
-
Adds parameters.
パラメータを追加します。
- get()
-
Returns a parameter by name.
パラメータを名前で返します。
- set()
-
Sets a parameter by name.
パラメータを名前で設定します。
- has()
-
Returns
true
if the parameter is defined.パラメータが定義されている場合は true を返します。 - remove()
-
Removes a parameter.
パラメータを削除します。
The ParameterBag instance also has some methods to filter the input values:
- getAlpha()
-
Returns the alphabetic characters of the parameter value;
パラメータ値の英字を返します。
- getAlnum()
-
Returns the alphabetic characters and digits of the parameter value;
パラメータ値の英字と数字を返します。
- getBoolean()
-
Returns the parameter value converted to boolean;
ブール値に変換されたパラメーター値を返します。
- getDigits()
-
Returns the digits of the parameter value;
パラメータ値の桁を返します。
- getInt()
-
Returns the parameter value converted to integer;
整数に変換されたパラメーター値を返します。
- filter()
-
Filters the parameter by using the PHP filter_var function.
PHP の filter_var 関数を使用してパラメーターをフィルター処理します。
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:
1 2 3 4 5 6 7 8 9 10 |
// 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. The get()
method
doesn't support returning arrays, so you need to use the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// the query string is '?foo[bar]=baz'
// don't use $request->query->get('foo'); use the following instead:
$request->query->all('foo');
// returns ['bar' => 'baz']
// if the requested parameter does not exist, an empty array is returned:
$request->query->all('qux');
// returns []
$request->query->get('foo[bar]');
// returns null
$request->query->all()['foo']['bar'];
// returns 'baz'
|
Thanks to the public attributes
property, you can store additional data
in the request, which is also an instance of
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 getContent():
1 |
$content = $request->getContent();
|
For instance, this may be useful to process an XML string sent to the application by a remote service using the HTTP POST method.
If the request body is a JSON string, it can be accessed using toArray():
1 |
$data = $request->toArray();
|
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 getPathInfo() method:
1 2 3 |
// 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:
1 2 3 4 5 |
$request = Request::create(
'/hello-world',
'GET',
['name' => 'Fabien']
);
|
The 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 overrideGlobals():
1 |
$request->overrideGlobals();
|
Tip
You can also duplicate an existing request via duplicate() or change a bunch of parameters with a single call to initialize().
Accessing the Session ¶
If you have a session attached to the request, you can access it via the
getSession()
method of the Request
or RequestStack class;
the 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 HeaderUtils class that abstracts this complexity and defines some methods for the most common tasks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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"'
// Parses a query string but maintains dots (PHP parse_str() replaces '.' by '_')
HeaderUtils::parseQuery('foo[bar.baz]=qux');
// => ['foo' => ['bar.baz' => 'qux']]
|
Accessing Accept-*
Headers Data
¶
You can access basic data extracted from Accept-*
headers
by using the following methods:
- getAcceptableContentTypes()
-
Returns the list of accepted content types ordered by descending quality.
受け入れられたコンテンツ タイプのリストを、品質の降順で並べ替えて返します。
- getLanguages()
-
Returns the list of accepted languages ordered by descending quality.
品質の降順で並べられた受け入れられた言語のリストを返します。
- getCharsets()
-
Returns the list of accepted charsets ordered by descending quality.
品質の降順で並べられた、受け入れられた文字セットのリストを返します。
- 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
AcceptHeader utility class:
1 2 3 4 5 6 7 8 9 10 11 12 |
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:
1 2 3 4 5 |
$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
|
Anonymizing IP Addresses ¶
An increasingly common need for applications to comply with user protection
regulations is to anonymize IP addresses before logging and storing them for
analysis purposes. Use the anonymize()
method from the
IpUtils to do that:
1 2 3 4 5 6 7 8 9 |
use Symfony\Component\HttpFoundation\IpUtils;
$ipv4 = '123.234.235.236';
$anonymousIpv4 = IpUtils::anonymize($ipv4);
// $anonymousIpv4 = '123.234.235.0'
$ipv6 = '2a01:198:603:10:396e:4789:8e99:890f';
$anonymousIpv6 = IpUtils::anonymize($ipv6);
// $anonymousIpv6 = '2a01:198:603:10::'
|
Accessing other Data ¶
The Request
class has many other methods that you can use to access the
request information. Have a look at
the Request API
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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();
|
Response ¶
A 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:
1 2 3 4 5 6 7 |
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:
1 2 3 4 5 6 |
$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
setCharset() method:
1 |
$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
prepare() method to fix any
incompatibility with the HTTP specification (e.g. a wrong Content-Type
header):
1 |
$response->prepare($request);
|
Sending the response to the client is done by calling the method send():
1 |
$response->send();
|
Setting Cookies ¶
The response cookies can be manipulated through the headers
public
attribute:
1 2 3 |
use Symfony\Component\HttpFoundation\Cookie;
$response->headers->setCookie(Cookie::create('foo', 'bar'));
|
The setCookie() method takes an instance of Cookie as an argument.
You can clear a cookie via the clearCookie() method.
In addition to the Cookie::create()
method, you can create a Cookie
object from a raw header value using fromString()
method. You can also use the with*()
methods to change some Cookie property (or
to build the entire Cookie using a fluent interface). Each with*()
method returns
a new object with the modified property:
1 2 3 4 5 |
$cookie = Cookie::create('foo')
->withValue('bar')
->withExpires(strtotime('Fri, 20-May-2011 15:25:52 GMT'))
->withDomain('.example.com')
->withSecure(true);
|
Managing the HTTP Cache ¶
The Response class has a rich set of methods to manipulate the HTTP headers related to the cache:
- setPublic()setPublic()
- setPrivate()setPrivate()
- expire()期限切れ()
- setExpires()setExpires()
- setMaxAge()setMaxAge()
- setSharedMaxAge()setSharedMaxAge()
- setStaleIfError()setStaleIfError()
- setStaleWhileRevalidate()setStaleWhileRevalidate()
- setTtl()setTtl()
- setClientTtl()setClientTtl()
- setLastModified()setLastModified()
- setEtag()setEtag()
- setVary()setVary()
Note
The methods setExpires(),
setLastModified() and
setDate() accept any
object that implements \DateTimeInterface
, including immutable date objects.
The setCache() method can be used to set the most commonly used cache information in one method call:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$response->setCache([
'must_revalidate' => false,
'no_cache' => false,
'no_store' => false,
'no_transform' => false,
'public' => true,
'private' => false,
'proxy_revalidate' => false,
'max_age' => 600,
's_maxage' => 600,
'stale_if_error' => 86400,
'stale_while_revalidate' => 60,
'immutable' => true,
'last_modified' => new \DateTime(),
'etag' => 'abcdef',
]);
|
6.1
The stale_if_error
and stale_while_revalidate
options were
introduced in Symfony 6.1.
To check if the Response validators (ETag
, Last-Modified
) match a
conditional value specified in the client Request, use the
isNotModified()
method:
1 2 3 |
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 RedirectResponse class:
1 2 3 |
use Symfony\Component\HttpFoundation\RedirectResponse;
$response = new RedirectResponse('http://example.com/');
|
Streaming a Response ¶
The 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:
1 2 3 4 5 6 7 8 9 10 11 |
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:
1 2 |
// disables FastCGI buffering in nginx only for this response
$response->headers->set('X-Accel-Buffering', 'no');
|
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 involved. The
makeDisposition()
abstracts the hard work behind a simple API:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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 BinaryFileResponse:
1 2 3 4 |
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
trustXSendfileTypeHeader()
if it should:
1 |
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:
1 2 3 4 5 6 7 8 9 10 |
<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
:
1 2 3 4 5 6 |
// ...
$response->headers->set('Content-Type', 'text/plain');
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
'filename.txt'
);
|
It is possible to delete the file after the response is sent with the
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:
1 2 3 4 5 |
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.
Creating a JSON Response ¶
Any type of response can be created via the Response class by setting the right content and headers. A JSON response might look like this:
1 2 3 4 5 6 7 |
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 JsonResponse class, which can make this even easier:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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 or if you want to customize the encoding options
$response = new JsonResponse();
// ...
// configure any custom encoding options (if needed, it must be called before "setData()")
//$response->setEncodingOptions(JsonResponse::DEFAULT_ENCODING_OPTIONS | \JSON_PRESERVE_ZERO_FRACTION);
$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 outermost 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:
1 |
$response->setCallback('handleResponse');
|
In this case, the Content-Type
header will be text/javascript
and
the response content will look like this:
1 |
handleResponse({'data': 123});
|
Session ¶
The session information is in its own document: Session Management.
Safe Content Preference ¶
Some web sites have a "safe" mode to assist those who don't want to be exposed to content to which they might object. The RFC 8674 specification defines a way for user agents to ask for safe content to a server.
The specification does not define what content might be considered objectionable, so the concept of "safe" is not precisely defined. Rather, the term is interpreted by the server and within the scope of each web site that chooses to act upon this information.
Symfony offers two methods to interact with this preference:
- preferSafeContent();preferSafeContent();
- setContentSafe();setContentSafe();
The following example shows how to detect if the user agent prefers "safe" content:
1 2 3 4 5 6 |
if ($request->preferSafeContent()) {
$response = new Response($alternativeContent);
// this informs the user we respected their preferences
$response->setContentSafe();
return $response;
|
Generating Relative and Absolute URLs ¶
Generating absolute and relative URLs for a given path is a common need in some applications. In Twig templates you can use the absolute_url() and relative_path() functions to do that.
The UrlHelper class provides the
same functionality for PHP code via the getAbsoluteUrl()
and getRelativePath()
methods. You can inject this as a service anywhere in your application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// src/Normalizer/UserApiNormalizer.php
namespace App\Normalizer;
use Symfony\Component\HttpFoundation\UrlHelper;
class UserApiNormalizer
{
private UrlHelper $urlHelper;
public function __construct(UrlHelper $urlHelper)
{
$this->urlHelper = $urlHelper;
}
public function normalize($user)
{
return [
'avatar' => $this->urlHelper->getAbsoluteUrl($user->avatar()->path()),
];
}
}
|
Learn More ¶
- Configuring Sessions and Save Handlersセッションと保存ハンドラの構成
- Integrating with Legacy Sessionsレガシー セッションとの統合
- Testing with Sessionsセッションでのテスト
- Session Managementセッション管理
- Controllerコントローラ
- How to Customize Error Pagesエラーページをカスタマイズする方法
- How to Forward Requests to another Controllerリクエストを別のコントローラに転送する方法
- How to Define Controllers as Servicesコントローラーをサービスとして定義する方法
- How to Create a SOAP Web Service in a Symfony ControllerSymfony コントローラーで SOAP Web サービスを作成する方法
- How to Upload Filesファイルのアップロード方法
- Extending Action Argument Resolvingアクション引数の解決の拡張
- Configuring the Session TTLセッション TTL の設定
- Store Sessions in a Databaseセッションをデータベースに保存する
- Making the Locale "Sticky" during a User's Sessionユーザーのセッション中にロケールを「スティッキー」にする
- Bridge a legacy Application with Symfony SessionsSymfony セッションを使用してレガシー アプリケーションをブリッジする
- Session Proxy Examplesセッション プロキシの例
- Cache Invalidationキャッシュの無効化
- Varying the Response for HTTP CacheHTTP キャッシュに対する応答の変更
- Working with Edge Side Includesエッジ サイド インクルードの操作
- HTTP Cache ExpirationHTTP キャッシュの有効期限
- Working with Server Side Includesサーバーサイドインクルードの操作
- HTTP Cache ValidationHTTP キャッシュの検証
- How to Use Varnish to Speed up my Websiteワニスを使用してウェブサイトを高速化する方法