產生 QRCode
在某次活動中,我們使用了 QRCode 掃票機制,事先產生 QRCode 派送給報名參加的來賓,活動開始時則進行 QRCode 掃票。以下簡單記錄 QRCode 產生機制,現場掃票部分則見即時查驗票。
Simple Qrcode
Simple Qrcode 是 Bacon/BaconQrCode 針對 Laravel 所提供的封裝版本,Laravel 使用者可以透過它輕鬆製作出簡易的 QRCOde。
首先透過 composer 安裝:
$ composer require simplesoftwareio/simple-qrcode
接著在需要的時候使用它即可:
use Qrcode;
// ...
Qrcode::generate('嵌入 QRCode 的字串', 'QRCode 的儲存位置');
也可以不儲存 QRCode,直接在 blade 渲染出來:
{!! QrCode::generate('嵌入 QRCode 的字串'); !!}
當然這都只是簡單的範例,還有許多可以調整的設定,例如透過 .format()
指定 QRCode 檔案格式、透過 .size()
、color()
指定 QRCode 的尺寸、顏色等,甚至透過 merge()
將自己的 logo 嵌入到 QRCode 裡:
QrCode::errorCorrection('H')
->format('png')
->size(300)
->color(0, 0, 0)
->merge('logo-path.png', .2, true)
->generate('嵌入 QRCode 的字串');
提示
errorCorrection()
為 QRCode 的容錯能力。容錯能力越高,QRCode 能儲存的資料量越少,但圖形越簡單,越容易被讀取。細節可參考這篇 台大電子報 的說明。
Simple Qrcode 圖例:
加入文字到 QRCode
QRCode 產生出來了,但也有更多問題冒出來:
這張 QRCode 怎麼掃就是掃不出來,怎麼辦?
我們會隨信附上票號,到時可透過票號查詢。
如果來賓只印了 QRCode,沒有印信件內容,更沒有印票號呢?
那我把票號直接印在 QRCode 上可以了吧?
Step1. 產生文字方塊
首先透過 imagettfbbox()
產生一個文字方塊,並將票號 $code
輸入進去:
// 取得字型檔 & 設定字型大小
$fontFile = "path-to-font.ttf";
$fontSize = 12;
// 產生文字方塊 & 計算寬高
$textBox = imagettfbbox($fontSize, $angle = 0, $fontFile, $code);
$textW = $textBox[4] - $textBox[6];
$textH = $textBox[1] - $textBox[7];
說明
imagettfbbox()
會回傳一個陣列,索引 0 - 7 對應的值分別是:
Step2. 計算座標
我們剛才產生了文字方塊,並計算出它的寬高,接下來要與 QRCode 的圖片尺寸比對,計算出適當的座標將文字輸入進去,以確保文字在 QRCode 下方水平置中:
$qrcode = QrCode::generate($code);
$image = imagecreatefromstring($qrcode);
$imageW = imagesx($image);
$imageH = imagesy($image);
$x = ($imageW / 2) - ($textW / 2);
$y = $imageH - $textH;
Step3. 加入文字
計算完座標之後,透過 PHP 的 imagettftext()
將文字寫入圖片,並儲存下來,就大功告成了:
imagettftext($image, $fontSize, 0, $x, $y, $color, $fontFile, $code);
imagepng($image, $file);
發信事件監聽
QRCode 產生完後,就是透過 Laravel 的發信機制將票券寄給來賓了,這部分參照 Laravel 官方文件便可。
若要確保系統有正常發信,可分別在發信時與發信後紀錄 Log,Laravel 預設提供 MessageSending
與 MessageSent
兩個監聽事件給我們使用,在 EventServiceProvider
註冊它們即可:
protected $listen = [
'Illuminate\Mail\Events\MessageSending' => [
'App\Listeners\LogSendingMessage',
],
'Illuminate\Mail\Events\MessageSent' => [
'App\Listeners\LogSentMessage',
],
];