PHPで大量のデータのインポート/エクスポートがしたい
って話があったので、PHPバブちゃんな投稿者が色々とやってみた結果を備忘録として残してみた。
困ったときのGoogle先生は?
真っ先に検索されたのが「PhpSpreadsheet」と「PHPExcel」だったので、
とりあえず記事の数的にもPhpSpreadsheetのほうが多くて何か安心だねってことで調べながら使ってみたんだけど、
この子がたかだか数万件のレコードを処理するだけなのにメモリと時間をアホみたいにモグモグして実用性に欠けたので、
検索文言変えまくって出てきたavadim/fast-excel-templatorを使ってみたよって話。
※PhpSpreadsheetでキャッシュとか使えって話ですが、使うための設定とかがめんどくさかったので、ノー設定でいけるのが欲しかった
とりあえず環境をDockerで作ってみた
※前に投稿したPHP(Apache入り)の環境+α
- PHP:8.1.4
- composer:2.7.1
Dockerfileを少しいじった
Dockerfile
FROM php:8.1.14-apache
WORKDIR /var/www/html
RUN echo "ServerName localhost" | tee /etc/apache2/conf-available/fqdn.conf
RUN a2enconf fqdn
# apt-get(Excel使うに当たって必要なライブラリ追加)
RUN apt-get update && \
apt-get install -y zlib1g-dev && \
apt-get install -y libzip-dev && \
apt-get install -y unzip
# ミドルウェアのインストール(Excel使うに当たって必要なエクステンション追加)
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions zip intl gd ctype
# コンポーザーのインストール
COPY --from=composer:2.7.1 /usr/bin/composer /usr/bin/composer
# コンポーザーでライブラリを導入
# Rootでcomposer installできるように、ここでこの設定を入れておく
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_NO_INTERACTION 1
COPY ./src/logic/composer.json /var/www/logic/composer.json
RUN cd /var/www/logic && composer install
composerの設定はこんな感じ
composer.json
{
"require": {
"avadim/fast-excel-reader": "^2.14.0",
"avadim/fast-excel-templator": "^1.0.5"
}
}
フォルダ構成はこんな感じ
インポート・エクスポートのテンプレ(template.xlsx)はこんなん
Excel処理をまとめたかったのでクラス化して実装
ExcelAction.php
<?php
use avadim\FastExcelTemplator\Excel;
require 'vendor/autoload.php';
final class ExcelAction
{
/**
* エクスポート
*/
function export()
{
try {
$excel = Excel::template(__DIR__ . '/template.xlsx');
$sheet = $excel->sheet("テンプレ"); // シート名指定でシート情報の取得
$rowTemplate = $sheet->getRowTemplate(2); // 2行目を出力テンプレにする
for ($i = 0; $i < 1000; $i++) { // とりあえずダミーデータ生成(1000件入れちゃう)しながら書き込み
$rowData = [
"A" => $i, // 整数
"B" => "ラベル" . $i, // 文字列
"C" => $i * 1.25, // 整数と少数有り数値
];
$sheet->replaceRow($i + 2, $rowTemplate, $rowData);
}
// ファイル保存
$path = __DIR__ . "/output/" . date("YmdHis") . substr(explode(".", (microtime(true) . ""))[1], 0, 3) . '.xlsx';
$excel->save($path);
return $path;
} catch (\Throwable $ex) {
$ex->getMessage();
exit;
}
}
/**
* インポート
*/
function import($path)
{
try {
$excel = Excel::open($path);
$sheet = $excel->selectSheet('テンプレ');
foreach ($sheet->nextRow([
'A' => "key",
'B' => "label",
'C' => "value"
], Excel::KEYS_ZERO_BASED) as $rowNum => $rowData) {
// ヘッダーはスキップ
if ($rowNum < 1)
continue;
echo $rowNum . "行目(key:" . $rowData["key"] . ",label:" . $rowData["label"] . ",value:" . $rowData["value"] . ")\n";
}
} catch (\Throwable $ex) {
$ex->getMessage();
exit;
}
}
}
動作確認も大事だよねってことで、起動用のファイルも作った
exportTest.php
<?php
require_once "../ExcelAction.php";
$excel = new ExcelAction();
$time_start = microtime(true);
$path = $excel->export();
$excel->import($path);
$time_end = microtime(true);
$time = $time_end - $time_start;
print_r('処理時間 = ' . $time . ' 秒');
実行結果(左がDockerDesktop, 右がVSCode)
まとめ
実行速度的にはエクスポート→インポートで0.5秒ぐらいで終わってた。
ちなみに1万でも試したけど2秒かからず、また実行中の利用メモリ量も特にアホみたいに跳ね上がることがなかったので、特にExcelに装飾せずに単純にテンプレとして処理したいとかなら、このライブラリ一択な気がするよ!