文字化け対処方法について - PHPプロ!Q&A掲示板

371

  • 500P

文字化け対処方法について

質問日時 / 2007年2月20日 16:22    回答数 / 19件

Questioner:  hachiya  このエントリーをはてなブックマークに追加 

キーワード / 文字化け    EUC-JP    Eclipse   

初めてご質問させていただきます。

現在、FORM送信→送信内容を.datに書込→書込内容をブラウザに表示
といった具合の簡単なテストプログラムを作成しております。
困ったことに、ブラウザ上に取得した文字を表示させると文字化けしてしまい、
いろいろ試しましたが解決策はみつからず、わかる方にご教授願おうと投稿
いたしました。

クライアントOS:Windows XP
開発環境:PHPEclipse
FTPソフト:FFFTP
サーバーOS:Fedora5
WEBサーバー:Apache2
PHPバージョン:5.2.0

php.iniのmbstringは下記の設定になっています。
mbstring.detect_order auto
mbstring.encoding_translation On
mbstring.func_overload 0
mbstring.http_input auto
mbstring.http_output EUC-JP
mbstring.internal_encoding EUC-JP
mbstring.language Japanese
mbstring.strict_detection Off
mbstring.substitute_character no value

作成プログラムは下記の通りです
encoding.php
  1. <html lang="ja">
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
  4. <title>エンコーディングテスト</title>
  5. </head>
  6. <body>
  7. <form method="POST">
  8. <input type="text" name="enctest" />
  9. <input type="submit" value="送信" />
  10. </form>
  11. <?php
  12.  include("include/inctest.php");
  13.  $encdata = $_POST['enctest'];
  14.  if($encdata != NULL){
  15.   encadd($encdata);
  16.  }
  17.  
  18.  $csvfile = fopen("doc/sample.dat""r");
  19.  $csvdata = fgetcsv($csvfile1000);
  20.  if($csvdata != NULL){
  21.   encshow($csvdata);
  22.   fclose($csvfile);
  23.  }
  24. ?>
  25. </body>
  26. </html>

include.php
  1. <?php
  2.  function encadd($data){
  3.   $datfile = fopen("doc/sample.dat""w");
  4.   flock($datfileLOCK_EX);
  5.   $data = mb_convert_encoding($data"Shift_JIS""EUC-JP");
  6.   if($data != NULL){
  7.    fputs($datfile$data."\n");
  8.   }else{
  9.    return false;
  10.   }
  11.     
  12.   flock($datfileLOCK_UN);
  13.   fclose($datfile);
  14.     
  15.   return;
  16.  }
  17.   
  18.  function encshow($data){
  19.   $enc_data = $data[0];
  20.   $enc_data = mb_convert_encoding($enc_data"EUC-JP""Shift_JIS");
  21.   echo "<table border='1'>";
  22.   echo "<tr>";
  23.   echo "<td>".$enc_data."</td>";
  24.   echo "</tr>";
  25.   echo "</table>";
  26.     
  27.   return;
  28.  }
  29. ?>

これで、例えばフォームに「サンプルテスト」と入力し送信すると
「Yプルテスト」と表示されてしまいます。
「漢字」と送信すると今度は何も表示されません。
http://www.shapers-style.com/phplesson/encodintest.php
で実際のページが見れます。

これをローカルで実行すると送信した内容はちゃんと表示されるのですが・・・
自宅サーバーを経由し.datファイルからデータを取得すると文字化けしてしまいます。

この2日間、まったく先へ進めません。
どなたかよろしくお願いいたします。

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。



ツリー一覧

