📝

【laravel-dompdf】Undefined array key "" のエラー対応

2024/07/10に公開

結論

  • ビルドコンテナ内でload_font.phpを実行していたのが原因
  • デプロイコンテナ内でload_font.phpを実行するように修正したら解決!

環境

  • 環境
    • Docker + CodeBuild + ECS
  • ライブラリ

経緯

  • 以下の作業中に発生
    • Laravel 7 → Laravel 10へのマイグレーション中
    • デプロイコンテナ単体で各種インストールからセットアップまで一括で行っていたが、ビルドコンテナ+デプロイコンテナの構成に変更
      • CodeBuild上のビルドコンテナでcomposer installを実行や設定ファイルの生成を行う
      • その後はECS上のデプロイコンテナにコピー
    • が、laravel-dompdfでPDF機能の確認をしようとしたらエラー!なぜ!

エラー内容

{
    "class": "ErrorException",
    "message": "Undefined array key \"\"",
    "code": 0,
    "file": "/var/www/html/vendor/dompdf/dompdf/lib/Cpdf.php:4752"
}

手順

laravel-dompdfのインストール手順は省く

1. config/dompdf.phpの再生成

  • 旧バージョンからのバージョンアップしていた場合、config/dompdf.phpが旧仕様のままの可能性があるので再生成する
php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"

2. load_font.php内の$fontDirに絶対パスを指定

自分の環境では以下のようにフォントファイルのパス設定していたので

// dompdf用の設定
$this->publishes([
    base_path('vendor/dompdf/dompdf/lib/fonts') => storage_path('fonts'),
], 'public');

以下のように調整した。(これはちょっと蛇足だったかもしれない、各々の環境に応じて調整が必要かも)

// 2. [Optional] Set the path to your font directory
//    By default dompdf loads fonts to dompdf/lib/fonts
//    If you have modified your font directory set this
//    variable appropriately.
//$fontDir = "lib/fonts";
/**
 * load_font.phpからstorage/fontsディレクトリへの絶対パスを設定する。
 * 自分の場合はこのファイルがresources/foo/fontsに配置されていたので、dirname(__DIR__, 3)でstorage/fontsディレクトリへの絶対パスを取得する。
 */
$fontDir = dirname(__DIR__, 3) . '/storage/fonts';

3. load_font.phpをデプロイコンテナ内で実行

以下のコマンドでload_font.phpを実行すると、実行環境におけるstorage_path関数を元にフォントファイル設定を生成する

php resources/foo/fonts/load_font.php ipag resources/foo/fonts/ipag.ttf

つまりビルドコンテナ上でload_font.phpを実行していると、生成された設定ファイルがビルドコンテナ環境のstorage_pathとして生成される!←これがエラーの原因

生成されたフォント設定ファイル(installed-fonts.json)について

  • ↓がビルドコンテナ上で生成したinstalled-fonts.json
  • パスがビルドコンテナ準拠になっているので、これをデプロイコンテナにコピーしても当然動かない
  • 「設定ファイルがあるが、パスが不正でフォントを読み込めない」という挙動になる
    • その結果としてUndefined array key ""が発生
{
    "ipag": {
        "normal": "\/codebuild\/output\/XXXX\/src\/vendor\/dompdf\/dompdf\/lib\/fonts\/ipag",
        "bold": "\/codebuild\/output\/XXXX\/src\/vendor\/dompdf\/dompdf\/lib\/fonts\/ipag",
        "italic": "\/codebuild\/output\/XXXX\/src\/vendor\/dompdf\/dompdf\/lib\/fonts\/ipag",
        "bold_italic": "\/codebuild\/output\/XXXX\/src\/vendor\/dompdf\/dompdf\/lib\/fonts\/ipag"
    }
}
  • ↓がデプロイコンテナ上で生成したinstalled-fonts.json
  • パスが正しいので当然ちゃんと動く
{
    "ipag": {
        "normal": "\/var\/www\/html\/storage\/fonts\/ipag",
        "bold": "\/var\/www\/html\/storage\/fonts\/ipag",
        "italic": "\/var\/www\/html\/storage\/fonts\/ipag",
        "bold_italic": "\/var\/www\/html\/storage\/fonts\/ipag"
    }
}

余談

  • 公式のissueに同じエラーが報告されているが、この人もinstalled-fonts.json内のパスがおかしいのでは?という気がしている
  • もうちょっとエラーメッセージがわかりやすければ...
    • 「設定ファイルに記述されているフォントファイルが存在しません」みたいなやつが欲しかった

Discussion