Любой способ заставить браузер Android по умолчанию распознавать имена файлов, отличные от ASCII, в Content-Disposition: загрузки вложений?

Прежде всего, я почти уверен, что это не дубликат, потому что я изучал эту тему в течение достаточно долгого времени, как в StackOverflow, так и в других местах. Подобные вопросы задавались, но ни на один из них не был получен удовлетворительный ответ.

Связанные (но не идентичные) вопросы из прошлого:

Я также полностью осведомлен о mod_rewrite трюках, которые делают его совершенно ненужным для жонглирования именами файлов в заголовках HTTP. Но допустим, что это не вариант.


Большинство современных браузеров (IE9+, Firefox, Chrome) поддерживают RFC2231/5987 при загрузке файлов с кодом, отличным от ASCII. символов в своих именах. В этих случаях следующий PHP-код работает как шарм:

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

IE ‹= 8 не понимает RFC2231/5987, но в большинстве случаев работает следующий код. Поскольку каждый браузер пытался в какой-то степени эмулировать IE, это работает и во многих других браузерах, таких как Firefox.

header("Content-Disposition: attachment; " .
       'filename="' . rawurlencode($filename) . '"');

Между тем, Chrome ‹ 11 и Safari ‹ 6, похоже, предпочитают следующее, несмотря на то, что они размещают не-ASCII-символы непосредственно в заголовке.

header("Content-Disposition: attachment; filename=" . $filename);

Все идет нормально.


Но все рушится, когда дело доходит до браузерного приложения Android по умолчанию. (До сих пор я тестировал это в Gingerbread, Ice Cream Sandwich и Jelly Bean.)

Если вы дадите ему стандартную обработку RFC2231/5987, браузер по умолчанию полностью проигнорирует его и попытается угадать имя файла из последней части URL-адреса.

Если вы дадите ему обычную нестандартную (IE ‹ = 8) обработку, либо браузер по умолчанию попытается интерпретировать имя файла как ISO-8859-1, что приведет к неразборчивой мешанине символов, либо он молча отбрасывает все символы, отличные от ASCII. . Точное поведение различается между версиями, но в любом случае ясно, что браузер Android по умолчанию также не предназначен для поддержки формата rawurlencode().

То же самое произойдет, если вы поместите необработанное имя файла в заголовок.

Обычно это не проблема со сторонними браузерами, такими как Firefox для Android, Dolphin Browser и Boat Browser. Браузерное приложение по умолчанию — единственное, которое постоянно не понимает имена файлов UTF-8.


Возможно, это было окончательно исправлено в последней версии Android, или, возможно, это будет исправлено в следующей версии. Но это не мой вопрос. Мне нужно, чтобы это работало на существующих устройствах, а есть еще миллионы устройств Gingerbread и ICS.

Я прочитал отчеты об ошибках, я прочитал жалобы, я прочитал почти все, что можно прочитать об этой проблеме. До сих пор мне не удалось найти какую-либо схему кодирования, которая действительно работает.

Если кто-нибудь знает, как закодировать имя файла, отличное от ASCII** (например, файла파일ファイル名.jpg) в Content-Disposition **заголовке, чтобы браузер Android по умолчанию распознал его, поделитесь им! Мне все равно, насколько он хакерский или нестандартный. Меня не волнует, нужно ли его настраивать для каждой версии Android.

Обновлять

К сожалению, до сих пор я не получил никакого ответа, который действительно решает проблему, упомянутую выше. Таким образом, награда истекает невостребованной. Пожалуйста, не отвечайте, если вы действительно не знаете, как кодировать неевропейские имена файлов на разных языках таким образом, чтобы они распознавались браузером Android до ICS, или если у вас есть веские доказательства того, что это невозможно.


person kijin    schedule 01.04.2014    source источник
comment
можете ли вы сказать мне, хотите ли вы, чтобы это работало только с вашим приложением или чтобы пользователь использовал его регулярно? В версиях до 4.0.1 расположение содержимого отбрасывается.   -  person Diogo Bento    schedule 05.04.2014
comment
Поскольку Android является открытым исходным кодом, возможно, вы сможете заглянуть в исходный код Android и выяснить, как именно обрабатываются имена файлов. Затем вы также можете узнать, как обойти это.   -  person Gerben    schedule 05.04.2014
comment
@DiogoBento Это не для приложения, это для веб-сайта. Поэтому он должен быть совместим с широким спектром настольных и мобильных браузеров. Приложение браузера по умолчанию не совсем отбрасывает Content-Disposition, оно ведет себя странно только тогда, когда в имени файла есть символы, отличные от ASCII.   -  person kijin    schedule 06.04.2014


