Веб-приложения, которые хотят заставить ресурс быть скачано, а не напрямую оказано в веб-браузере, выдают заголовок Content-Disposition в HTTP-ответе в форме:
Content-Disposition: attachment; filename=FILENAME
Параметр filename может использоваться для предложения имени файла, в который браузер загружает ресурс. Однако RFC 2183 (Content-Disposition) указывает в Раздел 2.3 (Параметр имени файла), что имя файла может использовать только символы US-ASCII:
Current [RFC 2045] grammar restricts parameter values (and hence Content-Disposition filenames) to US-ASCII. We recognize the great desirability of allowing arbitrary character sets in filenames, but it is beyond the scope of this document to define the necessary mechanisms.
Тем не менее, есть эмпирические доказательства того, что большинство популярных веб-браузеров сегодня допускают символы, отличные от US-ASCII, но (из-за отсутствия стандарта) расходятся во мнениях относительно схемы кодирования и спецификации набора символов имени файла. Тогда возникает вопрос, какие различные схемы и кодировки используются в популярных браузерах, если имя файла «naïvefile» (без кавычек и третья буква U + 00EF) необходимо закодировать в заголовке Content-Disposition?
Для целей этого вопроса популярные браузеры:
Также см. этот похожий вопрос
Content-Disposition: attachment.





