Windowsにおける日本語ファイル/フォルダ名の文字化け対策

Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿
返信数: 12

データフォルダへのファイルアップロード,フォルダ作成,ファイル/フォルダ名のリネームがWindowsPCをサーバとする場合に一部化けてしまう問題に対する検討のためのトピックであり,

http://moodle.org/mod/forum/discuss.php?d=71061

後半からの続きです.順次,作業の進み具合を報告します.

現状では,moodle/files/index.phpおよびmoodle/lib/uploadfile.phpを修正し,日本語ファイル名/フォルダ名をrawurlencode()/rawurldecode()してファイルシステムに保存させることで問題を回避することが可能であることまで試験的に確認済み.

ちなみに,S-JISにファイル名/フォルダ名を変換することで期待通りの効果が得られるかと思われ,一部成功したが,ファイルのアップロードの際にフォルダが見つからない,というエラーが出てしまう状態にある.

現在,UTF-16,S-JIS,rawurlencode/decodeの3種類で試せるように変換部を関数化し,ユーザ側で選択できるようにする作業を行ないながら,うまくファイルI/Oを誤魔化すにはどこに手を入れたら良いのか,を洗い出しているところです.

S-JISでフォルダの作成は成功しました.エクスプローラで見ることもできるため,このまま成功すれば日本語Windowsのユーザにとっては嬉しい話.S-JISでうまくいくならば,UTF-16でもうまく行くでしょう.


Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿

データフォルダをWebファイルで参照する場合,
moodle\lib\editor\htmlarea\coursefiles.php
にも手を入れないといけないことが判明.

意外とあちこちに飛び火している可能性がある.
しかしハイパーリンクできないことには日本語ファイルをアップロードする意味がない.
rawurlencode()されたフォルダ名ならば(表示はメチャメチャでも)参照の際にフォルダへの移動やファイルの選択くらいはできると期待していたが,フォルダへの移動をおこなった段階で,いくつものエラーが同時に表示された.

以下,そのエラーメッセージ.
Warning: opendir(C:\xampplite\moodledata/13/test/参考文献) :ここは何故か正しく表示されている.
[function.opendir]: failed to open dir: Invalid argument in C:\xampplite\htdocs\moodle\lib\editor\htmlarea\coursefiles.php on line 656

Warning: readdir(): supplied argument is not a valid Directory resource in C:\xampplite\htdocs\moodle\lib\editor\htmlarea\coursefiles.php on line 657

Warning: closedir(): supplied argument is not a valid Directory resource in C:\xampplite\htdocs\moodle\lib\editor\htmlarea\coursefiles.php on line 668
Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿

ファイルシステムに合ったファイル名/フォルダ名に変換してファイル操作を行うという方向で検討を行なっているが,これには2つのアプローチが考えられる.

(1)入り口での対策:ファイル名/フォルダ名が入力された段階で変換してしまう.この場合,ログ等には変換された文字コードで記録されてしまう.また,選択時は既に変換された文字コードであるため,それをサイトの文字コードに変換する必要がある.

(2)水際での対策:ファイル/フォルダを操作する直前で文字コード変換を行なう.この場合,moodleの各所(ログやリンク)ではUTF-8のオリジナルのファイル名で格納されているため,安全性は高いが,PHPコードの変更箇所が膨大になる可能性が高い.

(1)の方向でまず第一段階の処理を行ってみたところ,フォルダの作成,リネーム,削除,ファイルのアップロードには成功した.しかし,HTMLエディタ等でリンクを張る際に問題が発生した.

(2)について調べているところだが,先にあるようにリンクを編集する際にはmoodle\lib\editor\htmlarea\coursefiles.phpに,さらに(1)では解決済みのフォルダを作成する場合であっても,make_upload_directory()の存在するmoodle\lib\setuplib.phpを修正する必要がある,といった感じで一つ一つ潰していく必要があるようである.

Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Yasuhisa Matsumura の投稿

