問題はどんな言語で書いても起こることですが、たまたま仕事でPHPつかってたときにぶつかったのでメモしておきます。
結論
HTTPのレスポンスヘッダで Content-Disposition: attachment; filename*=UTF-8''URLエンコードされたファイル名
を送ってあげる。
追記
2017/11/02: Edgeでも通用するようです。https://github.com/netcommons/NetCommons2/issues/126
ファイル名が化ける
PHPでファイルアップローダをつくっていました。
動作確認はUbuntu 14.04のFirefox30をつかっていましたが、社内ではIE11がデフォ。「一応やっとくか」とIE11で動かしたら、日本語のファイル名が見事に化けました。
またお前か、IE!チキショー
Slim Frameworkをつかっているので、こんなコードになっています。
$app->response->setStatus(200);
$app->response->headers->set('Content-Type', $type);
$app->response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
$app->response->headers->set('Content-Length', $size);
$app->response->setBody(file_get_contents($filepath));
UTF-8からShift-JISに変換してやった
ならば、ということで、
$app->response->headers->set('Content-Disposition', 'attachment; filename='.mb_convert_encoding($filename, 'SJIS-win', 'UTF-8');
などとしてやったわけですが、今度はLinuxで化けてしまって、会社のみんなはいいけど自分たちはすごく不便、という状況に。
ちくしょうめ。
IEを使っているかどうか判断?
ググってみると、UserAgentの文字列をみてSJISかUTF-8か判断している記事が多く見つかったのですが、IE11になったときにUserAgentからMSIEの表記が消えてTridentになりましたよね。またそういうのがないとも限らないので、できるだけ避けたいものであります。
最終的に...
Content-Disposition
をattachment; filename*=UTF-8''URLエンコードされたファイル名
などとすれば良いことが判明。仕様はRFC6266だそうです。
RFC6266のこの書式をサポートしているのはIE9以上、(少なくとも)Firefox22以上、Safari6以上(Safari5はダメらしい)ということが、http://greenbytes.de/tech/tc2231/ からよめました。
最終的にはこんなコードになりました。一応動いています。
$app->response->setStatus(200);
$app->response->headers->set('Content-Type', $type);
$app->response->headers->set('Content-Disposition', 'attachment; filename*=UTF-8\'\''.rawurlencode($filename);
$app->response->headers->set('Content-Length', $size);
$app->response->setBody(file_get_contents($filepath));
参考
http://support.microsoft.com/kb/436616/ja
http://tools.ietf.org/html/rfc6266