Я обычно URL-кодирую (с% xx) имена файлов, и, похоже, это работает во всех браузерах. В любом случае вы можете захотеть провести несколько тестов.
Я тестировал несколько, и это не работает во всех браузерах, поэтому вопрос. :)
Это обсуждается, включая ссылки на тестирование браузера и обратную совместимость, в предложенном RFC 5987, «Набор символов и языковая кодировка для параметров поля заголовка протокола передачи гипертекста (HTTP)».
RFC 2183 указывает, что такие заголовки должны быть закодированы в соответствии с RFC 2184, который был отменен RFC 2231, охваченным проектом RFC выше.
С быстрым тестом, который реализован Firefox и ужасно сломан в IE: он просто не распознает «filename *» как имя файла и пытается определить имя файла из mime-типа и последней части URL-адреса.
Это было частично исправлено в IE9.
Также обратите внимание, что интернет-черновик (не «черновик RFC») был завершен, а окончательный документ - RFC 5987 (greenbytes.de/tech/webdav/rfc5987.html).
В связи с этим я обнаружил, что Firefox (версии 4-9 включительно) прерывается, если в имени файла есть запятая (,), например Content-Disposition: filename = "foo, bar.pdf". В результате firefox правильно загружает файл, но сохраняет расширение .part (например, foo,bar.pdf-1.part). Тогда, конечно, файл не откроется правильно, потому что приложение не связано с .part. Другие символы ASCII, похоже, работают нормально.
RFC, как хорошо известно, «неправильно реализован» различными браузерами. IE, Chrome, Fx, особенно стандартный браузер Android, очень сильно отличаются в кодировке Unicode / non-ascii.
@DennisCheung У вас есть ссылка на эти несоответствия в работе браузера? (Я хочу предоставить доказательства проблемы).
@MatthewSchinckel например kbyanc.blogspot.hk/2010/07/… и digiblog.de/2011/04/android-and-the-download-file-headers
Для получения дополнительной информации о поведении IE см. blogs.msdn.com/b/ieinternals/archive/2010/06/07/….
@catchdave: Вы забыли «вложение»; часть.
Например, в Node.js с hapi вы можете reply(something).header('Content-Disposition', 'attachment; filename = "' + encodeURI(fileName) + '"')
В общем, это не что иное, как ответ только по ссылке с 74 голосами "за".
Следующий документ, связанный с проект RFC, упомянутый Джим в его ответе, дополнительно рассматривает вопрос и определенно заслуживает прямого упоминания здесь:
Тестовые примеры для заголовка HTTP Content-Disposition и кодирования RFC 2231/2047
Обратите внимание, что можно указать оба способа кодирования параметра имени файла, и что они, похоже, правильно работают со старыми браузерами и новыми браузерами (в данном случае старыми являются MSIE8 и Safari). Отметьте attfnboth в отчете, упомянутом @AtifAziz.
В Content-Disposition нет совместимого способа кодирования имен, отличных от ASCII. Совместимость браузера - беспорядок.
теоретически правильный синтаксис для использования UTF-8 в Content-Disposition очень странный: filename*=UTF-8''foo%c3%a4 (да, это звездочка, и никаких кавычек, кроме пустой одинарной кавычки посередине)
Этот заголовок не совсем стандартный (Спецификация HTTP / 1.1 подтверждает его существование, но не требует, чтобы клиенты его поддерживали).
Есть простая и очень надежная альтернатива: используйте URL-адрес, содержащий желаемое имя файла.
Когда имя после последней косой черты - то, что вам нужно, вам не нужны дополнительные заголовки!
Этот трюк работает:
/real_script.php/fake_filename.doc
И если ваш сервер поддерживает перезапись URL (например, mod_rewrite в Apache), вы можете полностью скрыть часть скрипта.
Символы в URL-адресах должны быть в кодировке UTF-8 побайтно:
/mot%C3%B6rhead # motörhead
Кто-нибудь знает, как это сделать в ASP.NET? Можно ли без особых проблем сделать что-то вроде GetAttachment.aspx? Id = 34 / fake_filename.doc?
Попробуйте GetAttachment.aspx / fake_filename.doc? Id = 34 (хотя это может быть причуда только для Apache)
Вы можете обработать такой путь в IIS, используя либо настраиваемый модуль .Net HttpModule, либо, возможно, параметр UrlRewrite в IIS7.
это фантастическое решение; действительно мне очень помог. Благодарю.
@SeanHanley - также проверьте перезапись URL-адресов для IIS и MVC framework
Я пошел по кроличьей тропе и попробовал другие решения; попытка найти правильный браузер и версию для правильной установки заголовков - это слишком большой кошмар. Chrome неправильно идентифицировал себя как Safari, который ведет себя совсем не так (разрывы на запятые, если кодируется неправильно). Избавьте себя от проблем, используйте это решение и задайте псевдоним URL-адреса по мере необходимости.
Я сделал это в веб-формах ASP.NET 4.0, используя Маршрутизация ASP.NET. Я зарегистрировал маршрут: routes.MapPageRoute("Download", "download/{id}/{filename}", "~/download.aspx"); В download.aspx я использую только id: Page.RouteData.Values ["id"] и не пишу дополнительный заголовок Content-Disposition. Полагаю, работает хорошо и проще, чем HttpModule.
пожалуйста, не кодируйте. на% 2e, ie7 в winxp не сможет отображать правильное имя файла.
Метод /:id/:filename действительно прост и работает, спасибо!
как мне реализовать подход url с laravel Response::download()? если я не определяю имя файла в этом методе, он сам выберет имя файла и не учитывает url
Тысячу раз «Да». С этим вы серьезно выиграете время. Более того, некоторые браузеры Android заменяют игнорироватьContent-Disposition и вместо этого создают очень интересные имена файлов (они будут сгенерированы из вашего пути). Таким образом, единственное решение для сохранения здравомыслия - это просто установить Content-Disposition: attachment и передать желаемое имя файла в качестве последнего компонента пути:
это отличное решение (и заставило меня почувствовать себя немного глупо) в соответствующей заметке, помните, если имя файла исходит из пользовательской переменной, вам все равно нужно убедиться, что оно готово для файловой системы. Если вы этого не сделаете, и в файле есть что-то вроде /, вы получите странные ошибки браузера В самом деле. С этот ответ в качестве ссылки я использовал s.replace(/[\000-\031\\/:*?"<>\|]/g, '_')
Но в этом случае нам нужно заранее знать имя файла, не так ли? Это делает два запроса, один для имени файла, один для самого файла.
@GuneyOzsan На уровне HTTP нет абсолютно никакой разницы, и он никогда не вызывает никаких дополнительных запросов. Вам не нужно знать имя файла, вам нужно включить имя файла в URL-адрес, который вы все равно должны знать.
@Kornel в моем текущем проекте я не знаю заранее имена файлов и запрашиваю файлы по идентификатору и пытаюсь получить файл (как поток) и имя (желательно в заголовке) в одном запросе. С другой стороны, версия C#, которую использует Unity, не поддерживает этот странный синтаксис в Content-Disposition. В конце концов я решил это, закодировав его на php с помощью filename = "' . rawurlencode($file_name_with_extension) . '" и декодировав на C# с помощью headerValue = ContentDispositionHeaderValue.Parse(contentDisposition) и fileName = Uri.UnescapeDataString(headerValue.FileName.Replace("\"", "")).
@Kornel Мне было интересно, как и почему fake_filename.doc интерпретируется, как если бы это имя файла в заголовке.
@GuneyOzsan имя файла для сохранения определяется веб-браузером, и браузеры не понимают, что происходит на стороне сервера, поэтому они не понимают и не заботятся о том, как сервер интерпретирует URL-адрес. Браузеры просто принимают все, что стоит после последней косой черты в пути URL, иногда дополнительно пытаясь исправить расширения имени файла на основе Content-Type.
@Kornel Ops, извините, я устал часами работать над исправлением какой-то ошибки и путал «косую черту» с «подчеркиванием», пытаясь понять черную магию, стоящую за тем, почему браузер удаляет часть fake_. Спасибо за уделенное время.
в asp.net mvc2 я использую что-то вроде этого:
return File(
tempFile
, "application/octet-stream"
, HttpUtility.UrlPathEncode(fileName)
);
Я думаю, если вы не используете mvc (2), вы можете просто закодировать имя файла, используя
HttpUtility.UrlPathEncode(fileName)
Кодировка URL-адреса для кодировки имени файла недействительна, браузеры не должны декодировать URL-адрес.
IE 11 определенно не декодирует кодировку url в этом поле.
Но он должен быть UrlEncoded, когда браузер Chrome или IE, другие, такие как FF, Safari и Opera, отлично работают без кодирования.
Я знаю, что это старый пост, но он все еще очень актуален. Я обнаружил, что современные браузеры поддерживают rfc5987, который позволяет кодировать utf-8 с процентной кодировкой (с кодировкой url). Тогда Naïve file.txt станет:
Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt
Safari (5) не поддерживает это. Вместо этого вы должны использовать стандарт Safari для записи имени файла непосредственно в заголовок в кодировке utf-8:
Content-Disposition: attachment; filename=Naïve file.txt
IE8 и более ранние версии также не поддерживают его, и вам нужно использовать стандарт IE для кодировки utf-8 с процентной кодировкой:
Content-Disposition: attachment; filename=Na%C3%AFve%20file.txt
В ASP.Net я использую следующий код:
string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
contentDisposition = "attachment; filename = " + Uri.EscapeDataString(fileName);
else if (Request.Browser.Browser == "Safari")
contentDisposition = "attachment; filename = " + fileName;
else
contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);
Я тестировал вышеуказанное, используя IE7, IE8, IE9, Chrome 13, Opera 11, FF5, Safari 5.
Обновлять ноябрь 2013 г .:
Вот код, который я использую сейчас. Мне все еще нужно поддерживать IE8, поэтому я не могу избавиться от первой части. Оказывается, браузеры на Android используют встроенный диспетчер загрузок Android, и он не может надежно анализировать имена файлов стандартным способом.
string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
contentDisposition = "attachment; filename = " + Uri.EscapeDataString(fileName);
else if (Request.UserAgent != null && Request.UserAgent.ToLowerInvariant().Contains("android")) // android built-in download manager (all browsers on android)
contentDisposition = "attachment; filename=\"" + MakeAndroidSafeFileName(fileName) + "\"";
else
contentDisposition = "attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);
Вышеупомянутое теперь протестировано в IE7-11, Chrome 32, Opera 12, FF25, Safari 6 с использованием этого файла для загрузки: 你好 abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§! # ¤% & () = `@ £ $ € {[]} + ´¨ ^ ~ '-_,;. txt
В IE7 это работает для некоторых символов, но не для всех. Но кого сейчас волнует IE7?
Это функция, которую я использую для создания безопасных имен файлов для Android. Обратите внимание, что я не знаю, какие символы поддерживаются на Android, но я проверил, что они работают точно:
private static readonly Dictionary<char, char> AndroidAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+,@£$€!½§~'=()[]{}0123456789".ToDictionary(c => c);
private string MakeAndroidSafeFileName(string fileName)
{
char[] newFileName = fileName.ToCharArray();
for (int i = 0; i < newFileName.Length; i++)
{
if (!AndroidAllowedChars.ContainsKey(newFileName[i]))
newFileName[i] = '_';
}
return new string(newFileName);
}
@TomZ: Я тестировал IE7 и IE8, и оказалось, что мне не нужно избегать апострофа ('). У вас есть пример, когда это не удается?
@Dave Van den Eynde: объединение двух имен файлов в одной строке, как в соответствии с RFC6266, работает за исключением Android и IE7 + 8, и я обновил код, чтобы отразить это. Спасибо за предложение.
@Thilo: Не знаю ни о GoodReader, ни о каком-либо другом небраузере. Возможно, вам повезет с использованием подхода Android.
@ Алексей Жуковский: Я не знаю почему, но, как обсуждалось на Соединять, похоже, что это работает не очень хорошо.
Я протестировал приведенный выше код с помощью FF 8.0.1 в Windows 7. Выбран RFC5987, и имя файла (Naïve file.txt) отображается правильно.
Он работает для Mobile Safari (необработанный utf-8, как предложено выше), но не работает для GoodReader с того же устройства. Есть идеи?
IE7 и 8 также нуждаются в экранировании апострофов: .Replace ("'", Uri.HexEscape (' \ ''))
Прямая запись символов UTF-8, похоже, работает для текущих версий Firefox, Chrome и Opera. Не тестировал Safari и IE.
Мой Chrome '26 .0,1410,64 м 'не распознает формат rfc5987. Ест старую т.е. процентную кодировку.
Почему бы не объединить их, как Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt; filename=Na%C3%AFve%20file.txt, и пропустить поиск в браузере? Это сработает?
Еще одно дополнение: в IE9 %20 в аргументе filename* приводит не к пробелу, а к буквальному %20 в имени файла.
@Rutix В моем случае полное удаление части имени файла сработало, потому что путь URL-адреса уже включал имя файла. Затем все протестированные браузеры использовали это имя в качестве имени файла (которое работало с пробелами).
Проверено на IE11 Mobile на "Windows Phone 8.1 Update" не работает :-(
@DaveVandenEynde Это не работает в современных браузерах на основе Chromium. Вместо этого браузер показывает предупреждение о проблемах с безопасностью (хотя я не уверен, какие проблемы с безопасностью могут быть вызваны указанием нескольких имен файлов).
@Georg С тех пор я научился полагаться на класс ContentDispositionHeaderValue Web.Api, чтобы справиться с этим за меня.
Некоторое повторное тестирование этого (с использованием inline;filename=) предполагает, что использование имен файлов, содержащих пробелы, должно иметь символы двойных кавычек ("), чтобы Firefox 42 использовал что-либо, кроме имени файла перед первым пробелом. Использование имен файлов в кодировке URL не работает; имя файла в диалоговом окне «Сохранить как» становится my%20file.txt. То же самое с Safari 9: необходимо использовать кавычки, а% -кодирование - беспорядок. Google Chrome 46, похоже, полностью игнорирует заголовок или, возможно, ему не нравится что-то конкретное в форматировании.
Я должен был упомянуть, что кодирование URL не работает специально с filename. Другое дело - использование filename*. Также обратите внимание, что вы не можете использовать + для пробела в имени файла при использовании filename*: вы должны использовать %20.
Например, в Node.js с hapi вы можете reply(something).header('Content-Disposition', 'attachment; filename = "' + encodeURI(fileName) + '"')
Добрые люди из fastmail нашли другой обходной путь: blog.fastmail.com/2011/06/24/download-non-english-filenames Content-Disposition: attachment; filename = "foo-% c3% a4.html"; filename * = UTF-8''foo-% c3% a4.html Если указать имя файла дважды (один раз без префикса UTF-8 и один раз с), он будет работать в IE8-11, Edge, Chrome, Firefox и Safari ( похоже на исправленное сафари Apple, так что теперь оно работает и там)
@ MartinØrding-Thomsen Знаете ли вы, почему стандарт System.Net.Mime.ContentDisposition генерирует недопустимое имя, которое не может быть интерпретировано никаким браузером (даже Chrome не может)?
@DaveVandenEynde Необходимо отличать Content-Disposition в заголовках запроса от заголовков в теле multipart/form-data. В последнем случае использование filename* явно запрещено для Content-Disposition, см. tools.ietf.org/html/rfc7578#section-4.2.
Я протестировал следующий код во всех основных браузерах, включая старые проводники (в режиме совместимости), и он везде хорошо работает:
$filename = $_GET['file']; //this string from $_GET is already decoded
if (strstr($_SERVER['HTTP_USER_AGENT'],"MSIE"))
$filename = rawurlencode($filename);
header('Content-Disposition: attachment; filename = "'.$filename.'"');
Я использую следующие фрагменты кода для кодирования (предполагая, что имя файла содержит имя файла и расширение файла, например: test.txt):
PHP:
if ( strpos ( $_SERVER [ 'HTTP_USER_AGENT' ], "MSIE" ) > 0 )
{
header ( 'Content-Disposition: attachment; filename = "' . rawurlencode ( $fileName ) . '"' );
}
else
{
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode ( $fileName ) );
}
Ява:
fileName = request.getHeader ( "user-agent" ).contains ( "MSIE" ) ? URLEncoder.encode ( fileName, "utf-8") : MimeUtility.encodeWord ( fileName );
response.setHeader ( "Content-disposition", "attachment; filename=\"" + fileName + "\"");
Правильно, это должно быть rawurlencode в PHP, по крайней мере, для заголовка расположения filename*=, поскольку value-chars, используемый в ext-value RFC 6266-> RFC 5987 (см. tools.ietf.org/html/rfc6266#section-4.1 и tools.ietf.org/html/rfc5987#section-3.2.1), не допускает пространства без процентного экранирования (filename=, с другой стороны, кажется что он может позволить пробел вообще без экранирования, хотя здесь должен присутствовать только ASCII). Нет необходимости кодировать с полной строгостью rawurlencode, поэтому некоторые символы могут быть неэкранированными: gist.github.com/brettz9/8752120
RFC 6266 описывает «Использование поля заголовка Content-Disposition в протоколе передачи гипертекста (HTTP)». Цитата из этого:
6. Internationalization Considerations
The “
filename*” parameter (Section 4.3), using the encoding defined in [RFC5987], allows the server to transmit characters outside the ISO-8859-1 character set, and also to optionally specify the language in use.
И в их раздел примеров:
This example is the same as the one above, but adding the "filename" parameter for compatibility with user agents not implementing RFC 5987:
Content-Disposition: attachment; filename = "EURO rates"; filename*=utf-8''%e2%82%ac%20ratesNote: Those user agents that do not support the RFC 5987 encoding ignore “
filename*” when it occurs after “filename”.
В Приложение D. также есть длинный список предложений по увеличению интероперабельности. Он также указывает на сайт, который сравнивает реализации. Текущие универсальные тесты, подходящие для общих имен файлов, включают:
filename».Этот RFC 5987, в свою очередь, ссылается на RFC 2231, который описывает фактический формат. 2231 в первую очередь предназначен для почты, а 5987 сообщает нам, какие части также могут использоваться для заголовков HTTP. Не путайте это с заголовками MIME, используемыми внутри multipart/form-data HTTP тело, который регулируется RFC 2388 (в частности, Раздел 4.4) и HTML 5 черновик.
У меня были проблемы с Safari. При загрузке файлов с русскими именами получаются ошибочные и нечитаемые символы. Решение помогло. Но нам нужно отправить заголовок в одну строку (!!!).
У нас была аналогичная проблема в веб-приложении, и в итоге мы прочитали имя файла из HTML <input type = "file"> и установили его в форме с кодировкой URL в новом HTML <input type = "hidden">. Конечно, нам пришлось удалить путь типа «C: \ fakepath \», который возвращают некоторые браузеры.
Конечно, это не дает прямого ответа на вопрос ОП, но может быть решением для других.
Совершенно другой вопрос. Речь идет о скачивание, ваш ответ - о загрузка.
Я получил следующий код в моем скрипте "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) ));
Используется стандартный способ filename = "..." до тех пор, пока используются только iso-latin1 и "безопасные" символы; в противном случае он добавляет имя файла * = UTF-8 '' в URL-кодировке. Согласно этот конкретный тестовый пример, он должен работать с MSIE9 и выше, а также с последними версиями FF, Chrome, Safari; в более ранней версии MSIE он должен предлагать имя файла, содержащее версию имени файла ISO8859-1, с подчеркиванием на символах не в этой кодировке.
Заключительное примечание: макс. размер каждого поля заголовка составляет 8190 байт на apache. UTF-8 может содержать до четырех байтов на символ; после rawurlencode это x3 = 12 байт на один символ. Довольно неэффективно, но теоретически возможно иметь более 600 «улыбок»% F0% 9F% 98% 81 в имени файла.
... но максимальная длина передаваемого имени файла также зависит от клиента. Только что выяснил, что самое большее [89 смайлов?] .pdf имя файла проходит через MSIE11. В Firefox37 это не более [111x ?] .pdf. Chrome41 обрезает имя файла на 110-м смайле. Что интересно, суффикс передается нормально.
В веб-API ASP.NET я кодирую URL-адрес имени файла:
public static class HttpRequestMessageExtensions
{
public static HttpResponseMessage CreateFileResponse(this HttpRequestMessage request, byte[] data, string filename, string mediaType)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(data);
stream.Position = 0;
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType =
new MediaTypeHeaderValue(mediaType);
// URL-Encode filename
// Fixes behavior in IE, that filenames with non US-ASCII characters
// stay correct (not "_utf-8_.......=_ = ").
var encodedFilename = HttpUtility.UrlEncode(filename, Encoding.UTF8);
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment") { FileName = encodedFilename };
return response;
}
}


Поместите имя файла в двойные кавычки. Решил проблему за меня. Так:
Content-Disposition: attachment; filename = "My Report.doc"
http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download
Я проверил несколько вариантов. Браузеры не поддерживают спецификации и действуют иначе, я считаю, что двойные кавычки - лучший вариант.
К сожалению, это не решает всех проблем, описанных в ответах выше.
Это позволит вам вернуть имя файла с пробелами, &, %, # и т. д. Так что это решает.
Что, если имя файла содержит двойные кавычки (да, это может случиться). Как указано в RFC 6266, имя файла является «строкой в кавычках», и, как указано в RFC 2616, двойные кавычки внутри строки в кавычках должны быть экранированы обратной косой чертой.
Если вы используете серверную часть 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);
}
Лучше использовать encodeURI(str). Например, с датами в имени файла: encodeURIComponent('"Kornél Kovács 1/1/2016') => "Kornél Kovács 1% 2F1% 2F2016" vs. encodeURI('"Kornél Kovács 1/1/2016') => "Kornél Kovács 1/1/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.
Хотя этот код может ответить на вопрос, предоставляя дополнительный контекст относительно Почему и / или как, он отвечает, что вопрос значительно улучшит его долгосрочное значение. Пожалуйста, редактировать свой ответ, чтобы добавить некоторые пояснения.
Ого, ни один из приведенных выше ответов, содержащих только код, не получил голосов или критики. Также я обнаружил, что Почему уже получил достаточно хороший ответ: IE не интерпретирует имя файла * = utf-8, но ему нужна версия имени файла ISO8859-1, которую предлагает этот сценарий. Только хотел дать ленивым работающий простой код для PHP.
Я думаю, что это было отклонено, потому что вопрос не зависит от языка, а о том, какие RFC следует придерживаться при реализации кодировки заголовка. Однако спасибо за этот ответ, для PHP, этот код избавил меня от проблем.
Спасибо. Возможно, этот ответ не отвечал строго на вопрос, но это было именно то, что я искал, и помог мне решить проблему в Python.
Я почти уверен, что этот код можно использовать в качестве вектора атаки, если пользователь может контролировать имя файла.
Большинство современных браузеров теперь поддерживают передачу 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.
Просто обновление, так как я пробовал все это сегодня в ответ на проблему клиента
Это хорошее обновление. Не могли бы вы подробнее рассказать о конкретных тестах, которые вы пробовали?
PHP-фреймворк Symfony 4 имеет $filenameFallback в HeaderUtils::makeDisposition.
Вы можете изучить эту функцию для получения подробной информации - она похожа на ответы выше.
Пример использования:
$filenameFallback = preg_replace('#^.*\.#', md5($filename) . '.', $filename);
$disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename, $filenameFallback);
$response->headers->set('Content-Disposition', $disposition);
Он работает для Mobile Safari (необработанный utf-8, как было предложено @Martin Ørding-Thomsen), но это не работает для GoodReader с того же устройства. Есть идеи?