You can serve a file in Symfony using the following code:
$response = new BinaryFileResponse($filepath);
// Set headers
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-Type', $file->getMimeType());
$response->headers->set('Content-Disposition', $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$file->getName()
));
return $response;
Make sure you also have:
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
How to get $file
is explained in the documentation of the Finder component you've linked. When you put the code in a controller in AppBundle you can use:
$filepath = __DIR__ . '/../Resources/myfile.txt';
Or you can use a path relative to your application root:
$rootDir = $this->get('kernel')->getRootDir();
$filepath = $rootDir. '/src/AppBundle/Resources/myfile.txt';
$filepath
could be an absolute path as well, but make sure that the webserver can read from that path. As long as the you use a path outside the webservers docroot (which is probably <your app root>/web
), you can control acces to the file using voters and other custom logic in PHP.
Getting the $file object:
In order to construct your fileobject you might use the Finder component, but this is actually nothing more that a wrapper around SPL filehandling. You could therefore also use:
$file = new \SplFileInfo($filepath);
Why BinaryFileResponse?
When sending large files, PHP might read the entire file into memory before sending it as a response to the client. This might cause PHP to run out of memory. Using BinaryFileResponse
avoids this by reading the file block-by-block and streaming those blocks to the client. Therefore, never send big files using a Response
object.
Using X-Sendfile:
While using the code above prevents PHP from running out of memory, it still keeps PHP busy while sending the file. When you have a busy webserver you might want to keep as many PHP processes as possible free to render webpages, not streaming files.
Luckely, instead of this:
Request ----> Webserver ----> PHP-FPM ----> File
Response <--- Webserver <---- PHP-FPM <---- File
You can do this:
Request ----> Webserver ----> PHP-FPM
Response <--- Webserver <---- PHP-FPM
^ |
| |
| V
File
This is done by using X-Sendfile.
That is wicked, how can I use that?
Getting X-Sendfile
to work requires two simple steps:
- Adding a header to your response that tells your webserver that it should server a file.
- Configuring your webserver to read that header and actually server that file.
The name of the header and how your webserver is configured depends on the type of webserver you are using:
Note that Nginx calls it X-Accel. The header you pass to Nginx is X-Accel-Redirect
but that is the only difference.