┣A01hanamimb_detect_encodingで、POSTされたデータのエンコード
┃┗A01-1hachiyaご回答ありがとうございます。 mb_detect_encodingで
┣A02weekendphpmbstringの設定で、http_inputがautoかつ、encoding_t
┃┗A02-1hachiyaご回答ありがとうございます。 ご指摘の通りにサー
┃ ┗A02-1-1weekendphphttp://www.shapers-style.com/phplesson/doc/sample.
┃  ┗A02-1-1-1hachiyaweekendphp様、ご確認ありがとうございます。 確か
┣A03dala00>>CODE function encshow($data){ print_r( $da
┃┗A03-1hachiya少し外出していたためレスが遅れました。 すいません
┃ ┗A03-1-1hachiya先ほどprint_rを指定して表示させたところ Array (
┃  ┗A03-1-1-1dala00>$data[0]は配列です。 >意図的にこのようにしている
┃   ┗A03-1-1-1-1hachiyadala00様、ご回答ありがとうございます。 仕事でこの
┣A04signalfgetcsv はバイナリセーフとなっていますが、 日本語
┃┗A04-1hachiyasignal様、ご回答ありがとうございます! signal様
┃ ┗A04-1-1signalnaritasan さんの書かれている通り fgetcsv はロケー
┃  ┗A04-1-1-1hachiyasignal様、的確なアドバイス及び、解決策をお教えいた
┃   ┗A04-1-1-1-1yossy解決されたようですが、私も以前まったく同じ現象で悩
┗A05pascalmb_convert_encoding の引数って、「Shift_JIS」では
 ┗A05-1hachiyapascal様、ご回答ありがとうございます。 何度か「
  ┗A05-1-1naritasanすでに解決されたっぽのですが、fgetcsvのマニュアル
   ┗A05-1-1-1QWWER741この意見は管理者によって削除されました。

回答一覧

並び替え:

A01
answererhanami [2月20日 16:44]

mb_detect_encodingで、POSTされたデータのエンコードをチェックしましたか?

余計なおせっかいになってしまうかもしれませんが、
CSVに書き込んだものを再度読み込んで、
ブラウザで、表示させるより、
POSTの値を、ブラウザに表示させたほうが、
処理として、きれいではないのでしょうか?

この意見に回答する

ツリーへ TOPへ

A01-1
replyerhachiya [2月20日 16:55]

ご回答ありがとうございます。
mb_detect_encodingでの確認はできております。
http://www.shapers-style.com/phplesson/encodintest.php

>CSVに書き込んだものを再度読み込んで、
>ブラウザで、表示させるより、
>POSTの値を、ブラウザに表示させたほうが、
>処理として、きれいではないのでしょうか?

現在、ショッピングカートを作成しておりまして、
商品データを.datに書き出し、商品一覧ページでその内容を
表示するといった処理をさせておりますので、書き出し処理、
読み込み処理は必要になってきます。

ですが、文字化け対処ができずにいたので、一度小さいプログラムで
問題を解決してから、元の作成に戻ろうと思った次第です。

説明不足で申し訳ございません。

この意見に回答する

ツリーへ TOPへ

A02
answererweekendphp [2月20日 16:55] (最終編集:2月20日 16:59)

mbstringの設定で、http_inputがautoかつ、encoding_translationがOnの場合、
文字化けの可能性があるようです。

http_inputをpassにするか、encoding_translationをOffにするかの
何れかを一度試してみてください。

特にautoの場合は、判定の優先順がASCIIからになっているので、
正しく判定されない場合が多いようです。

この意見に回答する

ツリーへ TOPへ

A02-1
replyerhachiya [2月20日 17:15]

ご回答ありがとうございます。

ご指摘の通りにサーバー側のphp.iniを

http_input → pass
encoding_translation → On

http_input → auto
encoding_translation → Off

http_input → pass
encoding_translation → Off

の3回に分けて実行してみましたが、結果は同じでした。

Fedoraサーバー側に問題があるんでしょうか?
書籍等を読んでいて、このエンコーディングについては
すんなりいくと思ったのですが、
ここまで長引くとは思っていませんでした。。。

この意見に回答する

ツリーへ TOPへ

A02-1-1
replyerweekendphp [2月20日 17:37] (最終編集:2月20日 17:42)

http://www.shapers-style.com/phplesson/doc/sample.dat
を開くと、「漢字」「サンプルテスト」の両方とも、
問題なくSJISで保存できているようでした。

すると、SJISからEUCへの変換がうまくいっていないと思われますが。。。


ずばりいえなくてすみません。

この意見に回答する

ツリーへ TOPへ

A02-1-1-1
replyerhachiya [2月20日 17:56]

weekendphp様、ご確認ありがとうございます。

確かに、datファイルへの書き込み(SJISでの)は問題ないようでした。
変換に問題があるのでは?との指摘ですが、
単純にmb_convert_encoding($enc_data, "EUC-JP", "Shift_JIS");
と記述しただけではEUC-JPに変換されないのでしょうか?
どの書籍を見てもこれで問題なさそうに書かれております。

ちなみにローカルホストでの表示では、
「漢字」と入力すると
EUC-JP テキスト追加前
SJIS コンバート前
EUC-JP コンバート後
表示部分 「漢字」

と、ちゃんと表示できているんですが・・・

サーバー経由だと
EUC-JP テキスト追加前
ASCII コンバート前
ASCII コンバート後 
表示部分 「空」

になってしまうんですよね。

やはり、datファイルからの読み込み時に問題があるとしか考えられませんが、
解決方法がまったくわからない状態です。

よろしくお願いいたします。

この意見に回答する

ツリーへ TOPへ

A03
answererdala00 [2月20日 23:03]

  1. function encshow($data){ 
  2.   print_r( $data );
  3.   $enc_data = $data[0]; 
  4.   print_r( $enc_data );
  5.   $enc_data = mb_convert_encoding($enc_data, "EUC-JP", "Shift_JIS"); 
  6.   print_r( $enc_data );
  7.   echo "<table border='1'>"; 
  8.   echo "<tr>"; 
  9.   echo "<td>".$enc_data."</td>"; 
  10.   echo "</tr>"; 
  11.   echo "</table>"; 
  12.      
  13.   return; 
  14.  }

のようにprint_rを入れて試しましたか?
個人的には$data[0]って配列のような気がするのですが、
そんなことはないですか?

この意見に回答する

ツリーへ TOPへ

A03-1
replyerhachiya [2月20日 23:45]

少し外出していたためレスが遅れました。
すいません。
print_rは試していません。
すぐ実行してみます。

$data[0]は配列です。
意図的にこのようにしているのですが、
今作っているプログラムは、各フォームデータをカンマ区切りで
datファイルに収め、呼び出す際にカンマ区切りデータを
配列に収めるといった流れです。

ですので、こちらの簡単なプログラムも同じ流れに沿って
作ろうと思いました。

この意見に回答する

ツリーへ TOPへ

A03-1-1
replyerhachiya [2月20日 23:51]

先ほどprint_rを指定して表示させたところ

Array ( [0] => T???v???e?X?g ) T???v???e?X?gTンプルテスト
表示部分 → Tンプルテスト

となっていました。

この意見に回答する

ツリーへ TOPへ

A03-1-1-1
replyerdala00 [2月21日 11:21]

>$data[0]は配列です。
>意図的にこのようにしているのですが、
>今作っているプログラムは、各フォームデータをカンマ区切りで
>datファイルに収め、呼び出す際にカンマ区切りデータを
>配列に収めるといった流れです。

$data[0]が配列表記、という意味ではなく、
$data[0]自体が配列という意味です。
CSV$dataは配列の配列ですよね?
なのでmb_convert_encodingしている
$enc_dataも配列ではないでしょうか?
(間違いならすみません)
一カ所でなく至る所にprint_rを入れて試して下さい。


あと、fgetcsvは自動的に文字を分割したりするので、
システムのロケールと文字コードが違うと
正しく動かなかったりします。
mb_internal_encodingを試してみたり、
保存時に現在のロケールに合わせて保存したり
する必要があると思います。

この意見に回答する

ツリーへ TOPへ

A03-1-1-1-1
replyerhachiya [2月22日 00:56]

dala00様、ご回答ありがとうございます。
仕事でこの時間にレスとなってしまいました。
申し訳ございません。

$data[0]は配列の中の[0]番目の値ということです。

fgetcsvでデータを取得しているので、
値は配列に格納されると思ったので。。。
実際、POSTされるデータは1つだけなのですが、
現在作成しようとしているプログラムは複数のフォームデータを
扱うので、あえて上記のようなロジックを書いています。

アドバイスいただいと事を少し試してみたいと思いますので、
また結果をご報告します。

よろしくお願いします。

この意見に回答する

ツリーへ TOPへ

A04 参考になった
answerersignal [2月21日 14:08]

fgetcsv はバイナリセーフとなっていますが、
日本語を含む CSV のパースは自分で行ったほうが無難です。

  1. $csvdata = fgetcsv($csvfile, 1000);

  1. $csvdata = explode(',', trim(fgets($csvfile, 1000)));
に置き換えてみてください。

この意見に回答する

ツリーへ TOPへ

A04-1
replyerhachiya [2月22日 01:16]

signal様、ご回答ありがとうございます!

signal様のご指摘通り変更してみたところ
見事変換ができるようになりました!

そこで、私自身も再度内容を理解しようと思いますが、
なぜ「日本語を含む CSV のパースは自分で行ったほうが無難」なのか
お時間があればご教授願いたいのですが。。。

よろしくお願いします。

この意見に回答する

ツリーへ TOPへ

A04-1-1 満足
replyersignal [2月22日 10:49]

naritasan さんの書かれている通り fgetcsv はロケール設定を考慮するようです。

が、ロケール設定を考慮するとのことなので・・・

  1. setlocale(LC_ALL, 'ja_JP');
を fgetcsv を利用する前に呼べば問題なく動くようになります。


> なぜ「日本語を含む CSV のパースは自分で行ったほうが無難」なのか
それ以外の解決策を知らなかったためです・・・未熟者でスミマセン・・・

この意見に回答する

ツリーへ TOPへ

A04-1-1-1
replyerhachiya [2月22日 20:30]

signal様、的確なアドバイス及び、解決策をお教えいただき
大変ありがとうございました!
ここからは自分でいろいろと理解し、自分もアドバイスできる
立場に立てるよう頑張ってみます!

hanami様、weekendphp様、dala00様、pascal様、naritasan様
ありがとうございました!

またわからないことがでてきたらご質問させていただくかも
しれませんが、その時はよろしくお願い致します。

この意見に回答する

ツリーへ TOPへ

A04-1-1-1-1
replyeryossy [3月15日 23:05]

解決されたようですが、私も以前まったく同じ現象で悩んだ経験があります。。。
最終的な回避策は上記同様の方法(自分で文字列をパース)となりました。
ただ、explodeでの文字列分割だとダブルクオートで囲われた文字列にカンマが含まれた場合や
改行を含む文字列の場合に正しくパースできなくなってしまう可能性があります。
なのでRFC4180(CSV形式のRFC)に準拠したCSVファイルをパースする関数を作りました。
ご参考程度にどうぞ。使い方は既存のfgetcsv関数と同様です。

  1. function fgetcsv_reg (&$handle, $length = null, $d = ',', $e = '"') {
  2.     $d = preg_quote($d);
  3.     $e = preg_quote($e);
  4.     $_line = "";
  5.     while ($eof != true) {
  6.         $_line .= (empty($length) ? fgets($handle) : fgets($handle, $length));
  7.         $itemcnt = preg_match_all('/'.$e.'/', $_line, $dummy);
  8.         if ($itemcnt % 2 == 0) $eof = true;
  9.     }
  10.     $_csv_line = preg_replace('/(?:\\r\\n|[\\r\\n])?$/', $d, trim($_line));
  11.     $_csv_pattern = '/('.$e.'[^'.$e.']*(?:'.$e.$e.'[^'.$e.']*)*'.$e.'|[^'.$d.']*)'.$d.'/';
  12.     preg_match_all($_csv_pattern, $_csv_line, $_csv_matches);
  13.     $_csv_data = $_csv_matches[1];
  14.     for($_csv_i=0;$_csv_i<count($_csv_data);$_csv_i++){
  15.         $_csv_data[$_csv_i]=preg_replace('/^'.$e.'(.*)'.$e.'$/s','$1',$_csv_data[$_csv_i]);
  16.         $_csv_data[$_csv_i]=str_replace($e.$e, $e, $_csv_data[$_csv_i]);
  17.     }
  18.     return empty($_line) ? false : $_csv_data;
  19. }

この意見に回答する

ツリーへ TOPへ

A05
answererpascal [2月21日 17:29]

mb_convert_encoding の引数って、「Shift_JIS」ではなく「SJIS」ではないですか?
手元の環境(PHP4系)で試したところ、「Shift_JIS」でも変換できているようでしたが・・・

とりあえずprint_rの結果から、CSVファイルを読み込んだ後のEUC-JPへの変換がうまく機能していないようですね。


ちょっと実験してみました。
 「サンプルテスト」と入力 → 「Tンプルテスト」と表示
 「シンプルテスト」と入力 → 「Vンプルテスト」と表示
 「トンプルテスト」と入力 →「gンプルテスト」と表示
 「aサンプルテスト」と入力 →「aサンプルテスト」と表示

「サ」のShift_JISでの文字コードは「8354」です。
そして「T」の文字コードは「54」です。
「シ」は「8356」、「V」は「56」。
「ト」は「8367」、「g」は「67」。

以上の結果から、1文字目が全角文字の場合、EUC-JPに変換する際に1バイト目が無視されているのではないかと思われます。
これが「Shift_JIS」と指定した事によるものかどうかはわかりませんが。

この意見に回答する

ツリーへ TOPへ

A05-1
replyerhachiya [2月22日 01:01]

pascal様、ご回答ありがとうございます。

何度か「Shift_JIS」を「SJIS」に変えてみたりしたのですが、
結果は同じでした。

>以上の結果から、1文字目が全角文字の場合、
>EUC-JPに変換する際に1バイト目が無視されているのではないかと思われます。

私もそんな予感はしていたのですが、
なぜ1文字目だけが文字化けしているのか解決策が見つからず・・・

また、最初に「漢字」や「改行」などと入力すると
まったく何も表示されず、mb_detect_encodingでチェックしてみると
ASCIIになっていたりと、どんどんドツボにはまっている感じでした。

もう少しいろいろ試してみます。

またアドバイスよろしくお願いします。

この意見に回答する

ツリーへ TOPへ

A05-1-1 満足
replyernaritasan [2月22日 09:44]

すでに解決されたっぽのですが、fgetcsvのマニュアルを参照してみてください。

  1. 注意:  この関数はロケール設定を考慮します。もし LANG  が例えば en_US.UTF-8 の場合、 ファイル中の 1 バイトエンコーディングは間違って読み込まれます。

とあります。

この意見に回答する

ツリーへ TOPへ

A05-1-1-1
replyerQWWER741 [2月22日 14:40]

この意見は管理者によって削除されました。

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
ログファイルの中の空のデータ行を削除したい
 このエントリーをはてなブックマークに追加 
A
ログのデータ個数(列数)が固定で、空のログが"<><><>"だと既知であれば if ($line === "<><><>") { continue; } で読み飛ばしてもいいのでは? ...

>>続きを読む

まずは配列や文字列の扱いから、じっくり勉強して行きましょう。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)