単語検索で「朝」が「i-」に化ける†
- ページ: BugTrack
- 投稿者: にぶんのに
- 優先順位: 普通
- 状態: 完了
- カテゴリー: 本体バグ
- 投稿日: 2003-04-14 (月) 02:25:13
- バージョン:
メッセージ†
単語検索で「朝」の1文字を検索すると、検索語の文字化けが発生して、正しく検索できない。
- 当方の環境では「朝」が「i-」に化けています。
- 「朝」でなく、「朝に」、「朝が」なら文字化けは起きなかった
雑談で出ていた以下のバグも同じ理由と考えられますので、ここに含めておきます。 -- 三浦克介
- 新規ページ作成で、「名前」等のページ名を指定すると、「?の編集」となってしまう。
- EUC-JP特有の化けかな? UTF-8では問題なく「朝」で検索できるようです。 -- reimy
- こちらでは、ココで検索した時醇dとなりますが :D -- aru
- 「表」「予」「貼」などを検索してもおかしいですね。 --
- init.php内で、postされたデータの文字コードを自動判別/コード変換しているんですが、そいつが入力文字コードを誤認しているようです。 -- ぱんだ
- フォーム内に適当な文字列(よくある「美乳」や「雀の往来」など)を埋め込んで、文字コードの誤認が起こらないようにする手とか、全てのフォームにSOURCE_ENCODINGの隠しフィールドを入れてしまうとか。 -- ぱんだ
- EUC, SJIS, UTF-8は、原理的に、コードの検出を誤るケースがあります。特に、短い文字列では発生しやすいです。デフォルトでは、コードの検出順序がASCII, JIS, UTF-8, EUC-JP, SJISとなっており、UTF-8と誤認されているようです。対策法としては、
- ぱんださんがおっしゃっているように、フォーム内にコード認識用の適当な文字列をいれておく。一応、うまくいくことを確認済みです。なお、SOURCE_ENCODINGフィールドを入れておく方法は、必ずしも、ブラウザがそのコードでPOSTしてくるとは限らないので、逆に文字化けを発生させる可能性があると思います。
- mb_detect_order() で、UFT-8よりも前にEUC-JPを指定しておく(UTF-8化PukiWikiでは、デフォルトの検出順位の方が良い)。これも、うまくいくことを確認済み。但し、EUC以外のコードでポストしてくるブラウザがあった場合(携帯からのポストする場合も)、やはり、誤認の可能性があります。
- ページの出力コードをJISにする。原理的に、JISコードは他のコード(EUC, SJIS, UTF-8)と確実に区別できるはずであり(試してはいません。しかし、シフトイン、シフトアウトのコードが確実に検出できるはず)、大抵のブラウザは、JISコードのページに対してはJISコードでポストしてくるので(未確認。IEはそうでした)、うまくいくはず。やはり、携帯からのポストや、JIS以外のコードでPOSTしてくるブラウザには無力。
- どれが良いですかね? -- 三浦克介
- <form>タグにaccept-charset属性でEUC-JP(UTF-8化した場合はUTF-8)を指定する。デフォルト値はunknown。携帯を除けば、この属性値を無視して違うコードをPOSTしてくるW3C準拠ブラウザはないはず(この属性はHTML4.0/XHTML1.0/XHTML1.1だけでなく、大昔のHTML 2.0の国際化版であるHTML i18N時代から存在します。PDAや携帯用のXHTML Basicにはこの属性は存在しません)。 -- reimy
- と思ったら、こんなページを発見。Mozilla以外のブラウザは信用できない? w3mの古いバージョンでもaccept-charsetにバグがあったらしい(参照)。 -- reimy
- 残念ながら、formでaccept-charset を指定したとしても、全てのブラウザがそれに従ってくれるのを期待するのは無理のようですね。何重かの対策が必要と思われます。 -- 三浦克介
- formに accept-charset="euc-jp,
iso-8859-1us-ascii" あたりを (気休めに) 指定しておく (iso-8859-1 は必要かな?) UTF-8なら、accept-charset="utf-8,iso-8859-1us-ascii"。携帯相手の場合は、accept-charset は無視されると思われるので、指定しても、しなくても関係無し?
- mb_detect_order("ASCII,JIS,EUC-JP,UTF-8,SJIS"); あたりを init.php で実行。UTF-8なら、mb_detect_order("ASCII,JIS,UTF-8,EUC-JP,SJIS"); とするか、デフォルトのままいじらない。携帯の場合は、mb_detect_order("ASCII,JIS,SJIS,UTF-8,EUC-JP");。
- formにコード検出用のhiddenフィールドを入れておき、適当な文字列をvalueに指定しておく。
- の3段構えでどうでしょうか。これだけしておけば、コードを誤認する確率はだいぶ低くなると思います。 -- 三浦克介
- ちょっと古いですが、CGIと漢字コードという、ブラウザが POST してくるコードを調査したページがありました。参考までに。ちなみに、MSIE3.0は、フィールド毎にコードが変わることがあるらしい。今更、MSIE3.0の為に対策をしてやる必要は無いと思いますが、現在のPukiWiki/1.4ではGET、POSTのデータを全てマージした上でコード判定をし、検出されたコードからEUC(UTF-8)へのコード変換をしていますので、フィールド毎にコードを変えられるとお手上げです。 -- 三浦克介
- どうしましょう。とりあえずhtml.php/catbody()あたりで、<input type="submit">を発見したら直前に<input type="hidden" name="encode_hint" value="雀の往来">を挿入するような仕掛けを入れておきましょうか。 -- ぱんだ
- 時間がかかってすみません。現在、変更箇所を検討しているところです。<input type="submit">を見つけたら入れる、とすると、一つのフォームに複数のsubmitがあるとき、複数のhiddenが入ってしまいますよね。今のところ、<form ...>を見つけたらその直後に入れるようにしています。これだけだとダメで、未作成のページの作成画面へのリンク ($script?cmd=edit...) とかにも入れる必要があるなど、変更箇所はそこそこ多いです。 -- 三浦克介
- それと、検出用の文字列(雀の往来)ですが、できるだけ短い方が良いかと思い、1文字で検出可能な文字を調べてみました。PHP GET/POSTメソッドでの日本語の文字化け防止 のページにまとめてありますが、大抵の文字は1文字で検出可能です。POSTの場合は問題ないですが、GETの場合はあまり長くならない方が良いと思いますので、何か「これぞ、PukiWikiを象徴する1文字!」を決めて、それをコード検出文字にしてはどうでしょうか。例えば、「ぷ」とか。 -- 三浦克介
- (まだ、PukiWikiのコードの全体的な構造が把握できていませんが・・・)現状では、GETメソッドで与えられるページ名も、デコードして、コード検出して、コード変換しているのですよね? GETメソッドで与えられたページ名については、コード検出・変換等行わない、というようにするとまずいでしょうか? 問題があるとすると、他のWikiサイトからInterWikiでページを参照する場合に、ページ名のエンコーディング方法の指定を間違えると、参照できない、ということだと思うのですが・・・、どうでしょうか。コード検出・変換するのであれば、PukiWikiサイト内のページに対するリンクについても、ダミー文字列を入れる必要が出てきます。 -- 三浦克介
- そうですね。GETリクエストについてはスルーして問題ないはず。 -- ぱんだ
- ブラウザのアドレス欄に「http://.../pukiwiki.php?ほげほげ」などと手打ちする人がいたら問題かもしれませんが。現状でもそれは通らないような気が。 -- ぱんだ
- あ。「?cmd=read&page=ほげほげ」だと変換ルーチンを通る…この場合は入力文字コードがそれこそ環境によってEUC/SJIS/他のどれになるかわからないので、変換ルーチンを通すべきなんだけれど、うーむ。 -- ぱんだ
- たらこせるさんが書いてたように、すなおにUTF-8化するのが一番手っ取り早かったりして…(^^;; ほんと、厄介ですね。 -- reimy
- UTF-8化しても、UTF-8以外のコードで送信された場合は、文字化けの可能性があります。逆に言えば、EUCでも、mb_detect_order("ASCII,JIS,EUC,UTF-8,SJIS") としておけば、EUCで送信されたデータに関しては、100%文字化けは発生しません。送信されたデータのエンコーディングが不明の場合は、検出用文字列を入れておかない限り、100%のコード検出は原理上不可能なんです。GETメソッドで与えられたデータについて、コード検出・変換が必要なケースと不要なケースに分け、できる限り、文字化けを防止するように、もう少し考えてみます。でも、"?cmd=read&page=ほげほげ" と手打ちされ、この時のページ名がコード検出不能文字しか含んでいない場合は、文字化けの可能性はゼロにはできません。 -- 三浦克介
- formに accept-charsetを指定するだけでいいんじゃないでしょうか。accept-charsetで指定された文字コードを送らないブラウザは、ブラウザ側のバグですから、PukiWiki側でブラウザのバグの面倒まで見る必要はないと思うのですが。 -- reimy
- 「壁」を PukiWiki-official で検索すると結果が変です。1.4rc2 で運用している自分のサイトだと「な部分」という文字の組合せに反応し、強調文字を埋めこんでくれるため、文字化けします;-)。accept-charset もいれてみましたが、だめです。PHP は 4.2.2 です。
341 なる BugTrack を作ってしまったのですが、reimy さんにここを教えてもらい、消しました。それで内容を少し補足しておこうかと。私は Perl 屋なので PHP のコードはあまり書いたことがありません。
Perl だと http://www.din.or.jp/~ohzaki/perl.htm#JP_Match にちょっと文字化けの情報があり、今回のケースに関係ありそうです。当方は「壁」を探しても「壁」という文字自体は化けず、検索結果がおかしいのです。フロントエンドとバックエンドの 2 つの問題があるのか、片方だけなのかは不明ですが……。-- 閑舎
- EUC-JP で運用していた PukiWiki を力技で UTF-8 に変えてしまいました。UTF-8 は 2 バイトクリーンなので、検索に失敗することがなくなりました。以上ご報告まで。 -- 閑舎
- すみません。ここのところ忙しくって、手がつけられていません。「壁」に関しては、mb_detect_encoding() の問題ではないです。正しくEUC-JPと認識されます。検索の問題ですね。2バイトコードの2バイト目と次の文字の1バイト目にマッチしてしまっています。ということで別のバグです。ソースをチェックしていませんが、マルチバイト対応の検索関数を使っていないのか、あるいは、マルチバイト対応検索関数の不具合かだと思われます。 -- 三浦克介
- そうですね。私も追っかけていくうち、ご指摘のように別問題だとわかりました。マルチバイト関係は EUC にしておけば Ok というものでないのが厄介ですね。暇になったら対応よろしく。私は発生時の経緯から知ってますが、本来的には Unicode って好きじゃないので。 -- 閑舎
BugTrack/412 につづく。 -- 三浦克介
- 根本的解決の為の修正パッチです。
bugTrack296a.diff.txt -- 三浦克介
- 以下の方法により、文字化けを防止しています。
- GET/POST に関係無く、<form> に、hiddenフィールド encode_hint="ぷ" を自動挿入。
- 受け取ったPOSTデータには、必ず encode_hint が含まれているはずなので、これを使ってコード検出(encode_hint以外のデータは、コード検出に悪影響を与える可能性がゼロではないので、コード検出時には無視してます)。
- 受け取ったGETデータには、encode_hintが含まれている場合とそうでない場合がある。
- <form methd="GET" ...> により、ブラウザが生成したデータの場合
- <a href="...>のリンクにQUERYが含まれていて、これをクリックした場合
- ブラウザのURI入力部に、手入力でURIを(QUERYも含めて)urlencode せずに入力した場合
- 上記 a. の場合は、GETデータの中に encode_hint が含まれるので、POST の場合と同様に、encode_hint を用いてコード検出し、全体をコード変換。
- 上記 b. の場合、URI はサーバーが生成しており、正しくエンコードされているはずであるので、コード変換は一切行わない。
- 上記 c. の場合(URIのQUERY部に、非ASCII文字が含まれているか否かで判定)は、GETデータをマージしてコード検出・変換を行う。
- 上記 c. の場合で、GETデータに含まれる日本語文字の部分が短い場合、文字化けの可能性は残ります(但し、URIに非ASCII文字を書くのは、本当はしちゃいけません)。
- ここでテストをしています。 お暇な方、短い名前のページを作ったり、短い単語の検索をするなど、テストしてみてください。問題なければ、CVS 投入お願いします。>コミッターさん
- cvsに投入しました。 -- ぱんだ
コメントスパム対策 -- ko-zu #comment外してます