К сожалению, в настоящее время нет ни одного решения, которое работало бы со всеми браузерами.
Существует как минимум три «более очевидных» подхода к проблеме.
а) Content-type: application/octet-stream; charset=utf-8
+ filename=<utf8 byte sequence>
например filename=Москва.txt
Это нарушение стандартов, но Firefox показывает имя правильно. IE нет.
б) Content-type: application/octet-stream; charset=utf-8
+ filename=<urlencode(utf8 byte sequence)>
например filename=%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0.txt
Это работает с IE, но не с Firefox.
c) предоставление имени, указанного в rfc 2231
например, filename*=UTF-8''%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0.txt
Опять же Firefox поддерживает это, IE нет.
для более полного сравнения см. http://greenbytes.de/tech/tc2231/
edit: Когда я сказал, что нет единого решения, я имел в виду заголовок ('...'). Но есть что-то вроде обходного пути.
Когда нет пригодного для использования заголовка filename = xyz, браузеры используют базовое имя части пути URL. То есть для <a href="test.php/lala.txt">
и firefox, и IE предлагают lalala.txt
в качестве имени файла.
Вы можете добавлять дополнительные компоненты пути после фактического пути к вашему php-скрипту (при использовании http для Apache см. http://httpd.apache.org/docs/2.1/mod/core.html#acceptpathinfo).
Например. если у вас есть файл test.php в корне документа и вы запрашиваете его как http://localhost/test.php/x/y/z
, переменная $_SERVER['PATH_INFO']
будет содержать /x/y/z
.
Теперь, если вы поставите ссылку, как
<a
href="/test.php/download/moskwa/Москва"
>
Москва
</a>
в вашем документе вы можете получить часть download/moskwa/...
и начать загрузку файла. Без отправки какого-либо имени файла = ... и Firefox, и IE предлагают "правильное" имя.
Вы даже можете комбинировать это с отправкой имени согласно rfc 2231. Вот почему я также поместил moskwa
в ссылку. Это будет идентификатор, который скрипт использует для поиска файла, который он должен отправить. IE игнорирует информацию filename*=...
и все еще использует часть базового имени URL, чтобы предложить имя. Это означает, что для firefox (и любого другого клиента, который поддерживает rfc 2231) часть после идентификатора не имеет смысла *, но для IE (и других клиентов, не поддерживающих rfc 2231) она будет использоваться для предложения имени.
автономный пример:
<?php // test.php
$files = array(
'moskwa'=>array(
'htmlentities'=>'Москва',
'content'=>'55° 45′ N, 37° 37′ O'
),
'athen'=>array(
'htmlentities'=>'Αθήνα',
'content'=>'37° 59′ N, 23° 44′ O'
)
);
$fileid = null;
if ( isset($_SERVER['PATH_INFO']) && preg_match('!^/download/([^/]+)!', $_SERVER['PATH_INFO'], $m) ) {
$fileid = $m[1];
}
if ( is_null($fileid) ) {
foreach($files as $fileid=>$bar) {
printf(
'<a href="./test.php/download/%s/%s.txt">%s</a><br />',
$fileid, $bar['htmlentities'], $bar['htmlentities']
);
}
}
else if ( !isset($files[$fileid]) ) {
echo 'no such file';
}
else {
$f = $files[$fileid];
$utf8name = mb_convert_encoding($f['htmlentities'], 'utf-8', 'HTML-ENTITIES');
$utf8name = urlencode($utf8name);
header("Content-type: text/plain");
header("Content-Disposition: attachment; filename*=UTF-8''$utf8name.txt");
header("Content-length: " . strlen($f['content']));
echo $f['content'];
}
*) Это немного похоже на переполнение стека. Ссылка на этот вопрос показана как
/2113364/pri-zagruzke-imen-failov-s-neangliiskih-yazykov-v-zagruzhennom-faile-nepravilno-otobrazhaytsya
но это также работает с
/2113364/pri-zagruzke-imen-failov-s-neangliiskih-yazykov-v-zagruzhennom-faile-nepravilno-otobrazhaytsya
важной частью является идентификатор 2578349