Windowsは奥深くではUnicodeを使っているはずだけれど,Windowsに送るZipファイルはファイル名をCP932にしないと化けるのが謎でしたが,Linux Conference 2006の岩本さんの論文CP-04を見てなんとなくわかりました。例えばファイルを作るシステムコールはCreateFile()を使うけれど実際にはCreateFileA()とCreateFileW()があり,前者はANSI(CP932),後者はUnicode(UTF-16LE)を使い,実際のファイルシステムにはUTF-16LEで格納されるということのようです。WindowsのZipがCreateFileA()を呼んでいるのが問題なんでしょう。ならApacheもそうかと思ってApache 2.0 の新機能の概要を見たらWindows NT上ではUTF-8でファイル名を扱えると書いてあります。このあたり,白井先生から昔お聞きした話がよく理解できていないので,混乱しています。
問題はApache以外のアプリケーションのUnicodeファイル名への対応ですね。PHP,テキストエディタ,そしてエクスプローラ(IEではなくファイルエディタ)。これらも対応していないとダメですね。
あと、不安なのは、あのApache2.0の説明で書かれているWindowsNTに日本語WindowsNTは含まれていないという悲惨な可能性。さすがにそれは無いと期待したいですね。
先日の調査で、PHPを介した日本語.Windowsへのファイルの読み書きにおいて、Windowsは与えられたファイル名がマルチバイト文字列がシフトJISであるという前提でUTF-16LEに変換していました。この操作、fopen()のWide版関数を用いればPCのロケールに依らずにUTF-16LEのままファイルシステムに対してスルーでアクセスできるのかも知れません。でも、PHPはまだ対応できていないように見えますね。
もしかしたら、CreateFile()の説明に書いてあったパス名の前に付ける特殊な文字列を追加したら、現状でもPHPやエクスプローラ上でUnicodeのファイル名が付けられる? だと良いですね〜。
現在は強制的にOSサイドでシフトJIS←→UTF-16LEの相互変換を行っています。多分、CreateFileW()を用いても与えられたファイル名の文字コードを自動認識してUTF-16LEと相互変換するようにはできません(UTF16-LEとシフトJISで異文字に同じ文字コードが割り当てられているかも)よね。となると与えられたファイル名の文字コードはUTF-16LEだから余計な変換はしないでね、という識別子が必要か、と考えた次第。
もしWindows用のソフトウェアをCreateFile()を用いて作成したとして、渡されたファイル名の文字コードを識別する手段が何か無いと困ります。プログラム中で自動作成されたファイル名ならばUTF-16LEかも知れないし、ユーザがキーボードから入力したのならばシフトJISなのかも知れない。
まとまりがなくて申し訳ありません。CreateFileW()を起点とし、もう少し調査してみます。もしかしたら"長いファイル名"と"短いファイル名"のように、比較的互換性の高い方法で対応されていて、それに気付いていないだけという可能性があります。理想はfs_moodleが不要な世界、ですね。
Windowsでファイル名にハートマークを付けている例をもう一度探し出しました.こちらです.
http://beefway.hp.infoseek.co.jp/prog/filename.html
CreateFileW()を使用しているのでしょうか.
さて,Windows版PHPでUTF-16LE形式でファイル名をダイレクトに保存可能かどうか,簡単に試して見ました.既存の'testA.pdf'をcopy()で別の名前のファイルにコピーしてみます.
$src = "testA.pdf";
$dest = "テスト.pdf";
$dest = mb_convert_encoding($dest, 'UTF-16LE', 'UTF-8');
$dest = '\\\\?\\'.$dest;
echo $dest.'<br/>';
copy($src, $dest);
パスの前にプレフィクスで'\\?\'を付ける,というのは,きっとこういう意味だろうと思って試してみたのですが,ダメでしたね.
\\?\�0�0�0.pdf
Warning: copy(\\?\�0�0�0.) [function.copy]: failed to open stream: No such file or directory in C:\xampplite\htdocs\mech\moodle\test.php on line 35
\\?\テスト.pdf
Warning: copy(\\?\テスト.pdf) [function.copy]: failed to open stream: No such file or directory in C:\xampplite\htdocs\mech\moodle\test.php on line 35
こちらはUTF-16LEに変換しないで,UTF-8のままにした場合です.
頭の'\\?\'を付けなければ”化けた”ファイル名のファイルが(正しく)作成されます.
php.iniになにか設定を付けると有効になる可能性はありますが,そこまでの調査はできていません.ファイル名の頭に'\\?\'が付いていたらCreateFileA()が,付いていたらCreateFileW()が呼ばれるように準備されているのかな,と少し甘く期待した実験です.
現状ですとPHPがUnicodeに対応できていないようですね.ApacheがUnicodeに対応しているとしても,このままではダメです.
先ほどから落雷による瞬停が頻発しているので小出しになります.
さて,ではCreateFileW()のAPIを使ってWindowsのファイルシステムにUTF-16LE素のままのファイル名でファイルが作成できることを確認し,それが他のソフトウェアにどのような影響を与えるのかを調べてみようと思いました.
考えたまでは良かったのですが,私がいつもWindowsアプリケーションを作成しているBorland C++ Builder (Turbo-C++)にはCreateFileW()に相当する関数が見当たらない...そもそも普段から”便利なC言語”としてC++言語を使用しているので,ファイルオープンはfopen()を使用している._wfopen()みたいな関数が存在するのかと期待したのですが...というわけで,Unicodeなファイル名を作成することができません.
ファイルシステムで,このファイルの名前はシステムのロケールに合わせてUTF-16LEと相互変換するべきものかどうか,を判断する属性を持つならばApacheからもUTF-16LEでアクセスできるのかも知れません.ただ,ここでUTF-8ではなくUTF-16LEでファイル名をAPIに渡さなくてはならないのだとすると,面倒ですね.どういうメカニズムでApacheはUnicodeのファイル名に対応しているのでしょうか.
アプリケーションは作れませんでしたが,その代わりエクスプローラで「♡.pdf」というファイル名にリネームできました.さて,このファイルを他のアプリケーションはうまく処理できるか?
(OK)
・秀丸エディタ: 読み込めました(バイナリファイルですが).
・Adobe Reader8: ダブルクリックで開くことができました.
・Firefox3 (+Apache2.2): URLをFirefoxに入力(http://www.suzuka-ct.ac.jp/mech/moodle/test/♡.pdf)してPDFファイルが開けた:これがApacheのUnicode対応という意味?
・Explzh(アーカイバ): ♡.pdfを圧縮した♡.lzhを作成化.それをダブルクリックして解凍&起動OK.
(NG)
・Irfan (Viewer): ♡.jpgを開けませんでした.
・Adobe Photoshop6: ♡.jpgを開けませんでした.
意外と♡はOKのようです.ちょっと古いソフト(特に海外物)はダメな傾向が見えます.
となると,PHPさえWindowsネィティブなファイルシステムへのアクセスにも対応してくれればWindowsでもUnicode対応が可能な感じがしますね.一部,古いソフトで処理できない点を除けば.
PHPのUnicodeファイル名への対応法(関数を使い分けるなど)によっては現状のfs_moodleのような大変な方法を継続しないとならないかも知れませんねぇ.
なお,ハート記号はこちらのWebページからコピー&ペーストして利用しました.
http://www.mukaiaki.com/cgi-bin/pc_qa/details.cgi?id=8
>私もWindowsで「萌え♥.txt」のようなファイルを作ってみました。
なんとなく負けたっという感じです(^^;).
気になるのは,PHP6のUnicode対応がファイル名/フォルダ名などのファイル関係の関数のことかどうか,ですね.ここが問題になるのはWindowsだけ?と思うと,内部の文字データの取り扱いをUnicodeで統一する(あるいはできる)ようにする拡張とも読み取れます.
fs_modleではUnicodeのファイル名やフォルダ名をファイルシステムに対してシフトJIS変換して渡しているだけです.データベースにはUnicodeのままの情報で記録されていますから,「よし,対応するぞ」という時には,一気にmoodledataフォルダ以下のファイル名/フォルダ名をシフトJISからUnicodeに変換するソフトウェア(あるならば使うし,無ければ作らなければならない.PHPでも良いかな?)で変換すれば,その後は何事も無かったかのように新システムに移行できます.ですので,PHP6の今後の動向についてチェックを続けようと思います.
Linux Conferenceの岩本氏の論文を読ませて頂きました.
内容も参考になりましたが,あのフリーのWindows用ビデオ編集ソフトVmaidの岩本さんだったのですね.特許問題に巻き込まれて公開中止になった時は本当に残念でした.とても使いやすく高性能なソフトでしたので.その後,Video Maidとして新しく公開されたと聞いていたのですが,しばらく情報を追うのを忘れていました.
以前にまとめたWindowsのファイルシステムに関する論文の抜粋を再構成したものを公開予定です.推敲しようと放置したままですが,ほぼ完成しています.このCreateFile()関係も追加すると発表が遅れるので,それはまた続報として.
(CreateFile()というキーワードのお陰で,未知の情報が沢山,入手できました.ありがとうございました)