LoginSignup
5
2

【PHP】PhpSpreadsheet なんかより fast-excelでいいじゃんっていう話

Posted at

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"
  }
}

フォルダ構成はこんな感じ

フォルダ構成1.png

インポート・エクスポートのテンプレ(template.xlsx)はこんなん

テンプレ画像.png

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)

実行結果.png

まとめ

実行速度的にはエクスポート→インポートで0.5秒ぐらいで終わってた。
ちなみに1万でも試したけど2秒かからず、また実行中の利用メモリ量も特にアホみたいに跳ね上がることがなかったので、特にExcelに装飾せずに単純にテンプレとして処理したいとかなら、このライブラリ一択な気がするよ!

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2