Как закодировать параметр имени файла заголовка Content-Disposition в HTTP? - PullRequest
489 голосов
/ 18 сентября 2008

Веб-приложения, которые хотят, чтобы ресурс загружался , а не напрямую отображался в веб-браузере, выдает заголовок Content-Disposition в ответе HTTP формы:

Content-Disposition: attachment; filename=<em>FILENAME</em>

Параметр filename может использоваться для указания имени файла, в который ресурс загружается браузером. RFC 2183 (Content-Disposition), однако, в разделе 2.3 (Параметр имени файла) говорится, что имя файла может использовать только символы US-ASCII:

Текущие грамматические ограничения [RFC 2045] значения параметров (и, следовательно, Content-Disposition filenames) для US-ASCII. Мы признаем великое желательность разрешения произвольного наборы символов в именах файлов, но это выходит за рамки этого документа определить необходимые механизмы.

Тем не менее, существует эмпирическое доказательство того, что большинство популярных веб-браузеров сегодня, по-видимому, допускают символы не-US-ASCII, но (из-за отсутствия стандарта) не согласны со схемой кодирования и спецификацией набора символов имени файла. Тогда возникает вопрос, каковы различные схемы и кодировки, используемые популярными браузерами, если имя файла «naïvefile» (без кавычек и где третья буква - U + 00EF) необходимо кодировать в заголовок Content-Disposition?

Для целей этого вопроса популярных браузеров , являющихся:

  • Firefox
  • Internet Explorer
  • Safari
  • Google Chrome
  • Opera

Ответы [ 17 ]

5 голосов
/ 25 сентября 2015

Если вы используете серверную часть nodejs, вы можете использовать следующий код, который я нашел здесь

var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''" 
             + encodeRFC5987ValueChars(fileName);

function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987, 
            // so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}
4 голосов
/ 05 апреля 2015

Я получил следующий код в моем скрипте "download.php" (на основе этого блога и этих тестов ).

$il1_filename = utf8_decode($filename);
$to_underscore = "\"\\#*;:|<>/?";
$safe_filename = strtr($il1_filename, $to_underscore, str_repeat("_", strlen($to_underscore)));

header("Content-Disposition: attachment; filename=\"$safe_filename\""
.( $safe_filename === $filename ? "" : "; filename*=UTF-8''".rawurlencode($filename) ));

Используется стандартный способ имени файла = "...", если используются только символы iso-latin1 и "safe"; если нет, то добавляется имя файла * = UTF-8 '' в кодировке URL. Согласно этому конкретному тестовому примеру , он должен работать как с MSIE9, так и на последних FF, Chrome, Safari; в более низкой версии MSIE он должен предлагать имя файла, содержащее версию имени файла ISO8859-1, с подчеркиванием на символах, не входящих в эту кодировку.

Конечная нота: макс. Размер каждого поля заголовка на Apache составляет 8190 байт. UTF-8 может содержать до четырех байтов на символ; после rawurlencode это x3 = 12 байт на один символ. Довольно неэффективно, но теоретически все еще должно быть возможно иметь более 600 «улыбок»% F0% 9F% 98% 81 в имени файла.

3 голосов
/ 20 мая 2016

В PHP это было сделано для меня (при условии, что имя файла в кодировке UTF8):

header('Content-Disposition: attachment;'
    . 'filename="' . addslashes(utf8_decode($filename)) . '";'
    . 'filename*=utf-8\'\'' . rawurlencode($filename));

Проверено на IE8-11, Firefox и Chrome.
Если браузер может интерпретировать имя файла * = utf-8 , он будет использовать версию имени файла в формате UTF8, иначе он будет использовать декодированное имя файла. Если ваше имя файла содержит символы, которые не могут быть представлены в ISO-8859-1, вы можете использовать iconv.

1 голос
/ 13 марта 2019

Просто обновление, так как я пробовал все это сегодня в ответ на проблему клиента

  • За исключением Safari, настроенного для японского языка, все протестированные нашим клиентом браузеры лучше всего работали с filename = text.pdf - где text - это значение клиента, сериализованное ASP.Net/IIS в utf-8 без кодировки URL. По какой-то причине Safari, настроенный на английский язык, будет принимать и правильно сохранять файл с японским именем utf-8, но тот же браузер, настроенный для японского, будет сохранять файл с символами utf-8 без интерпретации. Все остальные протестированные браузеры, кажется, работали лучше / лучше (независимо от языковой конфигурации) с именем файла utf-8, закодированным без кодировки URL.
  • Я не смог найти ни одного браузера, реализующего Rfc5987 / 8187 вообще . Я тестировал последние версии Chrome, Firefox, а также IE 11 и Edge. Я попытался установить заголовок только с именем файла * = utf-8''texturlencoded.pdf, установив его с именем файла = text.pdf; имя файла * = UTF-8''texturlencoded.pdf. Ни одна из функций Rfc5987 / 8187, по-видимому, не обрабатывается корректно ни в одном из вышеперечисленных.
1 голос
/ 23 мая 2016

Classic ASP Solution

Большинство современных браузеров поддерживают передачу Filename как UTF-8 сейчас, но, как и в случае с решением для загрузки файлов, которое я использую на основе FreeASPUpload.Net (сайт больше не существует ссылка указывает на archive.org ) , это не сработает, поскольку синтаксический анализ двоичного файла основан на считывании однобайтовых строк в кодировке ASCII, что прекрасно работало, когда вы передавали данные в кодировке UTF-8 до тех пор, пока получить символы ASCII не поддерживает.

Однако мне удалось найти решение, чтобы заставить код читать и анализировать двоичный файл как UTF-8.

Public Function BytesToString(bytes)    'UTF-8..
  Dim bslen
  Dim i, k , N 
  Dim b , count 
  Dim str

  bslen = LenB(bytes)
  str=""

  i = 0
  Do While i < bslen
    b = AscB(MidB(bytes,i+1,1))

    If (b And &HFC) = &HFC Then
      count = 6
      N = b And &H1
    ElseIf (b And &HF8) = &HF8 Then
      count = 5
      N = b And &H3
    ElseIf (b And &HF0) = &HF0 Then
      count = 4
      N = b And &H7
    ElseIf (b And &HE0) = &HE0 Then
      count = 3
      N = b And &HF
    ElseIf (b And &HC0) = &HC0 Then
      count = 2
      N = b And &H1F
    Else
      count = 1
      str = str & Chr(b)
    End If

    If i + count - 1 > bslen Then
      str = str&"?"
      Exit Do
    End If

    If count>1 then
      For k = 1 To count - 1
        b = AscB(MidB(bytes,i+k+1,1))
        N = N * &H40 + (b And &H3F)
      Next
      str = str & ChrW(N)
    End If
    i = i + count
  Loop

  BytesToString = str
End Function

Кредит идет на Чистую загрузку ASP-файла , благодаря реализации функции BytesToString() из include_aspuploader.asp в моем собственном коде, я смог заставить работать UTF-8 имен файлов.


Полезные ссылки

0 голосов
/ 18 сентября 2008

Я обычно URL-кодирую (с% xx) имена файлов, и это, кажется, работает во всех браузерах. В любом случае, вы можете захотеть сделать несколько тестов.

0 голосов
/ 27 января 2015

У нас была похожая проблема в веб-приложении, и в итоге мы прочитали имя файла из HTML <input type="file"> и установили его в кодированной форме в новом HTML <input type="hidden">. Конечно, нам пришлось удалить путь типа «C: \ fakepath \», который возвращают некоторые браузеры.

Конечно, это не дает прямого ответа на вопрос ОП, но может быть решением для других.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...