Ответы (3)


URLUtil.java отвечает за guessFileName который вызывает parseContentDisposition, который использует это регулярное выражение "attachment;\\s*filename\\s*=\\s*(\"?)([^\"]*)\\1\\s*$".

чтобы получить имя файла на основе заголовка Content-Disposition.

Приведенный ниже исходный код, который пытается воспроизвести функциональность parseContentDisposition, работает правильно, когда я его тестировал. Например, он возвращает файл 파일ファイル名.jpg.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HelloWorld{

     public static void main(String []args){
     String contentDisposition = "Content-Disposition: attachment; " + " filename=" +"\"файла파일ファイル名.jpg\"";     
     Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile("attachment;\\s*filename\\s*=\\s*(\"?)([^\"]*)\\1\\s*$",Pattern.CASE_INSENSITIVE);
        try {
            Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
            if (m.find()) {
                System.out.println("Result: " + m.group(2));
            }
        } catch (IllegalStateException ex) {
             // This function is defined as returning null when it can't parse the header
        }

     }
}
person Appleman1234    schedule 06.04.2014
comment
Этот код означает, что старый метод кодирования Chrome и Safari (третий пример в вопросе) должен работать. К сожалению, реальный браузер Android ведет себя иначе: либо полностью игнорирует имя файла (Gingerbread), либо отбрасывает все символы, отличные от ASCII (Jelly Bean). - person kijin; 06.04.2014

К сожалению, я не могу проверить это прямо сейчас, но я использую следующий код для отправки файла в браузеры, и до сих пор у меня не было никаких проблем (даже с браузерами Android), надеюсь, он вам поможет:

    $formatRFC2231 = 'filename*=UTF-8\'\'%s';
    $formatDef = 'filename="%s"';

    switch ($useragent) {
        case "Opera":
        case "Firefox":
            $filename = rawurlencode($name);
            $format = $formatRFC2231;
            break;
        case "IE":
        case "Safari":
        case "Chrome":
            $filename = rawurlencode($name);
            $format = $formatDef;
            break;
        default:
            $filename = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $name);
            $format = $formatDef;
            break;
    }

Ключевым моментом здесь является функция iconv, которая преобразует любой символ, отличный от utf8, в символ ISO-8859-1.

person Antonio E.    schedule 06.04.2014
comment
//TRANSLIT может работать с акцентированными латинскими символами, такими как ãèù, но я не думаю, что возможно транслитерировать 中文, 한글 или にほんご в ISO-8859-1. (Я пытался и получил только кучу вопросительных знаков. Угадайте, вопросительные знаки недействительны в именах файлов.) - person kijin; 06.04.2014
comment
Как насчет того, чтобы попытаться найти правильный iso-* (думаю, около cp25x, но я не могу сейчас вспомнить) с помощью функции iconv и преобразовать имя файла с этим? - person Antonio E.; 11.04.2014
comment
Вы прочитали мой вопрос? Я дал ссылку на эту ветку вверху моего вопроса. Я знаю соответствующие RFC, я просто ищу обходной путь для конкретного пользовательского агента, который не соблюдает RFC. Как я уже упоминал в вопросе, я также знаю, как использовать mod_rewrite, чтобы поместить имя файла в сам URL-адрес, но я ищу решение, которое не требует перезаписи URL-адреса. Спасибо за попытку помочь, но если вы действительно хотите помочь, пожалуйста, внимательно прочитайте вопрос и скажите мне что-то, чего я еще не знаю. - person kijin; 11.04.2014
comment
Есть CP932 для японского языка, CP949 для корейского, CP936 и CP950 для китайского и CP874 для тайского, но UTF-* — единственные кодировки, которые могут кодировать имена файлов на разных языках (которые на удивление распространены в некоторых частях Азии), даже с / /ТРАНСЛИТ. Например, очень немногие корейские иероглифы даже отдаленно похожи на японские иероглифы. - person kijin; 11.04.2014

Я полагаю, что вы столкнулись с ошибкой в ​​диспетчере загрузок Android, как описано здесь:

https://code.google.com/p/chromium/issues/detail?id=162333

person Julian Reschke    schedule 30.06.2014