こんにちは。株式会社リンクネット、ソリューション事業部の高橋です。
弊社では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-jaPHPでは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や日本語フォントのインストールが必要となります。
そのため、自動でインストールできる仕組みの構築が課題となります。