diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index 22f84da4a4..490726dadf 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -160,6 +160,20 @@ class BinaryFileResponse extends Response $filename = $this->file->getFilename(); } + if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || false !== strpos($filename, '%'))) { + $encoding = mb_detect_encoding($filename, null, true); + + for ($i = 0; $i < mb_strlen($filename, $encoding); ++$i) { + $char = mb_substr($filename, $i, 1, $encoding); + + if ('%' === $char || ord($char) < 32 || ord($char) > 126) { + $filenameFallback .= '_'; + } else { + $filenameFallback .= $char; + } + } + } + $dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback); $this->headers->set('Content-Disposition', $dispositionHeader); diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index 88fb251366..ac6c3288ae 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -34,6 +34,11 @@ class BinaryFileResponseTest extends ResponseTestCase $this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition')); } + public function testConstructWithNonAsciiFilename() + { + new BinaryFileResponse(__DIR__.'/Fixtures/föö.html', 200, array(), true, 'attachment'); + } + /** * @expectedException \LogicException */ @@ -49,6 +54,14 @@ class BinaryFileResponseTest extends ResponseTestCase $this->assertFalse($response->getContent()); } + public function testSetContentDispositionGeneratesSafeFallbackFilename() + { + $response = new BinaryFileResponse(__FILE__); + $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'föö.html'); + + $this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition')); + } + /** * @dataProvider provideRanges */ diff --git a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/föö.html b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/föö.html new file mode 100644 index 0000000000..e69de29bb2