2007年5月24日木曜日

 

fgetcsv関数を使用した場合の文字化けについて

array fgetcsv ( resource handle,int length [, string delimiter [, string enclosure]])
ExcelCSVファイルから一行ずつ取得し、CSVフィールドを処理する関数。
第一引数:ファイルポインタ、第二引数:フィールドの最大長、第三引数:フィールドの区切り文字、第四引数、フィールドの囲い文字

PHPfgetcsv関数を使ったプログラムを書いていたらCSVファイルの日本語が化けた。
半角文字が先頭にあれば文字が壊れずに正しく表示されるが、実用的でないので調べた。

fgetcsv()関数について

~略~
ここでまず重要なのは最後の「enclosure と delimiter はそれぞれ1文字に限られており、もし1文字を超える文字列が指定された場合は、 最初の文字だけが使われます。」という一文。
~略~
「\t」を「\」と「t」の二文字として判断したりはしません。
次に、「enclosure (フィールド囲い子) パラメータは、別の文字を4番目のパラメータで 指定しない限り、デフォルトではダブルクォーテーショーンマークとなります。」という一文。
私はマニュアルを良く読まずに「enclosureを指定しなければ、フィールドの囲い子は「ない」として扱われると思いこんでいたため(そしてうちのサーバーではそれで問題なく動いてしまっていた)、そのスクリプトを他所様のサーバーで動かすと大量に文字化けが発生してしまいました。
この件の場合、fgetcsv()を使っている箇所は何も弄らずに、データ自体の各フィールドをダブルクォーテーションで括るようにしたところ、無事に意図通りの挙動をするようになりました。

挙動が怪しく、省略可能な区切り文字と囲み文字にもきちんとカンマ(,)ダブルクォーテーション(")を指定した方が良いということ。
文字化けが直らない場合はさらに以下。

文字化け対処方法について
setlocale(LC_ALL, 'ja_JP');

fgetcsv関数を実行する前に上のコードを追加する。すると大分改善されます。
それでも一部文字化けは残りました。fgetcsv関数はに依存する様です。
皆、ぶつかる事らしく以下の解答がありました。

[Re:Re:Re:Re:Re:文字化け対処方法について]

RFC4180(CSV形式のRFC)に準拠したCSVファイルをパースする関数を作りました。 ご参考程度にどうぞ。使い方は既存のfgetcsv関数と同様です。

yossy [3月15日 23:05]

CSVファイルに日本語を使っても文字化けしない関数 fgetcsv_reg
これで解消されました。


 function fgetcsv_reg (&$handle, $length = null, $d = ',', $e = '"') {
   $d = preg_quote($d);
   $e = preg_quote($e);
   $_line = "";
   while ($eof != true) {
      $_line .= (empty($length) ? fgets($handle) : fgets($handle, $length));
      $itemcnt = preg_match_all('/'.$e.'/', $_line, $dummy);
      if ($itemcnt % 2 == 0) $eof = true;
  }
  $_csv_line = preg_replace('/(?:\\r\\n|[\\r\\n])?$/', $d, trim($_line));
  $_csv_pattern = '/('.$e.'[^'.$e.']*(?:'.$e.$e.'[^'.$e.']*)*'.$e.'|[^'.$d.']*)'.$d.'/';
  preg_match_all($_csv_pattern, $_csv_line, $_csv_matches);
  $_csv_data = $_csv_matches[1];
  for($_csv_i=0; $_csv_i<count($_csv_data); $_csv_i++) {
     $_csv_data[$_csv_i] = preg_replace('/^'.$e.'(.*)'.$e.'$/s','$1',$_csv_data[$_csv_i]);
      $_csv_data[$_csv_i] = str_replace($e.$e, $e, $_csv_data[$_csv_i]);
  }
  return empty($_line) ? false : $_csv_data;
}

関連記事

PHPでCSVファイルを読み込み[2007年4月3日]

参考

amethyst-web.org
http://www.amethyst-web.org/
PHPプロ!Q&A掲示板
http://www.phppro.jp/
追記:2010年2月9日
CSV_Iterator - Openpear
CSVファイル(ref:RFC4180)をイテレートするためのクラスです。 外国産の同様のクラスでは、fgetcsvを利用しているため文字エンコード周りで不具合があるのでその点を考慮したものを目指しています。 UTF-16でエンコードされたファイルにも対応しています。

ラベル: ,


コメント: コメントを投稿

登録 コメントの投稿 [Atom]



この投稿へのリンク:

リンクを作成



<< ホーム

This page is powered by Blogger. Isn't yours?

登録 投稿 [Atom]

Google