CSVファイル読み込み方法(fgetcsv)

CSVデータを読み込む方法を紹介します。CSVデータを読み込む際、文字コードに注意が必要です。ここでは、PHPの内部エンコーディングとCSVデータの文字コードが「一致する場合」と「一致しない場合」の読み込み例を紹介します。

目次

検証パターン

パターンPHP内部エンコーディング外部ファイル
1UTF-8UTF-8
2UTF-8SJIS

ここでは、次のデータを読み込みます。

文字列A,文字列B,文字列C,日付,時刻
あああああ,佐藤,apple,2015/8/21,22:55
いいいいい,鈴木,orange,2015/9/11,11:25
ううううう,高橋,melon,2015/8/17,8:05

CSVデータ読み込み
文字コードが「一致する場合」

PHPの内部エンコーディングとCSVデータの文字コードが「一致する場合」の読み込み例を紹介します。

<?php
 
header("Content-Type: text/html; charset=UTF-8");
 
$filepath = __DIR__ . "/test_utf8.csv";
 
// 読み込みモードでファイルポインタを取得
if (($handle = fopen($filepath, "r")) !== FALSE) {
    // ファイルポインタから行を取得
    while (($line = fgetcsv($handle, 1000, ",")) !== FALSE) {
        $records[] = $line;
    }
    fclose($handle);
}
var_dump($records);
array (size=4)
  0 => 
    array (size=5)
      0 => string '文字列A' (length=10)
      1 => string '文字列B' (length=10)
      2 => string '文字列C' (length=10)
      3 => string '日付' (length=6)
      4 => string '時刻' (length=6)
  1 => 
    array (size=5)
      0 => string 'あああああ' (length=15)
      1 => string '佐藤' (length=6)
      2 => string 'apple' (length=5)
      3 => string '2015/8/21' (length=9)
      4 => string '22:55' (length=5)
  2 => 
    array (size=5)
      0 => string 'いいいいい' (length=15)
      1 => string '鈴木' (length=6)
      2 => string 'orange' (length=6)
      3 => string '2015/9/11' (length=9)
      4 => string '11:25' (length=5)
  3 => 
    array (size=5)
      0 => string 'ううううう' (length=15)
      1 => string '高橋' (length=6)
      2 => string 'melon' (length=5)
      3 => string '2015/8/17' (length=9)
      4 => string '8:05' (length=4)

fgetcsv関数の引数は以下のようになります。

引数概要
第1引数ファイルポインタを指定。
第2引数CSVファイルにある最大行長を指定。
指定しないと最大行長の制限はないが遅くなる。
第3引数区切り文字を指定。(デフォルト「,」)
第4引数囲み文字を指定。(デフォルト「”」)

CSVデータ読み込み
文字コードが「一致しない場合」

PHPの内部エンコーディングとCSVデータの文字コードが「一致しない場合」の読み込み例を紹介します。パターン1のソースでSJISのCSVデータを読み込むと次のようにマルチバイト文字が文字化けします。

array (size=4)
  0 => 
    array (size=5)
      0 => string '������A' (length=7)
      1 => string '������B' (length=7)
      2 => string '������C' (length=7)
      3 => string '���t' (length=4)
      4 => string '����' (length=4)
  1 => 
    array (size=5)
      0 => string '����������' (length=10)
      1 => string '����' (length=4)
      2 => string 'apple' (length=5)
      3 => string '2015/8/21' (length=9)
      4 => string '22:55' (length=5)
  2 => 
    array (size=5)
      0 => string '����������' (length=10)
      1 => string '����' (length=4)
      2 => string 'orange' (length=6)
      3 => string '2015/9/11' (length=9)
      4 => string '11:25' (length=5)
  3 => 
    array (size=5)
      0 => string '����������' (length=10)
      1 => string '����' (length=4)
      2 => string 'melon' (length=5)
      3 => string '2015/8/17' (length=9)
      4 => string '8:05' (length=4)

そこで次のようにmb_convert_encodingで文字コードを変換してから読み込んでいきます。

<?php
 
header("Content-Type: text/html; charset=UTF-8");
 
$filepath = __DIR__ . "/test_sjis.csv";
 
// mb_convert_encodingでCSVから取得した文字列をsjisからutf-8に変換
$buf = mb_convert_encoding(file_get_contents($filepath), "utf-8", "sjis");

// tmpfile関数で一時ファイルを作成
$handle = tmpfile();

// $bufの内容を $handleが指しているファイル・ストリームに書き込む
fwrite($handle, $buf);

// $handleのファイル位置指示子を、ファイルストリームの先頭にセット
rewind($handle);
 
while (($line = fgetcsv($handle, 1000, ",")) !== FALSE) {
    $records[] = $line;
}
fclose($handle);
var_dump($records);

これで、パターン1と同じ結果になります。

よかったらシェアしてね!
目次