【Laravel9】QRコードを使った入退室管理機能

この記事には広告を含む場合があります。記事内で紹介する商品を購入することで、当サイトに売り上げの一部が還元されることがあります。

Laravelを使って入退室管理機能(出席確認)を実装します。

今回のおもな仕様
  • Laravel9(8でも可能)
  • 入退室の記録はQRコードを使う
  • 入退室の記録はスマホやタブレット端末を使い専用QRコードリーダは使わない。
  • QRコードで記録後は画面遷移せずにそのまま次の人を記録したい(非同期通信)

想定ニーズ

ダンススクールや空手などのカルチャー教室での出席や入退室を管理する場合を想定。

会員の入退室を手作業で記録せず、ローコストで簡単にシステム管理(DB管理)する。

会員固有のQRコードを発行し、運営側が手持ちのスマホやタブレットで一気に読み取っていく感じです。

または専用のタブレットを入場口に固定しておき、会員がQRコードかざして記録させる。

こういったニーズを想定しています。

実装の前提条件

  • Laravelの実装環境が整っていること
  • DB環境が整っていること

会員固有のQRコード出力

LaravelでQR出力をするのはたったの2ステップで驚くほど簡単です。

simple-qrcodeをcomposerからインストール

QRコードの出力には「simplesoftwareio/simple-qrcode」のライブラリを使います。

「composer require simplesoftwareio/simple-qrcode “~4″」を実行してインストールします。

bladeから直接実行してQRコードを出力する

QRコードを表示させたい画面のbladeに以下を実装すればそれだけでQRコードが画面表示されます。

{!! QrCode::generate('QRコードに保存したい文字列'); !!}

基本的にはこの2ステップでQRコードが画面表示されます。

あとはQRコードに持たせるデータをどうするかを考えればよいです。

例えば会員ごとの固有の番号をQRコードに持たせます。会員番号とかです。

blade
// 会員モデルのIDをQRコードにする
{!! QrCode::generate( $user->id ); !!}

これで会員ごとの一意のQRコードができました。

そのQRコードをログイン後の会員システムで表示するなり、紙に印刷して渡したりします。

会員は渡されたQRコードを使い入退室を記録します。

「simple-qrcode」について詳細な利用方法はこちらに日本語マニュアルがあります。

https://www.simplesoftware.io/#/docs/simple-qrcode/ja

画像形式(png)を使うにはimagemagickが必要

デフォルトの仕様だとSVG形式でQRコードが出力されます。png形式にも対応しておりますが、imagickというphp拡張モジュールが必要になります。私が契約しているMixhostではimagickのphp拡張モジュールのインストールが難しい可能性があります。

https://help.mixhost.jp/hc/ja/articles/4407593474713-ImageMagick-PerlMagick-%E3%81%AE%E3%81%94%E5%88%A9%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

QRコードの読み込み

次にQRコードの読み取りです。

スマホの標準アプリのQRコードの読み取り機能は使いません。(iPhoneではカメラアプリでQRコード読み取ればWebページにアクセスすることが可能です。しかしこれは使いません)

今回は、Laravelで作ったアプリからQRコード読み込みのカメラを表示させて読み込ませます。

QRコードをただ読み取ればいいだけの仕様にすると、会員側が手持ちのスマホでいつでも入退室を記録できてしまうからです。

運営側がアプリ経由で立ち上げたQRコードリーダで読み取ることで、意味のあるQRコードとして記録されるようにします。

前置きが長くなりましたが、さっそくQRコード読み取りに進みましょう。

javascriptライブラリ「cozmo/jsQR」を使う

QRコード読み取りにはcozmo/jsQRを使います。

使うためにCDNをheadタグ内に定義します。

guest.blade.php
<head>

    <script src="https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"></script>
    <script>
        jsQR(...);
    </script>

</head>

これでライブラリを使う準備はOKです。

LivewireでQRコードリーダを実装する

laravelで非同期通信をするには「Livewire」か「Vue/React」を使います。

Livewireを使って進めます。

なぜ非同期通信を使うのかというと、入退室を連続で記録していきたいからです。

会員が複数人おとずれたときに記録するごとにQRコードリーダでアクションが必要となるのは手間が増えます。

QRコードリーダを起動したら起動したまま次々と会員の入退室を記録したいからです。