うわーっ、大変ですね。私には到底出来そうもない仕事です。ところでこれらの問題に関係があるのかどうか、あるとしても問題の解決に至るのかが判然としないのですが、この1週間頭を悩ましていたことがあります。それは、Windows版のPHP5の日本語処理の仕方に深刻なBugがあるのではないか、という疑いです。(まぁ、仮にBugがあったとしても特にMoodleには関係しないような気もするのですが...)とりあえず疑問だけをぶつけておきます(すみません・・・)

疑問点:PHPの組み込み関数であるrawurlencodeの処理が異常ではないか?実際Shift_JISコードの「実践工業数学参考文献.doc」というファイル名にrawurlencodeをかけると「%8E%C0%91H%8DH%8B%C6%90%94%8Aw%8EQ%8Dl%95%B6%8C%A3.doc」という文字列に変換されます。この文字列はちょっと変です。%記号の直後に3文字となっている箇所が4か所程度あります。しかもHやQ、小文字のwやlという文字は、16進数の表現としてはとても異常です。他の日本語文字コード表から想像すれば、この文字列は正しくは「%E5%AE%9F%E8%B7%B5%E5%B7%A5%E6%A5%AD%E6%95%B0%E5%AD%A6%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE.doc」となっていなければならないはずです。実際、前者のコード文字列にrawurldecode関数でデコードしてみると、全く意味不明な文字列になるのに対して、後者の文字列にrawurldecodeをかけると、UTF-8コードの「実践工業数学参考文献.doc」という元の文字列にきちっと戻すことができます。

そこで思い余って、ええい、PHPの勉強だと思って、rawurl_encodeという別の関数を作ることにしました。一応、正常に動いているような気がします。このrawurl_encodeを使ってMoodleのなかのrawurlencodeを置き換えると、一応Windows上のMoodleでファイルの処理が正常に行えているような気がします。これまであった現象、「実践工業数学参考文献.doc」というファイルがアップロードできないなどというような現象もないようなのです。Moodleの内部処理として、すべてUTF-8コードで処理させられるような気がします。ただ依然として単なる表示がうまくいきません。たとえば、「実践工業数学参考文献.doc」というファイルをアップロードすると、画面上では「_.doc」という表示なります。ただこれだけのことで、このファイルを開いたり、ダウンロードしたりすることは全く問題ないです。ただ以前よりは、私自身の中で進歩した点があります。それは、Primeira LiçãoとかBücherという欧文の文字を使った<ファイル名>をきちっと表示してくれるようになったことです。だから、Moodleの内部処理をすべてUTF-8コードで行わせるようにすれば、日本語表示もrawurldecodeでデコードするようにどこかでソースコードを変更すれば、うまくいくのではないか、という期待感があるのですが...。

