CakePHP 4 で PhpSpreadsheet を使い xlsx ファイルからデータを配列で読み込む
はじめに
前回の「CakePHP 4 で PhpSpreadsheet のダウンロード機能をコンポーネントに実装」に引き続き、今日も CakePHP 4 で PhpSpreadsheet を使う話題です。
今日は xlsx ファイルをアップロードして、そこからデータを読み込む方法をご紹介します。
CakePHP 4 に PhpSpreadsheet を導入する方法は、過去記事「CakePHP 4 で PhpSpreadsheet を使う方法」を参考にしてください。
- Welcome to PhpSpreadsheet's documentation - PhpSpreadsheet Documentation
- https://phpspreadsheet.readthedocs.io/en/latest/
- CakePHP
- 4.0.3
- PhpSpreadsheet
- 1.10.1
- PHP
- 7.3.11
- OS
- Win 10 Home
1. xlsx ファイルから配列形式でデータを取得
まずは xlsx 読込部分のサンプルをご紹介します。下記は xlsx からデータを配列で取得するものです。動作確認の前に /webroot/sample.xlsx を作成してください。
<?php
declare(strict_types=1);
namespace App\Controller;
use PhpOffice\PhpSpreadsheet\IOFactory;
class SampleController extends AppController
{
public function index()
{
$file = WWW_ROOT . 'sample.xlsx';
$spreadsheet = IOFactory::load($file);
$sheet = $spreadsheet->getActiveSheet();
debug($sheet->toArray());
exit;
}
}
上記コードは便宜上 webroot に sample.xlsx を配置していますが、それを推奨しているわけではありません。
webroot は公開ディレクトリなので、もし xlsx ファイルを一般公開したくない場合には、別なディレクトリに配置してください。
toArray() 関数を使えば簡単に配列として読み込むことができます。公式ドキュメントにはさらっと説明があります。
- Retrieving a range of cell values to an array (PhpSpreadsheet Documentation)
- https://phpspreadsheet.readthedocs.io/en/latest/topics/accessing-cells/#retrieving-a-range-of-cell-values-to-an-array
罫線、背景色、セル結合、SUM() などを含むエクセルファイルで試しましたが、各値を読むことができました。計算や SUM() などはその結果が取得されます。
ただ、セルの表示分類を「数値」にした際、末尾に半角スペースが付きました。
2. xlsx から1セルごとに値を取得
全体を一気に配列として取得するのではなく、1セルずつ値を取得したい場合は下記ように実装できます。
<?php
declare(strict_types=1);
namespace App\Controller;
use PhpOffice\PhpSpreadsheet\IOFactory;
class SampleController extends AppController
{
public function index()
{
$file = WWW_ROOT . 'sample.xlsx';
$spreadsheet = IOFactory::load($file);
$sheet = $spreadsheet->getActiveSheet();
$rows = [];
foreach ($sheet->getRowIterator() as $excelRow) {
$cellIterator = $excelRow->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(FALSE);
$row = [];
foreach ($cellIterator as $cell) {
$row[] = $cell->getValue();
}
$rows[] = $row;
}
debug($rows);
exit;
}
}
上記の例だと配列に格納するだけなので toArray() と変わりませんが、セルの値に応じてデータを加工したい場面などで役立つと思います。
公式ドキュメントの下記を参考にしています。
- Looping through cells (PhpSpreadsheet Documentation)
- https://phpspreadsheet.readthedocs.io/en/latest/topics/accessing-cells/#looping-through-cells
3. アップロードした xlsx からデータを配列で取得
CakePHP 4 のファイルアップロード機能と組み合わせて、フォームから送信した xlsx ファイルから配列でデータを取得します。
CakePHP 4 でのファイルアップ方法ついては「CakePHP 4 でファイルアップロードを実装する方法」でも紹介しています。
<form method="post" enctype="multipart/form-data">
<div>
<input type="file" name="my_file">
<input type="hidden" name="_csrfToken" autocomplete="off" value="<?= $this->request->getAttribute('csrfToken') ?>">
<button type="submit">アップロード</button>
</div>
</form>
<?php
declare(strict_types=1);
namespace App\Controller;
use PhpOffice\PhpSpreadsheet\IOFactory;
class SampleController extends AppController
{
public function index()
{
if ($this->request->is('post')) {
$myFile = $this->request->getData('my_file');
$tmpFile = $myFile->getStream()->getMetadata('uri');
$spreadsheet = IOFactory::load($tmpFile);
$sheet = $spreadsheet->getActiveSheet();
debug($sheet->toArray());
exit;
}
}
}
特に説明はなくても大丈夫だと思いますが、getStream()->getMetadata('uri') で一時保存先のパスが取得できます。getMetadata() と引数なしで実行すると、uri 以外のデータも含めて配列で取得できます。
- File Uploads (CakePHP 4 Cookbook)
- https://book.cakephp.org/4/en/controllers/request-response.html#file-uploads
- http-message/StreamInterface.php at master · php-fig/http-message · GitHub
- https://github.com/php-fig/http-message/blob/master/src/StreamInterface.php
4. おわりに
個人的な話になりますが、データの入出力は csv ファイル より xlsx を使うことが多くなってきています。CSV だと文字コードの調整が面倒だったり、Office ソフトで開いたときに「0001」が「1」になってしまったりするためです。
PhpSpreadsheet を使えば、エクセルファイルの単純な読み書きなら、少ないコードで実装可能です。気になる方は是非トライしてみてください。