こんにちは。株式会社リンクネット、ソリューション事業部の高橋です。
弊社ではWebシステムバックエンドにLaravelを利用しています。
エクセルのファイル(.xlsx)をPHPで操作しPDFファイルとして出力した際に、
レイアウトが崩れる場合や、日本語が表示されないといった想定外の問題が発生しました。
この記事では、上記の問題を解消した方法を共有します。
$ sail artisan -V
Laravel Framework 8.82.0
$ sail php -v
PHP 8.1.5 (cli) (built: Apr 21 2022 10:15:06) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.5, Copyright (c) Zend Technologies
with Zend OPcache v8.1.5, Copyright (c), by Zend Technologies
with Xdebug v3.1.2, Copyright (c) 2002-2021, by Derick Rethans
エクセルファイルを操作する方法としましてはPhpSpreadsheetを選定しました。
本記事ではインストール方法については省略します。
https://github.com/PHPOffice/PhpSpreadsheet
今回、使用するエクセルファイルは下記になります。
https://www.microsoft.com/ja-jp/office/pipc/template/result.aspx?id=13281
ベースとなるエクセルファイルを読み込む
$public_path = public_path('excel/sample_format.xlsx'); //サンプルファイルのPATHを取得
$file_name = 'example';
$tmp_path = storage_path('app/example');
$tmp_xlsx_path = $tmp_path.'/'.$file_name.'.xlsx';
$tmp_pdf_path = $tmp_path.'/'.$file_name.'.pdf';
$xr = new XReader(); //PhpSpreadsheetのClass
$xr->setReadDataOnly(false); //これをfalseにしないと複写できない
$spread = $xr->load($public_path); //エクセルファイルの読み込み
$sheet = $spread->getActivesheet();//現在選択中のシートの読み込み
エクセルファイルの任意のセルに値を代入する。
//エクセルファイルのセルに値を代入
$sheet->setCellValue('B6', 'サンプル株式会社');
エクセルファイルの保存
$sheet->getPageSetup()->setPrintArea('A1:F58');//印刷範囲
$sheet->getPageSetup()->setScale(90);//印刷時の倍率
$sheet->getPageSetup()->setPaperSize(PageSetup::PAPERSIZE_A4); //A4サイズ
//xlsxファイルを出力
$writer = new XlsxWriter($spread);
$writer->save($tmp_xlsx_path);
出力されたxlsxファイル ※B6にサンプル株式会社と入力されています。
PDFファイルとして出力する。
PhpSpreadsheet
の機能でPDFへ変換する。
$Xw = IOF::createWriter($spread,'Tcpdf'); //IOFactoryで作成する
$Xw->setFont('kozgopromedium'); //作成したオブジェクトにフォント設定をする(小塚ゴシック)
$Xw->save($tmp_pdf_path); //保存する
出力されたPDFファイル ※PhpSpreadsheetで出力されたPDFはレイアウトが崩れてしまいます。
PHPでの出力方法が他にないか調査したところDompdf
、TCPDF
、mPDF
が候補にあがりましたが、
やはりレイアウトが崩れてしまうようです。
PHPで変換するよりはlibreoffice
で変換するほうがレイアウトが崩れないようです。
参考サイト:
https://qiita.com/Hiro2525/items/2bab16f5d9318762e2fd
libreoffice
の機能でPDFへ変換する。
libreoffice
のインストール
参考サイト:
https://www.kkaneko.jp/tools/ubuntu/libreofficejaubuntu.html
開発環境ではsailを使用しているため、sail shellで libreoffice
をインストールします。
root権限でsail shellにログインし、libreoffice
をインストールする。
$ sail root-shell
root@b74b851b5064:/var/www/html#apt -y update
root@b74b851b5064:/var/www/html#apt -y install libreoffice libreoffice-l10n-ja libreoffice-dmaths libreoffice-ogltrans libreoffice-writer2xhtml libreoffice-pdfimport libreoffice-help-ja
PHPではlibreoffice
のコマンドを実行して.xlsxファイルをPDFへ変換します。
//libreofficeでxlsxファイルをpdfに出力
$command = '/usr/bin/soffice --headless --convert-to pdf --outdir '.$tmp_path.' '.$tmp_xlsx_path;
exec($command);
出力されたPDFファイル ※レイアウトはきれいに出力されましたが、日本語が文字化けしています。
おそらく、 libreoffice
に日本語フォントが登録されていないと推測できたので、
調査したところ、下記のサイトで導入方法が見つかりました。
今回はIPAフォントを選択しました。
参考サイト:
https://lab4ict.com/system/archives/879
日本語フォントを登録する。
root権限でsail shellにログインし、日本語フォントを登録する
$ sail root-shell
root@b74b851b5064:/var/www/html#apt install fonts-ipafont fonts-ipaexfont
root@b74b851b5064:/var/www/html#fc-cache -fv
出力されたPDFファイル ※日本語も表示されました。
今回、紹介しました方法では、dockerコンテナを起動する度に、
sail shellでのlibreofficeや日本語フォントのインストールが必要となります。
そのため、自動でインストールできる仕組みの構築が課題となります。