PSLブログ

ヨシナシゴトヲツヅリマス

CentOS6.10+PHP5.3.3の環境でLibXL PHP Extensionを試す

サーバのデータをExcel形式で出力したいというニーズがよくある。基本CSVでもいいのだが、基本的に数値であっても文字列として取り扱いため、CSVだと、頭の0が取れてしまうとか、"1-1"などの文字列が勝手に日付になったりという問題があるので、Excelのセルデータ型を文字列にしておいて、値をセットして出力するというのが楽でよい。


しかし、今まで使っていた、Perlだと、Excel::Writer::XLSXは、速度はそこそこだが、既存のファイルを読み込んで編集できない(テンプレート支給のケースでNG)、PHPのPHPExcelはメモリ食い過ぎ+遅すぎ+古過ぎ、後発のPhpspreadsheetはメモリ食い過ぎ+遅すぎで使えない。100行くらいまでならなんとか使えるが、数千行とか、万を超えるデータは到底扱えない。

そこで探してみたところ、LibXL PHP Extensionというのがあった。LibXLは、C++で書かれていて高速かつメモリを消費しない。数万行のデータも瞬時に書き出せる。という頼もしい記事を見つけた。類似の記事は他にもあったが代表的なものを以下に貼り付ける。

qiita.com

どうやら、so(shared object)を作ってphp.iniに登録すれば使えそうということがわかり、弊社のVPS(CentOS6.10、PHP5.3.3)の環境に入れてみることにした。

以下手順。

cd /usr/local/src
wget http://libxl.com/download/libxl-lin-3.8.3.tar.gz
tar zxf libxl-lin-3.8.3.tar.gz
cd libxl-3.8.3.0
wget https://github.com/iliaal/php_excel/archive/master.zip
unzip master.zip
cd php_excel-master
yum install php-devel
phpize
./configure --with-libxl-incdir=../include_c --with-libxl-libdir=../lib64 *1
ln -s /usr/include/libxml2/libxml /usr/include/libxml
make
make install

configureの --with-libxl-libdir は、64bit環境の場合はlib64、32bit環境の場合はlibとする。でないと

configure: error: excel module requires libxl >= 2.4.3

のエラーが出る。

libxmlのパスが通っていなかったので設定した。これがないと

/usr/include/php/ext/xml/expat_compat.h:36:27: error: libxml/parser.h: No such file or directory
/usr/include/php/ext/xml/expat_compat.h:37:36: error: libxml/parserInternals.h: No such file or directory
/usr/include/php/ext/xml/expat_compat.h:38:25: error: libxml/tree.h: No such file or directory
/usr/include/php/ext/xml/expat_compat.h:39:25: error: libxml/hash.h: No such file or directory

というエラーが出る。

php.iniに以下の行を追加する。ライセンス名とキーは、ライセンスを購入していないのでこのまま。もし購入したら、メールで送られてきた内容を記述して再起動。

; 2018-10-15 LibXL PHP Extension
[php_excel]
extension=excel.so
;excel.license_name=LICENSE_NAME
;excel.license_key=LICENSE_KEY

Apacheを再起動。

service httpd restart

テストプログラムを試す。横300列、タテ100行に6ケタのランダムな数値を入れるという内容。0埋めをしているため、セットする文字列の冒頭に"'"をつけた。

<?php

ini_set('memory_limit', '256M');

$objExcel = new ExcelBook(null, null, true);
$objSheet = $objExcel->addSheet('test');

$ROWS = 100;
$COLS = 300;

// セルに値を入れる
for ($row = 0; $row < $ROWS; $row++) {
	for ($col = 0; $col < $COLS; $col++) {
		$objSheet->write($row, $col, "'".sprintf("%06d", rand(0, 1000000)), null, ExcelFormat::AS_NUMERIC_STRING);
	}
}

header('Content-Type: application/octet-stream');
header('Content-Disposition:attachment;filename="test.xlsx"');
$objExcel->save('php://output');

?>

アクセスして瞬時にダウンロードが始まった。ちょっと感動的。この速度は使える。

f:id:chii1873:20181016153905p:plain
試用版では、1行目に「試用版で作成された」というメッセージが表示される

今のところ、できるとわかったもの。

  • 既存のファイルを読み込んで編集・書き込み
  • セルのマージ
  • セルにハイパーリンクを設定する
  • セルに画像を貼り付ける

できないもの

  • グラフまわり
  • 貼り付けた画像にハイパーリンクを設定する
  • オートフィルターを設定する ※PHP7+の環境で、php7ブランチからソースをもってきて構築すれば利用可能

LibXLは有償で、1ライセンス$199ドル、無制限$1399ドルとなっている。業務で使うことを考えたら、十分ありだと思った。

*1:configure時の--with-libxl-incdirと--with-libxl-libdirのパスを修正しました(2020-03-16修正)。