8000 [HttpFoundation] Added BinaryFileResponse by jalliot · Pull Request #2606 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[HttpFoundation] Added BinaryFileResponse #2606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[HttpFoundation] Added BinaryFileResponse
  • Loading branch information
jalliot committed Nov 17, 2011
commit fe73dfb04d7da5789d82ac87cc980eac96f4b3d7
138 changes: 138 additions & 0 deletions src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\HttpFoundation;

use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;

/**
* BinaryFileResponse represents an HTTP response representing a binary file.
*
* @author Jordan Alliot <jordan.alliot@gmail.com>
*/
class BinaryFileResponse extends Response
{
private $file;

/**
* Creates a BinaryFileResponse.
*
* @param SplFileInfo|string $file The file to download
* @param integer $status The response status code
* @param array $headers An array of response headers
* @param boolean $autoValidation Whether ETag and Last-Modified headers
* are automatically set or not
* @param boolean $public Files are public by default
*/
public function __construct($file, $status = 200, $headers = array(), $autoValidation = true, $public = true)
{
parent::__construct('', $status, $headers);

$this->setFile($file);

$this->headers->set('Content-Transfer-Encoding', 'binary');

if (true === $autoValidation) {
$this->setAutoLastModified();
$this->setAutoEtag();
}

if (true === $public) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should simply be if ($public) {

$this->setPublic();
}
}

/**
* Sets the file to download.
*
* Also sets some headers for the download, namely
* Content-Disposition, Content-Length and Content-Type.
*
* @param SplFileInfo|string $file The file to download
*/
public function setFile($file)
{
if (null === $file) {
throw new \InvalidArgumentException('File cannot be null.');
}

$file = new File((string) $file, true);

if (!$file->isReadable()) {
throw new FileException('File must be readable.');
}

$this->file = $file;

$this->makeDisposition();
$this->headers->set('Content-Length', $file->getSize());
$this->headers->set('Content-Type', $file->getMimeType() ?: 'application/octet-stream');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a good idea to make it possible to force a download?

An simple setter like setForceDownload() which always sets the 'application/octet-stream'.
In some cases the mime-type is known but you don't want to file to opent in the browser, namely pdf en Office documents.
Or downloading an HTML document.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to force the download, the proper way is not to force the mime type but to change the content disposition to attachement

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, your correct. I have not used this in a while.

Still, having an function name like this much clearer then makeDisposition.
And considering fabpot's note about overwriting the parents function.

}

/**
* Returns the file.
*
* @return File
*/
public function getFile()
{
return $this->file;
}

/**
* Sets the Content-Disposition header.
*
* @param string $disposition Either "inline" or "attachment" (default)
* @param string $filename Name of the file (by default the original file name)
* May be unicode
* @param string $filenameFallback A string containing only ASCII characters that
* is semantically equivalent to $filename. If the filename is already ASCII,
* it can be omitted, or just copied from $filename
*/
public function makeDisposition($disposition = null, $filename = '', $filenameFallback = '')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong as the method behavior is totally different from the parent. Why not set the content disposition without overriding this method?

{
$this->headers->set('Content-Disposition', $this->headers->makeDisposition(
$disposition ?: ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$filename ?: $this->file->getBasename(),
$filenameFallback ?: rawurlencode($this->file->getBasename())
));
}

/**
* Automatically sets the Last-Modified header according to the file modification date.
*/
public function setAutoLastModified()
{
$this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime()));
}

/**
* Automatically sets the ETag header according to the checksum of the file.
*/
public function setAutoEtag()
{
$this->setEtag(sha1_file($this->file->getPathname()));
}

/**
* Sends the file.
*/
public function sendContent()
{
if (!$this->isSuccessful()) {
parent::sendContent();
return;
}

readfile($this->file->getPathname());
}
}
0