- ベストアンサー
文字コードの判別ができない
- 特定の文字にて、mb_detect_encodingが正常な文字コードを返してこない現象が発生しています。
- DBから取得したデータをエンコードする際に文字化けする問題があります。
- 直接記述した場合には問題ないため、原因はDB取得に関連している可能性があります。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
少し分かりづらかったようなので、補足いたします。 $row =& $rs->fetchAll( MDB2_FETCHMODE_ASSOC ); こちらで取得した連想配列$rowを function_hogeにて、連想配列を文字列一つの文字列まで展開し、再起処理にて一つづつ エンコードを掛けているものと思います。 それの一レコード分ずつを連結させてしまって、detect_encodingしてやれば誤検出が減るのではないかという 意見となります。 <?php //取得した$rowが下記のようなものと仮定する $row = array( array('id'=>1, 'busho'=>'法務', 'name'=>'ほげほげ', 'extr'=>'なんとか'), array('id'=>2, 'busho'=>'法務', 'name'=>'ああああ', 'extr'=>'いいいい'), array('id'=>3, 'busho'=>'法務', 'name'=>'うううう', 'extr'=>'ええええ'), array('id'=>4, 'busho'=>'法務', 'name'=>'わわわわ', 'extr'=>'かかかか'), ); //コレの1レコード文の配列を文字列に連結します。 $row_str = implode('', $row[0]); //result: 1法務ほげほげなんとか //連結した文字列をmb_detect_encoding $encoding = mb_detect_encoding($row_str, 'EUC-JP,UTF-8,SJIS' ); ?> ただ、取得してきた一レコード分というものがそれぞれ文字コードがバラバラなのであればどうしようもないですね。
その他の回答 (4)
- hogehoge78
- ベストアンサー率80% (433/539)
何度もごめんなさい。 文字コード検出がもう少し簡単に誤検出率を落とせそうな方法を考えてみました。 <?php function mb_detect_encoding_ex($str, $order='ASCII,JIS,UTF-8,EUC-JP,SJIS', $default=false){ if($default) return mb_detect_encoding($str, $order); //第三引数をtrueにすると通常のmb_detect_encodingをおこなう $enc = mb_detect_encoding($str, $order); if($enc == 'UTF-8'){ $s = "/(?:[\xbc][\xa3-\xe1]|[\xbe][\xa3-\xfe]|[\xc0-\xde][\xa1-\xbf]|[\xdf-\xf3][\xa1-\xfe]|[\xf4][\xa1-\xa6])/"; $str = preg_replace($s, '', $str); if(empty($str)) return mb_internal_encoding(); } return $enc; } ?> 解説しますと、mb_detect_encodingを掛けたときにUTF-8と検出された場合に、前回貼り付けさせていただきましたURLに記載されていた誤検出リストを元に作成した正規表現にてpreg_replaceでその範囲を削除します。 削除した場合に誤検出リストがemptyとなった場合、mb_internal_encodingで検出される文字コードを返します。(個々の部分は、return 'EUC-JP'としてもいいと思います。) ただ、UTF-8の文字のパターンでこの置換を行ってemptyになるパターンがあるかどうかは謎です(マルチバイトだと全角1文字で3バイトなので恐らく大丈夫だと思いますが・・・) 以上です。
お礼
hogehoge78さん こちらこそ、何度も迷惑をかけてしまい申し訳ございません。 そして、本当にありがとうございます。 上記ロジック、最初考慮していたのですが 以下の理由で挫折していました。 ・正規表現が苦手 ※困らない程度で使える程度なので。。 ・共通処理なので、できればロジック修正を最小限にしたい ただ、ご教授いただいたロジック、大変興味深く 検証に問題がでなければ、使わせていただくこともありそうです。 ※現状、即組み込みはちょっと不安が大きいですが。。。 同じく、UTFの3バイトとか不安が少し残りますし くどいかもしれませんが 何度も何度も本当にありがとうございます。
- hogehoge78
- ベストアンサー率80% (433/539)
今回の件、少し気になったのでもう少し検証してみました。 結局のところ、「法務」とあった場合、 法務の後ろに何らかの文字を適当に挿入すると、正常な検出が出来るようなので、 データベースから取得した1レコードを、 $strEncode = mb_detect_encoding(implode('', $row), 'EUC-JP,UTF-8,SJIS'); としてやって、配列を展開する前に、文字コードチェックをするというのでは、どうでしょうか。 mb_detect_encodingを叩くタイミングで文字数が多ければ誤検出率も下がるのではないかと思います。
お礼
hogehoge78さん 何度もご回答ありがとうございます。 ご指摘のとおりなのですが、現在「法務」を「法務部」として対応しております。 ※ただし、これは局所的な対応であり 実際には誤検出され文字化けしている文字が多数あります。 またご教授いただいた手法も考慮していたのですが いかんせん、元の文字コードを判別できないので 付加する文字の文字コードを制御できないんですよね。。 たとえば、元がSJISの文字に対して、EUCの文字を付加するとおかしくなります。 この元の文字コードを判定し、SJISを付加してやれば誤検出の可能性は低くなりますが。。。それができないみたいですし。。。TT こないだの補足にて、出力時は EUC → UTFと書いてありますが なにせ、この処理使われている箇所が膨大なので。。 部分によっては、EUC以外 → UTFの可能性もあります。。。 文字数が多くなれば誤検出も下がるのは仰るとおりなのですが 元の文字コードを判別できないと、付加した文字列に 文字コードが混在する形になってしまいます。 ※現時点では、上記サンプルのように空文字で判定できるのか 未調査で申し訳ないのですが。。。 現時点でも解決策を模索しているので、 ご意見いただけるのは本当にありがたいです。
- hogehoge78
- ベストアンサー率80% (433/539)
mb_detect_encodingの件、少し簡単で且つ乱暴なアドバイスでした。 申し訳ございません。 少し調べてみたところ、下記のサイトを発見いたしました。 http://www-ise3.ist.osaka-u.ac.jp/miura/?PHP%20GET%2FPOST%A5%E1%A5%BD%A5%C3%A5%C9%A4%C7%A4%CE%C6%FC%CB%DC%B8%EC%A4%CE%CA%B8%BB%FA%B2%BD%A4%B1%CB%C9%BB%DF#dde97368 ある特定の文字で、誤検出が発生するという記事です。 ここに書いてある解決方法の項目は、POSTデータの検出に関してなので、使えないとして、もし行うのであれば、 ■取得してきたものがHTMLであった場合 ⇒正規表現等で、METAタグのcharset情報を抜いてくる ■RSSなどXML情報であった場合 ⇒正規表現等で最初のXML宣言のcharsetを抜いてくる などといったところになると思います。
お礼
hogehoge78さん 回答ありがとうございます。 そのページではないですが、同じことが書いてあるページは 結構あって読み漁っていたのですが。。。 やはり無理なんですかね。。。 現状、エンコードするのは共通処理になっているため 変更箇所が膨大で。。。 その後、少し調べてみましたが 「法務」 ご教授いただいたページにも誤検出リストに含まれていましたが echo mb_detect_encoding( "法務", 'UTF-8,EUC-JP,SJIS' ); 簡単にこれだけの記述でソースコードをEUC、UTF-8にするだけで どっちの場合でもUTF-8という判定になってしまいますね。。。 ※この調査はしていませんでした。 ※くどいようですが、ソースコードをEUCにして動かすとUTF-8という判定になり ソースコードをUTF-8にして動かすとUTF-8の検出となる(これは当たり前ですが) 解せないのが、最近になって発生しているってところなんですよね。。。 ※以前から発生していたのであればカットオーバー時から発生しているはずなので もっと早くに(テスト時)などから発見されているはずですが。。。 根本的な対応方法を考えなきゃですね。。。 ※共通処理を見直すなど。。。TT もしくは、DBをUTF-8で作り直してですかね。。。 せっかくいろいろ調べていただいたのに たいした情報、結果をお返しできなく残念です。 申し訳ございません。
- hogehoge78
- ベストアンサー率80% (433/539)
質問者さんの必要としている回答と若干ずれるかもしれませんが、 mb_detect_encodingでの自動検出に関しまして、 所詮は与えられた文字列が「それっぽい」を検出しているだけに過ぎません。 その為、与えられた文字列が少なかった場合(1文字しかないとか)には、 当然誤検出を起こします。 また、MySQLなどのデータベースは、デフォルトの文字コードが定義されています。 mysql_real_escape_string関数といったようなSQLインジェクションを防ぐための関数に関しましては そのデフォルトで定義した(又はset names ...で定義した)文字コードを元にエスケープします。 その為環境によって動的に文字コードを変更しデータベースに保存するような状態というのは 問題があると思います。※mb_detect_encodingで文字コードを判別されているようなので、勝手に仮定しました。 つきまして、スクリプトとデータベースで文字コードが違うのであれば、 INSERTする前に スクリプトの文字コード⇒データベースの文字コード へ変換、 SELECTなどで出力の際に データベースの文字コード⇒スクリプトの文字コード へ変換と、 設定値でも設けて、決め打ちされたほうがよいと思います。
補足
hogehoge78さん 回答ありがとうございます。 仰るとおりですが、処理は基本的にエンコードを必ず行っております。 1.データ登録時に、UTF-8 → EUC 2.データ出力時に、EUC → UTF-8 基本はこの2つです。 上記以外の処理にて、HTTP通信でWEB上のデータを拾ってくる場合があるので 登録時のエンコード元がUTF-8で固定というわけではないのですが。。 このため、EUCに変換するべくmb_detect_encodingで毎回エンコードを調べて UTF-8に変換という処理としています。 > 所詮は与えられた文字列が「それっぽい」を検出しているだけに過ぎません。 こちら、そうなんですよね。。。 もっとちゃんと判別できる方法ってないのでしょうか。。。
お礼
hogehoge78さん 何度も何度もありがとうございます。 そして。。。この考え方 ちょっとびっくりしました! 思いつかなかったですね。。。 配列の場合、かなりの確立で誤検出をなくせそうですね! 前回のご回答いただいた内容をちゃんと理解していなかったです。 すみません 問題は、配列じゃなかったときですが。。。 でも、現状のロジック的には ブラウザからはUTFでわたってくるし問題ないかもです! ※まぁ、いたずらされたらとかセキュリティ的な面もありますが そこはいったんスルーで。。。 これなら、回避できながら最小限の修正でいけるかも。 ちょっと組み込んでみます!