PHPでShiftJISのCSVファイルをfgetcsvで読み込むと先頭1文字が文字化けする

随分と長ったらしいタイトルですが、下記のような環境でShiftJISのCSVファイルをfgetcsv関数で読み込むと1文字目が文字化けするという現象に遭遇しました。最初は文字コードがらみの問題かと考えたのですが、先頭1文字だけ文字化けしている様子からカンマ区切りがうまくいっていない、つまりfgetcsv関数の問題ではないかと想像しました。
(もしかするとクライアントの環境も関係しているかもしれません。というのも、問題となるファイルをWindowsXP Home 32bitから読み込ませたところ、文字化けを再現することができませんでした。)

  • Windows XP Professional
  • Apache 2.2.20
  • PHP 5.3.5
  • クライアントはWindows7 HomePremium 32bit

検索して見つかったのはこちらPHP5 の fgetcsv() で読み込み内容が腐る現象
要約すると、fgetcsvで読み込む前に文字コードをShift-JISからUTF-8にしましょうというもの。
この方法は自分も思いつきましたが、レスポンスが少々悪いので尻込みしていました。

さらに検索を進めると、同じような現象に悩んでる方が他にもいらっしゃいました。
PHPでSJISなCSVファイルを読み込もうとして文字化け
この方も散々悩まれたようで、種々さまざまな解決方法を探された様子です。
この記事の中で最終的にチョイスされているsetlocaleによる解決方法を私も実践してみました。

fgetcsv関数を文字化け対応 setlocaleの文字コード指定
この修正を適用して、クライアントに様子を見てもらうことにします。

2012/08/16追記
setlocaleにて対応したのですが、解決しませんでした。
さらなる解決法を探したところ、下記のページが参考になりました。
PHP5でfgetcsvが正常に動作しない
[php]/**
* ファイルポインタから行を取得し、CSVフィールドを処理する
* @param resource handle
* @param int length
* @param string delimiter
* @param string enclosure
* @return ファイルの終端に達した場合を含み、エラー時にFALSEを返します。
*/
function fgetcsv_reg (&$handle, $length = null, $d = ‘,’, $e = ‘"’) {
$d = preg_quote($d);
$e = preg_quote($e);
$_line = "";
while (($eof != true)and(!feof($handle))) {
$_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]

このfgetcsv_reg関数をPHP5のfgetcsvに置き換えてやったところ、今度はうまくいきました。

スポンサーリンク
レクタングル大