日本語名のファイルを直接アップロード・ダウンロードさせる時の諸問題


実務系のWebシステムを作っていると、ファイルを日本語のファイル名のままアップロードを受け付けたり、ダウンロードして保存した時に分かりやすいように日本語ファイル名でダウンロードさせたいという希望がよくある。

お気持ちはよく分かるのですが〜、これは実は結構大変な場合があるので、その辺りの事情を解説します。プログラミング言語は私は Perl を使っています。

日本語名ファイルのアップロード・ダウンロードの際に考慮すべき問題

日本語名ファイルをアップロード・そのファイル名のまま保存・ダウンロードさせる時に、開発者が考慮しておかなければならない点があります。せっかちな人と早く終わらせて帰りたい人は、末尾のまとめだけをご覧下さい。




アップロード時のファイル名

アップロード時のファイル名は、ブラウザが送信してきます。通常はファイルをアップロードさせるページ(=送信フォーム)と同じ文字コードでファイル名も送ってきます。ブラウザによってローカルパスを付けてきたり、特殊文字をエスケープしてきたりするので若干の変換が必要です。詳しくはこちら

保存時ファイル名の文字コード

アップロードを受け付けるサーバがMacを除くUNIX系システム(CentOS、Linux、AWS、FreeBSDなど)の場合は、送信されてきたファイル名のままファイルの保存が可能です。Shift_JIS でも UTF-8 でも EUC-JP でも保存できます。OSがデフォルトで採用している文字コードとは関係なく、好きな文字コードで保存できます。このため、送信されてきたファイル名そのまま(=Webシステムの文字コード)で保存してOKです。ターミナルやFTPソフトなどの設定によってはファイル名が文字化けして見える場合がありますが、問題ありません。

Macの場合(OS X 以降、darwin)は、ファイル名が UTF-8 でないとエラーとなり保存できません。UTF-8 以外の文字コードで Webシステムを組んでいる場合は、ブラウザが送信してきたファイル名を保存前に UTF-8 エンコーディングに変換する必要があります。

Windows サーバの場合は、ファイル名が Shift_JIS でないとエラーとなり保存できません。Windows サーバは内部的には UTF-8 を使用していますが、少なくとも2014年現在で Perl での Webアプリケーションから保存しようとする場合は Shift_JIS 以外はエラーになります。Shift_JIS 以外の文字コードで Webシステムを組んでいる場合は、ブラウザが送信してきたファイル名を保存前に Shift_JIS エンコーディングに変換する必要があります。

ダウンロードのリンクのファイル名文字コード

日本語ファイルをダウンロードさせるときは保存してあるファイル名のをその文字コードのままパーセントエンコードに変換(URIエスケープ)して <a> タグのhref属性に指定します。MacやWindowsでそれぞれ UTF-8 以外、Shift_JIS 以外で Webシステムを組んでいる場合は、Webシステムのページの文字コードとパーセントエンコードされたファイルの文字コードが異なる事になりますが、それでも問題ありません。

だがしかし

ここでもMacの場合とWindowsの場合はそれぞれ特有の問題があります。




Macのファイルシステムのファイル名

Macがファイルシステムに採用しているエンコーディングシステムは通常の UTF-8 と少し異なり、濁点・半濁点の文字を2文字で構成しています。例えば「が」は「か」+「゙」と変換して保存しています(1文字の方を以下「合字」と呼びます)。これは、Perlからは「が」と指定してファイルを書き出した場合でも、保存された時は「か」+「゙」になります。なお、-f 等のファイルテスト演算子を使う場合も自動的に変換され、「が」と指定すれば「か」+「゙」で保存されているファイルが期待通りチェックできます。

ところが、この保存されたファイル名を opendir → readdir で読み込んだ場合は、ファイルシステムに保存してある通り「か」+「゙」のまま取れてきます。このとき、ファイルシステムから読み取ったファイル名をリンクの href 属性だけに使うのであれば問題ありません。このままパーセントエンコードしてリンクできます。

ファイルシステムから読み取ったファイル名をリンクテキストなどで Webページ上にも表示する場合、Webシステムの文字コードが UTF-8 以外の時は、これを元の合字に戻してから変換しないと文字化けします。Shift_JIS や EUC-JP には、保存時に変換されてしまった濁点や半濁点に対応する文字が無いからです。

このため、Mac(darwin)では、濁点・半濁点の付いたファイル名をファイルシステムから読み取ってWebページに表示する場合は、Webシステムの文字コードが UTF-8 でないならば、ファイル名をまず合字に変換した後、使用している文字コードに変換する必要があります。Webシステムの文字コードが UTF-8 の場合は、2文字に分かれたまま表示しても大体のブラウザでは合字と同じ表示になりますので問題ありません。高機能なエディタでHTMLコードを見ると、2文字で構成されているのが見える場合があります。

なお、パーセントエンコードして使う href 属性の方は、「か」+「゙」をパーセントエンコードしたものでも「が」に変換してからパーセントエンコードしたものでも、どちらでも同じファイルにリンクできます。

WindowsのApacheのパーセントエンコーディング解釈

Windowsの場合、Webサーバが IIS(Internet Information Service)であれば保存された Shift_JIS ファイル名をパーセントエンコードしてファイルへのリンクが可能です。しかしながら、Webサーバが Apache の場合は Shift_JIS でのパーセントエンコードを想定していないらしく(Apache 2.2で確認)、Shift_JIS パーセントエンコード中の ASCII 文字だけを通常のアルファベットとして解釈して変換してしまうため、ファイル名が壊れてファイルを見つけられないという問題が出ます。

この時は、保存したファイル名が Shift_JIS にも関わらず、ファイル名を UTF-8 エンコーディングに変換してからパーセントエンコードすると、不思議な事にリンクが可能です。UTF-8 のパーセントエンコードは、Webサーバが IIS でもリンクできます。つまり、IIS は一つのファイル名を2つのエンコーディングでアクセス可能です。すごいですね。

日本語ファイル名アップロード・ダウンロードのポイントまとめ

日本語名ファイルを扱う時の必要な変換は、まとめると下記の通りです。

  サーバ環境
UNIX Mac Windows
送信されたファイル名 ブラウザ依存。詳細 ブラウザ依存。詳細 ブラウザ依存。詳細
ファイルシステムへの保存 変換なし UTF-8に変換 Shift_JISに変換
リンクファイル名
(パーセントエンコードする前に)
変換なし 変換なし
(合字に変換してもOK)
UTF-8に変換
ファイル名
(ページ上に表示)
変換なし 合字に戻してからページの文字コードに変換 ページの文字コードに変換