1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravel + BrowsershotでPDFを生成 → プレビュー表示 → 自動印刷まで一括完了する方法【完全ガイド】

Last updated at Posted at 2025-07-09

✅ やりたいこと

Laravelアプリ上で、

・PDFを綺麗に出力し

・ブラウザで自動表示し

・印刷ダイアログまで自動で出す

という一連の流れを実現したい!

✅ 技術スタック

・Laravel 9

・spatie/browsershot

・Node.js + Puppeteer

・JavaScript (iframe.onload → print())

・Tailwind CSS(PDFでは非対応。CSSはstyle属性で対応)

✅ 完成イメージ

ボタンをクリックすると…
✅ サーバーでPDF生成
✅ 自動的に新しいタブで表示
✅ 即印刷ダイアログが開く!

↓ サンプル動画

✅ 1. Node.js & Puppeteer インストール手順

✅ 2. Laravel側に Browsershot 導入

✅ 3. PDF用Bladeテンプレートを作成

✅ 4. 印刷ボタン

// /views/receipts/show.blade.php

{{-- 印刷 --}}
<form action="{{ route('receipts.generate_and_print', [ 'id' => $receipt->id ]) }}"
    target="_blank">
    <button type="submit"
        class="text-white bg-indigo-500 border-0 py-2 px-8 focus:outline-none hover:bg-indigo-600 rounded text-lg">
        印刷する
    </button>
</form>

✅ 5. ルーティング

routes/web.php

// 印刷
// PDF生成 & 中継ページへ
Route::get('/receipts/pdf/print/{id}', [ReceiptController::class, 'generateAndPrint'])->name('receipts.generate_and_print');

// 中継ビュー(iframe + 自動印刷)
Route::get('/receipts/print/show/{filename}', [ReceiptController::class, 'showPrintView'])->name('receipts.print.show');

✅ 6. # tmpディレクトリ(storage/app/public/tmp)作成

mkdir -p storage/app/public/tmp
chmod -R 775 storage/app/public/tmp

✅ 7. ControllerにPDF生成&中継ビュー表示処理を追加

/Http/Controllers/ReceiptController.php
// ⭐️印刷
public function generateAndPrint($id)
{
    // ✅ 情報の取得
    /** @var \App\Models\User $user */
    $user = Auth::user();
    $receipt = $user
        ->receipts()
        ->with(['paymentMethod', 'bentoDetails'])
        ->findOrFail($id);

    // ✅ PDF作成
    $html = view('pdf.receipt', compact('receipt'))->render();
    $customerName = preg_replace('/[^\w\-]/u', '_', $receipt->customer_name);
    $filename = "receipt_{$customerName}_{$id}.pdf";
    $pdfPath = storage_path("app/public/tmp/{$filename}");

    Browsershot::html($html)
        ->setNodeBinary('/usr/local/bin/node')
        ->setIncludePath('/usr/local/bin')
        ->format('A4')
        ->showBackground()
        ->save($pdfPath);

    // ✅ PDF作成完了後、中継ビューへリダイレクト
    return redirect()->route('receipts.print.show', ['filename' => $filename]);
}

✅ 8. 中継ビューでPDF表示&自動印刷

// /views/pdf/print_redirect.blade.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>印刷中...</title>
    <style>
        html, body {
            margin: 0;
            padding: 0;
            height: 100%;
        }
        iframe {
            width: 100%;
            height: 100%;
            border: none;
        }
    </style>
</head>
<body>
    <iframe id="pdfFrame" src="{{ $pdfUrl }}"></iframe>

    <script>
        const iframe = document.getElementById('pdfFrame');
        iframe.onload = () => {
            iframe.contentWindow.focus();
            iframe.contentWindow.print();
        };
    </script>
</body>
</html>

✅ 9. 中継ビュー用 Controller を追加

/Http/Controllers/ReceiptController.php
public function showPrintView($filename)
{
    $pdfUrl = asset("storage/tmp/{$filename}");
    return view('pdf.print_redirect', compact('pdfUrl'));
}

✅ 10. 1時間以上経過したPDFは自動削除

① tmp フォルダを .gitignore に追加(Git管理対象外に)

.gitignore
/storage/app/public/tmp/

② Artisanコマンドで「古いPDFファイルを削除するスクリプト」を作成

php artisan make:command DeleteOldPdfs


作成後、以下のように編集:

app/Console/Commands/DeleteOldPdfs.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Carbon\Carbon;

class DeleteOldPdfs extends Command
{
    protected $signature = 'pdf:cleanup'; // コマンド名
    protected $description = '1時間以上前に作られたPDFを削除します';

    public function handle()
    {
        $dir = storage_path('app/public/tmp');
        $deleted = 0;

        foreach(File::files($dir) as $file) {
            // ファイルの作成から1時間以上経ってたら削除
            if(now()->diffInMinutes(Carbon::createFromTimestamp(filemtime($file))) > 60) {
                File::delete($file);
                $deleted++;
            }
        }

        $this->info("🗑️ {$deleted}個の古いPDFを削除しました!");
    }
}

③ スケジュールに登録する

app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    // 毎時このコマンドを実行(1時間以上前のPDF削除)
    $schedule->command('pdf:cleanup')->hourly();
}

④ 本番サーバでcron登録(ローカルなら不要)

Linuxサーバでターミナルから:

crontab -e

以下を追記(Laravelのschedulerを毎分呼び出す):

* * * * * cd /your/project/path && php artisan schedule:run >> /dev/null 2>&1

※ cd のパスは artisan があるプロジェクトルートにしてください。

関連

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?