CSVファイルの読み込み | PHPでのデータ操作の複数の手段

CSV(Comma-Separated Values)フォーマットは、データの保存や共有に広く使用され、特にデータのインポートやエクスポートにおいて多く使われます。

PHPは、このようなCSVファイルを読み込み、データを効果的に操作するための豊富なツールと機能を提供しています。

本記事では、PHPを使用してCSVファイルを読み込む複数の手段をサンプルコードを交えつつ紹介していきます。

データの取り込みからクリーニング、データベースへの保存まで、CSVファイルの処理に関連するさまざまな処理の実装をするために必要になります。

PHPの力を借りて、CSVデータの効果的な管理と活用方法を学んでいきましょう。

explode() による文字列の分割

まずはexplode関数を使用したcsvの読み込み方法です。

<?php

$delimiter = ',';
$csv = file_get_contents('./sample.csv');  
/**
(↓csvの中身)
one,two,three
1,2,3
*/

foreach (explode("\n", $csv) as $line) {
  $data = explode($delimiter, $line);
  var_dump($data);
}

/*
array(3) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
  [2]=>
  string(5) "three"
}
array(3) {
  [0]=>
  string(1) "1"
  [1]=>
  string(1) "2"
  [2]=>
  string(1) "3"
}
*/

csvはカンマを使用しているだけの文字列なので、一番簡単なのは explode関数を使用して改行コード(\n)によって分割、行毎にforeachで回してカンマで再度分割する方法です。

しかしこの方法には問題があります。

<?php

// 正常にデータ整形が出来ないパターン、csvのエスケープ処理に対応できないパターン
// "2,3"となっているのと 4と5の間にセル内改行が存在する

$delimiter = ',';
$csv = file_get_contents('./sample.csv');  
/**
(↓csvの中身)
one,two,three
1,"2,3","4
5"
*/

foreach (explode("\n", $csv) as $line) {
  $data = explode($delimiter, $line);
  var_dump($data);
}

/*
array(3) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
  [2]=>
  string(5) "three"
}
array(4) {
  [0]=>
  string(1) "1"
  [1]=>
  string(2) ""2"
  [2]=>
  string(2) "3""
  [3]=>
  string(2) ""4"
}
array(1) {
  [0]=>
  string(2) "5""
}
*/

エクセルなどでデータ内にカンマ(,)や改行(\n)を指定してcsv形式で出力するとエスケープ処理としてダブルクォーテーションに囲われて出力される仕様なのですが、その場合に正常にデータが抜き取れません。

そもそもダブルクォーテーションがデフォルトで添えられた状態で出力されるパターンも存在します。

CSVの規格について言及している記事は以下があります。csvを出力するアプリケーションによってセル内改行が除外されていたり、ダブルクォーテーションが付いていたりと様々あるようです。

参考: https://blog.tech-monex.com/entry/2021/03/26/160000

システム内で作成されたcsvで、あらかじめカンマが入らない事がわかっているのであれば使用しても問題はありませんが、人の手が解する場合にはカンマが入り込む可能性も存在するので対処が必要です。

SplFileObjectクラスを使用してエスケープ処理を回避

<?php

$csv = new SplFileObject('./sample.csv');
/**
(↓csvの中身)
one,two,three
1,"2,3","4
5"
*/
$csv->setFlags(
    \SplFileObject::READ_CSV |
    \SplFileObject::READ_AHEAD |
    \SplFileObject::SKIP_EMPTY |
    \SplFileObject::DROP_NEW_LINE
);

foreach ($csv as $data) {
  var_dump($data);
}

/*
array(3) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
  [2]=>
  string(5) "three"
}
array(3) {
  [0]=>
  string(1) "1"
  [1]=>
  string(3) "2,3"
  [2]=>
  string(2) "45"
}
*/

SplFileObject クラスを使用することでcsvのエスケープ処理を考慮してcsv読み込みを行うことができます。

PHPの組み込み関数である fgetcsv()str_getcsv() 関数もcsvを読み込む上で代表的な関数ですが、セル内改行には対応していません。

そのため、SplFileObjectクラスを使用することでPHPによる柔軟なcsv読み込み処理を実現することが可能になります。

参考: https://www.php.net/manual/ja/class.splfileobject.php

最後に

以上、PHPによるcsv読み込みを実装する方法を紹介しました。

csv形式はシンプルな構造ですが、エスケープ処理を考慮した場合を考えるとPHPの標準クラスである SplFileObjectクラスを使用する方法がベストプラクティスとなっています。

今回の内容が皆さんのプロジェクトに活用できれば幸いです。

お疲れ様でした。