Fixes #10563: Fixed forming Content-Disposition header for file downloads (#12721)

This commit is contained in:
Alexander Makarov
2016-10-12 11:41:21 +03:00
committed by GitHub
parent 677b55475b
commit 4b43183df7
2 changed files with 40 additions and 2 deletions

View File

@ -10,6 +10,7 @@ Yii Framework 2 Change Log
- Bug #9277: Fixed `yii\console\controllers\AssetController` looses custom options of 'target' bundles (petrabarus, klimov-paul)
- Bug #9561: Fixed `canGetProperty()` and `canSetProperty()` returns `false` for `yii\db\BaseActiveRecord` attributes (klimov-paul)
- Bug #10567: Fixed `yii\console\controllers\AssetController` looses bundle override configuration, which makes it external one (klimov-paul)
- Bug #10563: Fixed forming `Content-Disposition` header for file downloads (samdark)
- Bug #10681: Reverted fix of beforeValidate event calling in `yii.activeForm.js` (silverfire)
- Bug #11347: Fixed `yii\widgets\Pjax::registerClientScript()` to pass custom `container` to the PJAX JS plugin (silverfire)
- Bug #11352: Fixed `updateInputs()` method in `yii.activeForm.js` to prevent reading property of undefined (silverfire)

View File

@ -10,6 +10,7 @@ namespace yii\web;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\helpers\Inflector;
use yii\helpers\Url;
use yii\helpers\FileHelper;
use yii\helpers\StringHelper;
@ -584,7 +585,7 @@ class Response extends \yii\base\Response
->setDefault('Accept-Ranges', 'bytes')
->setDefault('Expires', '0')
->setDefault('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->setDefault('Content-Disposition', "$disposition; filename=\"$attachmentName\"");
->setDefault('Content-Disposition', $this->getDispositionHeaderValue($disposition, $attachmentName));
if ($mimeType !== null) {
$headers->setDefault('Content-Type', $mimeType);
@ -708,13 +709,49 @@ class Response extends \yii\base\Response
$this->getHeaders()
->setDefault($xHeader, $filePath)
->setDefault('Content-Type', $mimeType)
->setDefault('Content-Disposition', "{$disposition}; filename=\"{$attachmentName}\"");
->setDefault('Content-Disposition', $this->getDispositionHeaderValue($disposition, $attachmentName));
$this->format = self::FORMAT_RAW;
return $this;
}
/**
* Returns Content-Disposition header value that is safe to use with both old and new browsers
*
* Fallback name:
*
* - Causes issues if contains non-ASCII characters with codes less than 32 or more than 126.
* - Causes issues if contains urlencoded characters (starting with %) or % character. Some browsers interpret
* filename="X" as urlencoded name, some aren't.
* - Causes issues if contains path separator characters such as \ or /.
* - Since value is wrapped with ", it should be escaped as \".
* - Since input could contain non-ASCII characters, fallback is obtained by transliteration.
*
* UTF name:
*
* - Causes issues if contains path separator characters such as \ or /.
* - Should be urlencoded since headers are ASCII-only.
* - Could be omitted if it exactly matches fallback name.
*
* @param string $disposition
* @param string $attachmentName
* @return string
*
* @since 2.0.10
*/
protected function getDispositionHeaderValue($disposition, $attachmentName)
{
$fallbackName = str_replace('"', '\\"', str_replace(['%', '/', '\\'], '_', Inflector::transliterate($attachmentName, Inflector::TRANSLITERATE_LOOSE)));
$utfName = rawurlencode(str_replace(['%', '/', '\\'], '', $attachmentName));
$dispositionHeader = "{$disposition}; filename=\"{$fallbackName}\"";
if ($utfName !== $fallbackName) {
$dispositionHeader .= "; filename*=utf-8''{$utfName}";
}
return $dispositionHeader;
}
/**
* Redirects the browser to the specified URL.
*