livewireのコンポーネントの作成

まずはlivewireのコンポーネントを作成します。

ターミナル
php artisan make:livewire Attendance.Attendancesqrcd(任意の名前)

Javascriptの実装

次に作成したblade.phpにQRコード読み取りの実装をします。

ここでは入室の記録をとるケースです。

attendancesqrcd.blade.php
<div>
    <div id="loading">ブラウザのカメラの使用を許可してください。</div>
    @if (session()->has('message'))
    <div class="alert alert-success d-flex align-items-center" role="alert">
        <i class="fa-solid fa-circle-check mr-1"></i>
        {{ session('message') }}
    </div>
    @endif
    <canvas id="canvas" hidden></canvas>

    <style>
        #canvas {
            width: 100%;
            height: 720px;
        }
    </style>
    {{-- @pushで囲んだ内容を@stackで出力する --}}
    @push('scripts')
    <script>
        // ここにJS
        const video = document.createElement('video');
        const canvasElement = document.getElementById('canvas');
        const canvas = canvasElement.getContext('2d');
        const loading = document.getElementById('loading');
        const output = document.getElementById('output');
        let previousData = '';

        navigator.mediaDevices.getUserMedia({
                video: {
                    facingMode: 'environment',
                }
            })
            .then((stream) => {
                video.srcObject = stream;
                video.setAttribute('playsinline', true);
                video.play();
                requestAnimationFrame(tick);
            });

        function tick() {
            loading.innerText = 'ロード中...';
            if (video.readyState === video.HAVE_ENOUGH_DATA) {
                loading.hidden = true;
                canvasElement.hidden = false;
                canvasElement.height = video.videoHeight;
                canvasElement.width = video.videoWidth;
                canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
                var imageData = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height);
                var code = jsQR(imageData.data, imageData.width, imageData.height, {
                    inversionAttempts: 'dontInvert',
                });
                // 直前に読み込んだQRコードの会員ならスキップさせる。そうしないと同じQRコードを常にリクエストしちゃう
                if (code && code.data !== previousData) {
                    previousData = code.data; // いま読み込んだデータをチェックに使うために変数に退避しておく
                    @this.attend(code.data) // livewireのメソッドを実行する。引数には会員IDが入る
                }
            }
            requestAnimationFrame(tick);
        }
    </script>
    @endpush

</div>
LivewireでJavascriptを使う時は@pushと@stackが必要

livewireはレンダリング時に一回だけしか通常は実行されません。これを常に有効にするためにはスクリプトを@pushで囲います。

@push('scripts')
<script>
    // ここにJS
</script>
@endpush

囲んだスクリプトをテンプレートで@stack(‘scripts’)してスクリプトを出力します。

たとえばapp.blade.phpやguest.balde.phpなどに定義します。

実装した画面にアクセスしてカメラ機能が有効になることを確認します。

デスクトップパソコンにカメラ機能がない場合

スマホのカメラをパソコン上のカメラに代用できるアプリ「iVCam」を使いましょう。すごく便利です。

DB登録処理

カメラの起動確認ができたら、DB登録の処理を実装します。

ここは実現したい内容やDB構造によって処理を追加してください。

Attendancesqrcd.php
<?php

namespace App\Http\Livewire\Attendance;

use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Livewire\Component;

class Attendancesqrcd extends Component
{
 
    public function render()
    {
        return view('livewire.attendance.attendancesqrcd')->layout('layouts.guest');
    }


    // 画面側から呼ばれるメソッド。入室編
    public function attend(User $user)
    {
        // テーブルに登録する
        DB::table('attendances')->insert([
            'user_id' => $user->id,
            'check_in_at' => Carbon::now(),
        ]);
        session()->flash('message',  $user->name ."様の出席登録が完了!");

    }
}

Livewireでレンダーさせることで非同期通信であるかのように動作します。

画面遷移することないので、複数人が連続で入室記録を取ることが可能になります。

まとめ

初歩的な入退室記録機能がLaravelとlivewireで実現できました。

  • QRコードの出力は「simplesoftwareio/simple-qrcode」を使ってラクできる
  • QRコードの入力は「cozmo/jsQR」を使ってラクできる
  • Livewireで実装すれば非同期通信で入室記録ができる