(なお、この私製のrawurl_encodeでMoodleを試してみよう(=危険を冒してみよう)という奇特な方がいらっしゃいましたら、別途松村にメールをいただけませんか(matsmura@nufs.ac.jp)?というのは、このrawurl_encodeは、文字コード表の独自のデータベースを組み込んだ(辞書的に検索します)大きなデータなのです。圧縮しても1.8MBもある巨大なファイルとなって、ここにアップロードできません(申し訳ないです・・・)。

補足の補足です: 私製のrawurl_encodeとPHP組み込み関数のrawurldecodeとを使えば、Shif_JISコードの文字列からUTF-8の文字列に変換することができるわけですが、今回のプログラムを応用すれば、逆にUTF-8コードからShift-JISコードへの逆変換プログラムも比較的簡単にできると思います。なお、Browserに表示するだけならUTF-8で問題はないでしょうから、その必要はないかと思ってこの逆変換プログラムは作っていません。


Yasuhisa Matsumura への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿

詳細な解説と情報提供ありがとうございます.
まだジックリと読んでいませんが,以下の記事にもヒントがあるかも知れません.
http://jsgt.org/ajax/ref/charset_test/responsetext/php/urlencode.php

rawurlencodeとは別にurlencodeというものもあるようですね.こちらは空白を+に置き換えるなど,ちょっと違うようです.
http://www.phppro.jp/phpmanual/php/function.urlencode.html

PHPの中のrawurlencodeはUTF-8を変換することを前提としてコーディングされていて,Shift-JISだと異常動作するのではないのか?ということですね.なんとなくありそうな気もします.rawurlencodeの変換がどのような変換を行なうのか知らないのですが,機械的に文字コードのデータをバイナリーのデータとして扱って単純に16進コードに変換しているわけではないのですね.少々期待していたのですが...

期待としては,
Shift-JIS -(rawurlencode)-> 16進コード -(rawurldecode)-> Shift-JIS
となると思っていたのですが,「実践工業数学参考文献.doc」の化け具合などから考えるに,

オリジナルのPHP5は,
UTF-8 -(rawurlencode)-> 16進コード -(rawurldecode)-> UTF-8
であって,
Shift-JIS-(rawurlencode)->変な16進コード -(rawurldecode)-> 期待とは異なるUTF-8
という理解で宜しいでしょうか.

そして松村さんの作成したrawurl_encodeでは,
Shift-JIS-(rawurl_encode)-> 16進コード -(rawurldecode)-> UTF-8
が可能になる,と.

これは,
Shift-JIS-(mb_convert_encoding)-> UTF-8 -(rawurlencode)-> 16進コード -(rawurldecode)-> UTF-8
とは異なるのでしょうか? (やはりよく理解できていないのかも...)


moodle内部は全てUTF-8で扱い,PHPのファイル/URL関係の関数の前後を地道にShift-JIS->UTF8 , UTF-8->Shift-JIS化して,ファイルシステムには全てShift-JISでファイル名/フォルダ名を作成する方針で考えていましたが,wikiやWebページの作成など,日本語のフォルダ名やファイル名にハイパーリンクする場面においてこのurlencode関係はいつか障害になるだろうなぁと漠然と考えていました.したがいまして,今回のお話,とてもタイムリーでした.

PHPの関数の前後でしらみつぶしにコード変換するよりも,PHPの関数をオーバーライドできないだろうか,それともソースリストを元にしてオリジナルのPHPバイナリを作成するのか?(無理悲しい)などと考えていると,結構楽しいのですが,技術的な限界はいかんともしがたいところです...PHPの設定をちょこっと変えるとこれが実現できるのでは?などと考えたのですが,そのような関数は無さそうですね.ファイルI/O,Windows向けの実装はどのように考えて進められているのか,知りたいところです.OSのロケール設定を突破してUTF-16でファイル名/フォルダ名を書き込むような実装がされたらとても嬉しい.

Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Yasuhisa Matsumura の投稿

Tatsuya Shirai>

そして松村さんの作成したrawurl_encodeでは,
Shift-JIS-(rawurl_encode)-> 16進コード -(rawurldecode)-> UTF-8
が可能になる,と.

Matsumura> あ、そうです。そうです。

Tatsuya Shirai> これは,
Shift-JIS-(mb_convert_encoding)-> UTF-8 -(rawurlencode)-> 16進コード -(rawurldecode)-> UTF-8
とは異なるのでしょうか?

あぁ、そうか。そういう簡単なやり方できちんとUTF-8コードに変換できているんですか?この変換については問題ないんですね? なんだ、そうか。くたびれもうけだったかなぁ?それでもPHPのお勉強にはなりました。ちょっとゴミのメッセージを撒き散らかしたようです。すみませんでした。

Yasuhisa Matsumura への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿
いや,分かりませんよ.
もしかしたらWindows版PHPのrawurlencode/mb_convert_encodingの実装に大きなミスがある可能性は無いとは言い切れません.それと,Shift-JISとUTF-8の対応も完璧と言う保証はありません.Shift-JIS->UTF-8->Shift-JISで戻すと別のコードになっている,という不安も完全には拭えません.

問題の切り分けが付かなくなった時のために,是非とも作成したrawurl_encodeのソースを分けて頂きたいです(メールします).rawurlencode()には細工を仕込めませんが,松村さんが作られたrawurl_encodeならばデバッグコードを埋め込むこともできますし,とても有用だと思います.


Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿
添付したファイルのようなライブラリを作成してテストを続けています.

string currentCharset2fsCharaset(string):moodleが使用している文字コード(UTF-8)からファイルシステム(日本語WindowsではShift-JIS.$CFG->fsCharsetで指定できる)の使用できる文字コードへ変換します.

string fsCharset2currentCharset(string):その逆です.

$CFG->fsCharsetでは,
$CFG->fsCharset = 'S-JIS';
// $CFG->fsCharset = 'WINDOWS'; // localwincharset
// $CFG->fsCharset = 'RAWURL'; // rawurlencode/rawurldecode
// $CFG->fsCharset = 'UTF-8';
// $CFG->fsCharset = 'UTF-16';
// $CFG->fsCharset = false;
を選択できるようにしています.

テストですので,色々と用意しましたが,実用的ではないものも含まれているでしょう.
何事も無かったようにするには,falseを選択すれば引数で与えられた文字列をそのままreturnします.

細かい部分に手を入れ続けていますが,そのお陰で比較的副作用が少ない状態で,ファイルのアップロード,フォルダの作成,リネーム,削除,編集あたりの操作は日本語WindowsXP上でS-JISで行なえています.これでかなりファイルの管理も容易になりそうです.

まだまだ作業を再開したばかりですが,とりあえず,力技でどこまで行けるか確かめてみます.修正箇所等は全て当方のサイト内のwikiにまとめています.エクスポートできるようならば,作業が全て終わったところで公開できます.

Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿

順調に進んでいたのですが,ZIP書庫の保存で止まりました.
どうもWindows版PHPのpathinfo()は少々脆弱なところがありそうです.
C:/xampplite/moodledata/30/TEST/1
というパスを分解しようとすると,
C:/xampplite/moodledata/30/TEST
をパス("dirname")とは認識してくれるのですが,
ファイル名("basename")として"1"が化けてしまい,その上,拡張子("extension")が
処理されないため,参照しようとするとワーニングが発生します.

CentOS版のmoodleではこの問題は発生しませんでした.
"1.zip"(全角の1)という名前のzip書庫を作成できるか,否か.

当方の環境ではpathinfo()が処理を失敗します.

仕方がないので,怪しげな自作のpathinfo()を作って組み込みました.
徐々にライブラリが大きくなっていきますが,添付したファイルにあるように,静的関数を誤魔化すような方法でパッチを作成中です.(例: fopen() -> fs_fopen())


Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿
少し進展しました.

ファイルシステムの文字コードをShift-JIS (日本語Windows)に設定してデバッグを行なっています.

その状態で,
・フォルダの作成,リネーム,移動,削除
・ファイルの作成,リネーム,移動,削除
・zip書庫の作成
に加えて,
・リソースの追加として,ファイルへのリンク
が出来ました.

なぜかzip書庫の解凍とリスト一覧の表示ができません.

http://www.suzuka-ct.ac.jp/mech/moodle/course/view.php?id=30
こちらに途中経過のWikiをゲストログオンで閲覧できる状態にしてあります.
(なぜかゲストログオンすると大量のNoticeが出るのですが...これは私のせいではありません赤面

なお,学外からはアクセスできないmoodleを使用して開発を行なっていますので,上記ページ上に追加されている日本語ファイル名のリソース等は正常に表示できません(オリジナルのmoodleのままですので).

リソースの追加で日本語名フォルダをコースに追加できるようにすること,課題で日本語のファイル名のファイルを提出できるようにすること,Wikiで日本語キーワードを使うと化けることがあること,など,まだまだ完全Shift-JIS化の道は遠いですが,一応の目途が立ったという報告です.
(修正箇所は,多いような少ないような,微妙なところです.恐れていたほどには多くありませんでした)
Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿
ほぼ完了しました.

フォルダの作成,リネーム,移動
ファイルのアップロード,リネーム,移動,編集

ファイルとフォルダのzip圧縮,zipリスト表示,zip解凍(*)

リソースの追加: ファイルへのリンク,フォルダの表示

いま現在,一つだけ不具合があります.zipの解凍で,フォルダ構造を保ったまま圧縮できるのですが,それを正しく解凍できない場合があります.これこそpclzip内の問題ですので,手を出すのが大変です.パッと眺めたところ,str_replace()しているようなところは見当たらないのですが...正しく解凍できない場合は?記号を含むフォルダに解凍されます.解凍できないわけではないので,致命的とまでは言いませんが...

エクスプローラで,moodledataフォルダ内の日本語のフォルダやファイルがそのまま見えるのは,かなり快感ですね!

Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿
[活動の追加]の[課題]に関して,
・単一ファイルのアップロード
・複数ファイルの高度なアップロード
も正常に動作するようになりました.

これで実用性はほぼ満足したようです.
以前に,Wikiで日本語の見出し語を使うと化ける場合がある,と言った気がしますが,その後,そのようなことを一切関知しないで使用している学生からは「問題ないですよ」という意見.自分で試してみましたが,確かに,試した範囲では化けませんでしたので,Wikiは問題ないようです.

Tatsuya Shirai への返信

Re: Windowsにおける日本語ファイル/フォルダ名の文字化け対策

- Tatsuya Shirai の投稿
お約束の(?)IEではうまくダウロードできない問題にぶちあたりましたが,なんとか解決しました.

奥村先生たちの対策は,send_files()で使う引数のうち,$filenameをSJISあるいはURLエンコードするという方法です.これは当方でも利用しました.

問題はそれ以前にファイルの有無を確認するところでコケてしまいました.
$pathnameに実際のファイルのフルパス名が入っている(UTF-8)のですが,ダウンロードしたいファイル名をクリックしてfile.phpを呼ぶ際に,Firefoxはマルチバイトの文字列をURLエンコードしてくれます(URLではなくてもエンコードしてくれるようですね).それに対してIE6の場合は生のデータ(UTF-8)のままで送信してしまうようです.file.phpが受け取った引数を分割したりしてパス名を切り出して$_GET[]という配列に入れるのですが,ここでデータが欠損するようです.$pathnameは$_GET[]を受け取っている.ところがどこでこの$_GET[]をセットしているのか,コードを読んでも追いきれない.こちらの方向は諦めました.

そこでダウンロードできるファイルの一覧を表示するmod/assignment/type/upload/assigment.class.phpの中のprint_user_files()の中でハイパーリンクを生成する際に,(Firefoxは自動的にコード変換してくれるのと同じように)ファイル名をrawurlencode()してしまう方法を選択しました.

マルチバイトのデータを自動的にエンコードしてくれないのはIEの仕様なのでしょうか.それとも設定次第なのでしょうか.

さて,来週は定期試験ですので,ここで一旦,作業を停止します.
実験結果とどこをどう変更すれば良いのか,改めて整理し直して報告します.


IEでリンク先のURLがエンコードすると変になる問題は,以前に松村先生にご報告していただいたS-JISをrawurlencode()すると変になる,という現象に少し似ている感じがします.$_GET[]で受け取った文字列をrawurlencode()すると,例示していただいたようなへんてこりんな文字列(%の後に3文字.正確には%の後に2桁の16進コード+1文字のANK文字)になります.rawurlencode()に問題があるのではなく,IEを介してマルチバイトをPHP間で受け渡しを行なうと,マルチバイトを明示的にURLエンコードしないと受け取り側でむちゃくちゃに化ける可能性がある,ということなのかも知れません.

もしかしてPHPのmb_string関係の設定で,強制的にURLエンコードして送出するという設定があって,それを私の方では設定していないだけ,という可能性もあります.

[mbstring]
; language for internal character representation.
mbstring.Xlanguage= Japanese

; internal/script encoding.
mbstring.internal_encoding = "UTF-8"

; http input encoding.
;mbstring.http_input = auto

; http output encoding. mb_output_handler must be
; registered as output buffer to function
mbstring.http_output = "UTF-8"

; enable automatic encoding translation according to
; mbstring.internal_encoding setting. Input chars are
; converted to internal encoding by setting this to On.
mbstring.encoding_translation = On

; automatic encoding detection order.
;mbstring.detect_order = auto

; substitute_character used when character cannot be converted
; one from another
;mbstring.substitute_character = none;

; overload(replace) single byte functions by mbstring functions.
; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(),
; etc. Possible values are 0,1,2,4 or combination of them.
mbstring.func_overload = 7