なんか勘違いしてるのかなぁ~?
fgetcsvを使って、こんなphpスクリプトを書いてみました。
% cat csvtest.php
<?php
$fp = fopen("csvtest.csv","r");
while( FALSE != ($data=fgetcsv($fp)) ) {
echo "data=";
print_r($data);
}
?>
読み込むCSVファイルcsvtest.csvはこんな内容。
% cat csvtest.csv
1,2,3,"あいうえお",4,5,6
2,3,"あいうえお",4,5,6,1
3,"あいうえお",4,5,6,1,2
文字コードは、日本語EUCにしてあります。
% hd csvtest.csv
00000000 31 2c 32 2c 33 2c 22 a4 a2 a4 a4 a4 a6 a4 a8 a4 |1,2,3,"あいうえ・
00000010 aa 22 2c 34 2c 35 2c 36 0a 32 2c 33 2c 22 a4 a2 |・,4,5,6.2,3,"あ|
00000020 a4 a4 a4 a6 a4 a8 a4 aa 22 2c 34 2c 35 2c 36 2c |いうえお",4,5,6,|
00000030 31 0a 33 2c 22 a4 a2 a4 a4 a4 a6 a4 a8 a4 aa 22 |1.3,"あいうえお"|
00000040 2c 34 2c 35 2c 36 2c 31 2c 32 0a |,4,5,6,1,2.|
0000004b
phpの関数fgetcsvは、CSVファイルを読み出して、フィールドごとに分解してくれるのですが、マニュアルによれば
http://www.php.net/manual/ja/function.fgetcsv.php
注意: この関数はロケール設定を考慮します。
ということになっています。
localeをCにして実行してみると
% env LC_CTYPE=C php csvtest.php
data=Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => あいうえお
[4] => 4
[5] => 5
[6] => 6
)
data=Array
(
[0] => 2
[1] => 3
[2] => あいうえお
[3] => 4
[4] => 5
[5] => 6
[6] => 1
)
data=Array
(
[0] => 3
[1] => あいうえお
[2] => 4
[3] => 5
[4] => 6
[5] => 1
[6] => 2
)
これは、まあそういうこともあるかな、という結果。
ところが、localeを、日本語EUCのja_JP.eucJPにすると
% env LC_CTYPE=ja_JP.eucJP php csvtest.php
data=Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => あいうえお",4,5,6
2,3,あいうえお"
[4] => 4
[5] => 5
[6] => 6
[7] => 1
)
data=Array
(
[0] => 3
[1] => あいうえお",4,5,6,1,2)
ダブルクォート「"」を見失って、「迷走」してます。どうして?
最初、ja_JP.EUC-JPにしたら
% env LC_CTYPE=ja_JP.EUC-JP php csvtest.php
data=Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => あいうえお
[4] => 4
[5] => 5
[6] => 6
)
~以下略~
となって、意図どおり動いているように見えたんで、locale名が間違ってるのか、と思ったんですが、どうもこちらは、ja_JP.EUC-JPなんていうlocaleは存在しないので、C相当の動作になっている、ってことらしいです。
☆
さて、エンコードをUTF-8にしてみると
% mv csvtest.csv csvtest.csv.org
% iconv -f EUC-JP -t UTF-8 csvtest.csv.org > csvtest.csv% env LC_CTYPE=ja_JP.UTF-8 php csvtest.php | iconv -f UTF-8 -t EUC-JP
data=Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => あいうえお
[4] => 4
[5] => 5
[6] => 6
)
data=Array
(
[0] => 2
[1] => 3
[2] => あいうえお
[3] => 4
[4] => 5
[5] => 6
[6] => 1
)
data=Array
(
[0] => 3
[1] => あいうえお
[2] => 4
[3] => 5
[4] => 6
[5] => 1
[6] => 2
)
ということで、UTF-8なら大丈夫っぽい。
ちなみに
% env LANG=ja_JP.UTF-8 date | iconv -f UTF-8 -t EUC-JP
2009年 2月23日 月曜日 22時30分10秒 JST
なので、ja_JP.UTF-8というlocale名は正しいと思う。
☆
デフォルト設定では、こんな感じになってるんですが、何か関係あるのでしょうかね。よくわかってないままphpを使っていたりするのが悪いのかも。
% php -i | grep -i encoding
iconv.input_encoding => ISO-8859-1 => ISO-8859-1
iconv.internal_encoding => ISO-8859-1 => ISO-8859-1
iconv.output_encoding => ISO-8859-1 => ISO-8859-1
mbstring.encoding_translation => Off => Off
mbstring.internal_encoding => no value => no value
mbstring.script_encoding => no value => no value
SQLite Encoding => UTF-8
☆
わかんないことがあればソースコードを見ろ!ってことで、cd /usr/ports/lang/php5/; make patchして、grepでそれらしい場所を推測して、眺めてみました。オープンソースって便利だね。FreeBSDって便利だね。
mblenとかいう、マルチバイトを考慮して文字列長を調べるのかな?って感じの関数が使われていましたが、よくわかんなかったです。