LaravelでPDFを出力する方法(laravel-dompdfを使う)

LaravelLaravel

Laravelでlaravel-dompdfを使用して、PDFを作成したので使い方をまとめました。
最初の方に、導入方法と実際にPDF出力の動作確認を書いて、後半に使いそうな内容をいくつか書いています。
載せているサンプルコードはLaravelのバージョン8で検証しています。

ライブラリのgithubはこちらです。
barryvdh/laravel-dompdf

laravel-dompdfの導入と設定

composerを使って、プロジェクトに導入したあとに、config/app.phpに対して設定を行います。

インストールする

下記コマンドをプロジェクト配下で実行します。

$ composer require barryvdh/laravel-dompdf

実行すると、インストールが終わって下記のように表示されます。

$ composer require barryvdh/laravel-dompdf
Using version ^0.9.0 for barryvdh/laravel-dompdf
./composer.json has been updated
Running composer update barryvdh/laravel-dompdf
# ---省略---
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
75 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

composer.json"barryvdh/laravel-dompdfが入っていることが確認できます。

"require": {
    "barryvdh/laravel-dompdf": "^0.9.0",
}

設定する

config/app.phpを開いて、インストールしたライブラリが使用できるように設定します。
providers項目に下記のようにライブラリを追加します。

'providers' => [
    //---省略---
    App\Providers\EventServiceProvider::class,
    App\Providers\RouteServiceProvider::class,
    //---ここから追加する---
    Barryvdh\DomPDF\ServiceProvider::class,
    //---ここまで追加する---
],

aliases項目のこちらにも、インストールしたライブラリを追加します。

'aliases' => [
    //---省略---
    'Validator' => Illuminate\Support\Facades\Validator::class,
    'View' => Illuminate\Support\Facades\View::class,
        //---ここから追加する---
    'PDF' => Barryvdh\DomPDF\Facade::class,
        //---ここまで追加する---
],

これで、PDFを出力する準備が完了しました。

日本語を表示するための設定

日本語を表示するためには、フォントファイルが必要です。
今回は、下記のフォントをダウンロードして使わせてもらいました。
M+とIPAの合成フォント

太字をPDFに表示するためには、フォントに太字のものが必要です。
migmix-2p-20200307.zipをダウンロードしました。
そして、下記の2つのフォントファイルをstorage/fonts配下に配置しました。

・migmix-2p-regular.ttf
・migmix-2p-bold.ttf

HTML(bladeファイル)からPDFを出力する

bladeのHTMLからPDFファイルを出力することができます。
今回は、このHTMLからPDFを作成する機能を使って、PDF出力しました。

コントローラーを作成する

出力のためのコントローラーを作成しました。
artisanコマンドで作成することができます。

$ php artisan make:controller PdfOutputController

app/Http/Controllers/PdfOutputController.phpにコントローラーが出来上がるので、下記のように編集しました。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PdfOutputController extends Controller
{
    public function output() {
        $sushiTable = [
            'たまご' => '100円',
            'いくら' => '200円',
            'サーモン' => '180円',
            'いか' => '100円',
            'マグロ' => '110円',
            'えび' => '100円',
        ];

        $pdf = \PDF::loadView('pdf_output', ['sushiTable' => $sushiTable]);
        $pdf->setPaper('A4');
        return $pdf->stream();
    }
}

解説

outputメソッドにPDF出力のための処理を書きました。
まず、bladeに渡したい値を配列で作成しました。お寿司のネタと値段を入れた配列です。

その後に、インストールしたPDFライブラリを使っています。
loadViewメソッドの第1引数にbladeファイルの名前、第2引数に渡したい値を連想配列で渡します。

作成したPDFクラスのインスタンスのsetPaperメソッドで用紙のサイズを指定しています。
今回はA4です。

最後にstreamメソッドを使用して、return $pdf->stream()としています。
こうすることで、ブラウザのPDFプレビューモードで開くようになります。

HTML(blade)ファイルを作成する

resources/views配下にpdf_output.blade.phpという名前でbladeファイルを作成しました。
内容は下記になります。

<html lang="ja">
    <head>
        <title>pdf output test</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <style>
            @font-face{
                font-family: migmix;
                font-style: normal;
                font-weight: normal;
                src: url("{{ storage_path('fonts/migmix-2p-regular.ttf')}}") format('truetype');
            }
            @font-face{
                font-family: migmix;
                font-style: bold;
                font-weight: bold;
                src: url("{{ storage_path('fonts/migmix-2p-bold.ttf')}}") format('truetype');
            }
            body {
                font-family: migmix;
                line-height: 80%;
            }
            .main_image {
                width: 100%;
                text-align: center;
                margin: 10px 0;
            }
            .main_image img{
                width: 90%;
            }
            .sushiTable {
                border: 1px solid #000;
                border-collapse: collapse;
                width: 50%;
            }
            .sushiTable tr th{
                background: #87cefa;
                padding: 5px;
                border: 1px solid #000;
            }
            .sushiTable tr td{
                padding: 5px;
                border: 1px solid #000;
            }

        </style>
    </head>
    <body>
        PDFの出力テスト!<br>
        <div style="font-weight:bold">ここは太字!</div>
        <div class="main_image">
            <img src="https://codelikes.com/wp-content/uploads/2019/06/PHP-e1601051806241.jpg" />
        </div>
        お寿司のテーブル
        <table class="sushiTable">
            <tr>
                <th>名前</th>
                <th>価格</th>
            </tr>
            @foreach ($sushiTable as $key => $value)
            <tr>
                <td>{{ $key }}</td><td>{{ $value }}</td>
            </tr>
            @endforeach
        </table>
    </body>
