【決定版】PHPで超簡単にCSVを操作する方法
プログラムを作っていく中で、データのやり取りや保存などを手軽に行う方法の一つとして「CSV」があります。
しかし、CSVのやり取りを毎回作っていては時間の無駄、かといって RFC4180 に準拠したCSVを取り扱えるようなプログラムを作るには時間がかかります。
今回はそんな、面倒なCSVファイルの取扱いを【超簡単】にしてしまうライブラリをご紹介します。
目次
はじめに
今回ご紹介するライブラリは 「league/csv」 です。
バージョンは記事執筆時点の最新安定板 9.2.1 を使用します。
◆league/csvに関するリンク
環境
実行環境はこんな感じです。
CentOS 7
PHP Version 7.1.11
Composer
※Composerのインストールおよび使い方の説明は割愛します
※Linuxの使い方の説明は割愛します
実装方法
インストール
まずは composer で league/csv をインストールします
1 2 3 |
$ composer require league/csv:^9.0 |
続いて league/csv を使用できるようにします
1 2 3 4 5 6 7 8 |
require 'vendor/autoload.php'; // League\Csv use League\Csv\Reader; use League\Csv\Writer; use League\Csv\CharsetConverter; |
これで league/csv を使用する準備ができました。
CSVファイルを読み込む
CSVを読み込むには下記のような感じになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 読み込むCSVファイルを指定 $reader = Reader::createFromPath('data.csv', 'r'); // 文字エンコードを指定(SJIS-win -> UTF-8) CharsetConverter::addTo($reader, 'SJIS-win', 'UTF-8'); // レコード件数を取得 echo $reader->count(); // データ読み込み $records = $reader->getRecords(); foreach($records as $idx => $row) { echo $idx.":".$row[0]; // 各レコードごとの処理は割愛 } |
これですべてのデータを2次元配列として取得することができます。
エンコードも設定1つでできるので非常に楽ですね。
細かくCSVデータを取得する
このライブラリの真骨頂はここにあると思っています。
1つずつ説明していきます。
CSVの詳細を設定する
1 2 3 4 5 6 7 8 |
// 区切り文字を指定 $reader->setDelimiter(','); // 囲い文字を指定 $reader->setEnclosure('"'); // エスケープを指定 $reader->setEscape("\\"); |
デフォルトは上記のようなものですが、タブ区切りなどにも変更が可能です。
ヘッダー行を設定する
1 2 3 4 5 |
// ヘッダーの行番号を指定し、ヘッダーを取得 $reader->setHeaderOffset(0); $header = $reader->getHeader(); |
指定した行番号のデータをヘッダーとして設定・取得できます。
ヘッダーを指定した場合、データは 連想配列として取得 できるようになります。
ヘッダーを指定した場合 データ開始の番号が1番からになる という点に注意です。
列を指定して取得する
特定の列のみを取得するには下記のようになります。
1 2 3 4 5 6 7 |
// 列を指定して取得 $records = $reader->fetchColumn(1); foreach($records as $idx => $column) { echo $column; } |
なお fetchColumn はヘッダーを指定した場合、連想配列のキーを指定して取得することも可能です。
取得位置や件数を指定して取得する
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 操作用ライブラリを指定 use League\Csv\Statement; // 取得開始位置や件数を指定して取得 $stmt = (new Statement()) ->offset(1) ->limit(2); $records = $stmt->process($reader); foreach($records as $idx => $row) { echo $idx.":".$row[0]; } |
データベースのSQLのように、取得開始位置や件数を指定して取得できます。
JSON文字列化
1 2 3 4 |
// JSON文字列化 echo json_encode($reader); |
JSON文字列としてCSVのデータを出力することができます。
ヘッダーを指定するとkey-value形式になり、指定しないと先頭に行番号の付いた配列形式になります。
XMLとして出力する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// XML変換用のライブラリを指定 use League\Csv\XMLConverter; // XML出力 $converter = (new XMLConverter()) ->rootElement('csv') ->recordElement('record', 'offset') ->fieldElement('field', 'name'); $dom = $converter->convert($reader); $dom->formatOutput = true; $dom->encoding = 'UTF-8'; header("Content-Type: application/xml; charset=utf-8"); echo $dom->saveXML(); |
下記のような感じでCSVのデータをXMLとして出力できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="UTF-8"?> <csv> <record offset="1"> <field name="NO">1</field> <field name="NAME">Apple</field> <field name="Product">アイフォーン</field> </record> <record offset="2"> <field name="NO">2</field> <field name="NAME">Google</field> <field name="Product">アンドロイド</field> </record> <record offset="3"> <field name="NO">3</field> <field name="NAME">Microsoft</field> <field name="Product">ウィンドウズ</field> </record> <record offset="4"> <field name="NO">4</field> <field name="NAME">Amazon</field> <field name="Product">キンドル</field> </record> </csv> |
ヘッダーを指定しない場合下記のようにフィールド名が数字になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?xml version="1.0" encoding="UTF-8"?> <csv> <record offset="0"> <field name="0">NO</field> <field name="1">NAME</field> <field name="2">Product</field> </record> <record offset="1"> <field name="0">1</field> <field name="1">Apple</field> <field name="2">アイフォーン</field> </record> <record offset="2"> <field name="0">2</field> <field name="1">Google</field> <field name="2">アンドロイド</field> </record> <record offset="3"> <field name="0">3</field> <field name="1">Microsoft</field> <field name="2">ウィンドウズ</field> </record> <record offset="4"> <field name="0">4</field> <field name="1">Amazon</field> <field name="2">キンドル</field> </record> </csv> |
CSVファイルを書き出す
CSVを書き出すには下記のような感じになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// CSVのライターを作成(新規作成) $file = new SplTempFileObject(); $writer = Writer::createFromFileObject($file); // // 追加作成の場合はコチラ // $writer = Writer::createFromPath('data2.csv', 'a+'); // 文字コードを設定 $converter = (new CharsetConverter()) ->inputEncoding('UTF-8') ->outputEncoding('SJIS-win'); $writer->addFormatter($converter); // 区切り文字を設定 $writer->setDelimiter(","); // 囲い文字を設定 $writer->setEnclosure('"'); // エスケープを指定 $writer->setEscape("\\"); // 改行コードを設定 $writer->setNewline("\r\n"); // 書き込むデータを設定 $records = [ [1, 2, 3], ['one', 'two', 'three'], ['A', 'B', 'C'], ['あいうえお', "かき\"く\r\nけこ", 'さしすせそ'], ]; // 1件のデータを挿入 $writer->insertOne($records[0]); // 複数のデータを一度に挿入 $writer->insertAll($records); // ファイル名を設定 $fileName = 'test.csv'; // CSVファイルを書き出す $csvStr = $writer->getContent(); file_put_contents($fileName, $csvStr); |
既存ファイルへの追記などの場合 insertOne, insertAll は 実行した時点でファイルに書き込まれます。
囲い文字を指定しても出力されたファイルに囲い文字が設定されていない場合 RFC4180 を読んでください。
全ての項目を囲い文字で囲う処理はありません。
CSVファイルをダウンロードさせる
CSVファイルをダウンロードさせるには下記のような感じになります。
1 2 3 4 5 6 7 |
// ファイル名を設定 $fileName = 'test2.csv'; // ダウンロード処理 $writer->output($fileName); |
output の時点で header が出力されます。
そのため、ダウンロード命令より前に画面出力を行うとエラーになります。
日本語名のファイルダウンロードにも対応しています
Composerが使えない・使わない場合
もし環境によりComposerが使えない場合やWindowsで使用する場合など、別の方法でインストールしたい時はこちらの記事をご参照ください。
PhpSpreadsheetを例に挙げた、Composerを使わずに使用する方法を記載しています。
さいごに
今回説明したのは基本的な操作になります。
今までCSVファイルを扱うためにアレコレとプログラムを書いていましたが、これはかなり楽になります。
また、今回はご紹介しませんでしたが、DBとの連携もできるみたいですので、もっと詳しく操作したい場合は、公式の APIリファレンス を参照してください。
- おすすめ記事
POPULAR
のえる
Full-stack Developer