</html>

解説

下記の箇所で、インストールして配置したフォントを読み込んでいます。
storage_pathヘルパーを使用することで、storage配下のファイルにアクセスできます。
フォントファイルを通常用と太字用で、それぞれ読み込みました。

@font-face{
    font-family: migmix;
    font-style: normal;
    font-weight: normal;
    src: url("{{ storage_path('fonts/migmix-2p-regular.ttf')}}") format('truetype');
}
@font-face{
    font-family: migmix;
    font-style: bold;
    font-weight: bold;
    src: url("{{ storage_path('fonts/migmix-2p-bold.ttf')}}") format('truetype');
}

読み込んだフォントをbodyタグの全体に使うようにしています。

body {
    font-family: migmix;
    line-height: 80%;
}

後はCSSとしては、画像の位置やテーブルのボーダーなどを定義しました。
下記のように、bladeの書き方ができるので、if文を使用したりすることも可能です。

@foreach ($sushiTable as $key => $value)
<tr>
    <td>{{ $key }}</td><td>{{ $value }}</td>
</tr>
@endforeach

今回はforeachで渡された配列から、キーと値を取得して表示するようにしています。

PDF出力のルートを作成する

routes/web.phpを開いて、今回作ったコントローラーへのルーティングを追加します。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers;
use App\Http\Controllers\PdfOutputController;

Route::get('/output/pdf', [PdfOutputController::class, 'output']);

/output/pdfにアクセスしたら、PdfOutputControllerのoutputメソッドを実行してくれます。

動作確認する

ローカルで動作確認してみました。
`http://localhost:8000/output/pdf`にアクセスします。

そうすると、このようにPDFファイルが出力されました。
laravel-dompdfでPDF出力してみた

ちゃんと日本語出力できて、CSSが効いていますね。

用紙のサイズ・向きを変更する

サンプルコードで書いたように、setPaperメソッドで用紙のサイズを指定可能です。
また、横向きにするには、第2引数にlandscapeを指定します。

$pdf->setPaper('A4', 'landscape');

用紙のサイズについてはvendor/dompdf/dompdf/src/Adapter/CPDF.phpに定義があるのを発見しました。
$PAPER_SIZESに定義されている内容を設定できるようです。

static $PAPER_SIZES = [
        "4a0" => [0, 0, 4767.87, 6740.79],
        "2a0" => [0, 0, 3370.39, 4767.87],
        "a0" => [0, 0, 2383.94, 3370.39],
        "a1" => [0, 0, 1683.78, 2383.94],
        "a2" => [0, 0, 1190.55, 1683.78],
        "a3" => [0, 0, 841.89, 1190.55],
        "a4" => [0, 0, 595.28, 841.89],
        "a5" => [0, 0, 419.53, 595.28],
        "a6" => [0, 0, 297.64, 419.53],
        "a7" => [0, 0, 209.76, 297.64],
        "a8" => [0, 0, 147.40, 209.76],
        "a9" => [0, 0, 104.88, 147.40],
        "a10" => [0, 0, 73.70, 104.88],
        "b0" => [0, 0, 2834.65, 4008.19],
        "b1" => [0, 0, 2004.09, 2834.65],
        "b2" => [0, 0, 1417.32, 2004.09],
        "b3" => [0, 0, 1000.63, 1417.32],
        "b4" => [0, 0, 708.66, 1000.63],
//---省略---
];

余白を制御する

PDFで作成したページの上下左右の余白を調整したい場合です。
CSSで下記のようにすることで、制御可能です。

@page { 
    margin: 10px;
}

ここでは、上下左右に10px余白を取るようにしました。
このようにmarginで調整ができます。

改ページする

改ページさせたい場合にはCSSのpage-break-afterを使用します。
例えば、今回作成したサンプルの画像とテーブルを分けたい場合は、下記のようにします。

PDFの出力テスト!<br>
<div style="font-weight:bold">ここは太字!</div>
<div class="main_image">
    <img src="https://codelikes.com/wp-content/uploads/2019/06/PHP-e1601051806241.jpg" />
</div>
<div style="page-break-after: always"></div>
お寿司のテーブル
<table class="sushiTable">
    <tr>
        <th>名前</th>
        <th>価格</th>
    </tr>
    @foreach ($sushiTable as $key => $value)
    <tr>
        <td>{{ $key }}</td><td>{{ $value }}</td>
    </tr>
    @endforeach
</table>

下記のpage-break-after: alwaysがスタイルとして、つけられているタグの箇所で改ページされます。

<div style="page-break-after: always"></div>

結果として、このように分けられます。

ダウンロードさせる

プレビュー表示ではなくて、ダウンロードさせたい場合です。
その場合は、streamメソッドを呼ぶのではなく、downloadメソッドを呼んで返すようにします。

return $pdf->download();

保存していない画像(base64)を表示したい

base64を使用して、画像を表示することが可能です。
この場合は開発している環境に、PHPのgdライブラリが入っていないとエラーになるので注意です。

bladeファイルのimgタグに、下記のようにbase64画像の文字列を入れると表示されます。
png画像なら下記のように指定します。

<img src="data:image/png;base64,[base64画像テキスト]" />

画像をbase64文字列にするためのサンプルは下記になります。
[php]画像をbase64_encodeする

Laravelプログラミング
yasuakiをフォローする
codelikeなブログ

コメント

タイトルとURLをコピーしました