In this post, we will look at generating QR codes within your Laravel applications.
First, we will need to require the simple-qrcode package that provides first-party support for Laravel. The package itself wraps the Bacon/BaconQrCode package which itself is a port of the ZXing library but for PHP.
If you wish - you may directly interact with the BaconQrCode package without using simple-qrcode. However, simple-qrcode provides a better developer experience when used with Laravel. Additionally, with out-of-the-box support for overlaying images on QR codes.
With the context blurb out of the way. Let's dig in!
Step 1: Setting Up
Spin up a new Laravel 10 project (or step over this if you already have a project ready).
$ laravel new qrcodegenerator
Set up your database connection as per your own preference. Then install the simple-qrcode package via Composer.
$ composer require simplesoftwareio/simple-qrcode "~4"
Optional! If you want to create QR codes in .png
format. You will need to install the imagick
extension. In most cases, all you need to do is install via pecl
with pecl install imagick
. If that does not work for you, then Google is your friend here as it goes beyond the topic of this article.
Step 2: Creating The Controller
Now we need to wire up a controller and route before we can pull back a QR code in our browser.
Create a new QrCodeController
.
$ php artisan make:controller QrCodeController
And then reference the controller in our routes/web.php file.
<?php
use App\Http\Controllers\QrCodeController;
use Illuminate\Support\Facades\Route;
Route::get('/', [QrCodeController::class, 'show']);
Opening up the URL in our browser gives us a blank page at this point. Also as I'm using Valet here, I only need to enter the foldername.test
to view the project in my browser. Your setup may be different so you do you, whether that's php artisan serve
or something else.
Step 3: Generating QR Codes
At the very bare minimum, you can call the QrCode
facade alongside generate
with something to render. And you'll get a QR code back.
In my QrCodeController
I am creating a QR code with all the default settings with the following content "Hello, World!".
<?php
namespace App\Http\Controllers;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class QrCodeController extends Controller
{
public function show()
{
return QrCode::generate(
'Hello, World!',
);
}
}
Refresh the page in the browser and...
Step 4: Customising the Generated QR Code
Alright so how about something a little more interesting? A splash of colour? Let's use a couple of methods that allow us to change the background colour, foreground colour, and margin.
public function show()
{
return QrCode::size(200)
->backgroundColor(255, 255, 0)
->color(0, 0, 255)
->margin(1)
->generate(
'Hello, World!',
);
}
And here's the result:
Let's try something that makes our QR codes stand out. And I'm not talking about colours anymore.
We can actually modify the style and eye (the three corners) of the QR code. Try this out:
return QrCode::size(200)
->style('dot')
->eye('circle')
->color(0, 0, 255)
->margin(1)
->generate(
'Hello, World!',
);
Result:
Before closing this section. One more on colours: gradients.
$from = [255, 0, 0];
$to = [0, 0, 255];
return QrCode::size(200)
->style('dot')
->eye('circle')
->gradient($from[0], $from[1], $from[2], $to[0], $to[1], $to[2], 'diagonal')
->margin(1)
->generate(
'Hello, World!',
);
By specifying a from and to colour, alongside a type of gradient (vertical, horizontal, etc). You can create something really cool!
Merging Images
To overlay an image in a QR code - we'll need to change the way we do a few things.
To prepare for this I have dropped an image (twitter.jpg) in my storage/app folder. Then by calling ->merge($filepath)
, simple-qrcode will load that image and overlay it onto the QR code.
If you want to pull in the image data yourself, you can replace merge
with mergeString
. Eg: ->mergeString(Storage::get($path))
.
Merging an image is only supported with png
QR codes, so we need to specify the format on this, too.
public function show()
{
$data = QrCode::size(512)
->format('png')
->merge('/storage/app/twitter.jpg')
->errorCorrection('M')
->generate(
'https://twitter.com/HarryKir',
);
return response($data)
->header('Content-type', 'image/png');
}
Then the result of all this:
You may have noticed the line in regards to errorCorrection
. When we overlay an image, part of the QR code's data becomes obscured.
By default, the errorCorrection is set to the lowest value ('L'). If you attempt to scan your QR code like this, it's likely that the QR code will not scan. To remedy this we adjust the errorCorrection level up a notch until our code is scannable.
The various levels are:
- L: Low (7% correction)
- M: Medium (15% correction)
- Q: Quartile (25% correction)
- H: High (30% correction)
The higher the correction level, the more "noisy" the QR code becomes. Preferably you want the lowest correction level alongside a scannable QR code for the sake of keeping up appearances.
Downloading Generated QR Codes
To return a download response, you can either store the QR code as a file and return the path with return response()->download($path);
or stream the contents of the QR code without using the filesystem.
An example of using streamDownload
to do this:
public function download()
{
return response()->streamDownload(
function () {
echo QrCode::size(200)
->format('png')
->generate('https://harrk.dev');
},
'qr-code.png',
[
'Content-Type' => 'image/png',
]
);
}
Generating QR Codes in Blade
Since we've been using a Facade all along, generating a QR code in Blade is as simple as repeating the above steps. Call the facade, customise as required, and call generate.
{!! QrCode::size(256)->generate('https://google.com') !!}
Or another approach, encode the data within an image tag manually. For example, if you need to change the image type for whatever reason.
<img src="data:image/png;base64, {!! base64_encode(QrCode::format('png')->size(256)->generate('https://google.com')) !!} ">
QR Code Data Types
Alright, so we've been using URLs in these examples. Mobile devices are clever enough to figure out how to handle these when scanned, but we can go a step further.
If you want to read the long version of this. Check out the ZXing's Wiki page.
To summarise: simple-qrcode has a couple of helpers to specify the data the QR code will contain. You can replace the generate
method with any of these.
Here are a few examples:
Open a blank email addressed to "[email protected]".
QrCode::size(200)->email('[email protected]');
Open an email with a predefined subject and body.
QrCode::size(200)->email('[email protected]', 'Hello World', 'This is a test message.');
Phone Number
QrCode::size(200)->phoneNumber('555-555-5555');
SMS Text Message
Send an SMS text message to 555-555-5555 with a prewritten message, "Hi!".
QrCode::size(200)->SMS('555-555-5555', 'Hi!');
Wi-Fi
Share Wi-Fi credentials for your visitors.
QrCode::size(200)->wiFi([
'encryption' => 'WPA/WEP',
'ssid' => 'SSID of the network',
'password' => 'Password of the network',
'hidden' => 'Whether the network is a hidden SSID or not.'
]);
Geolocation
Share a location by providing a latitude and longitude.
QrCode::size(200)->geo(51.378638, -0.100897);
Conclusion
To see more advanced options for QR code customisation, refer to the documentation for simple-qrcode.
As for some real world examples of this package in action. I use simple-qrcode for generating QR codes for my QR code tracking SaaS.
Otherwise, if generating QR codes with Javascript is your thing. Consider checking out the node-qrcode library. I use this for generating QR codes on a static site, without any server involvement altogether.
Level Up Your Laravel Knowledge With Battle Ready Laravel
Learn how to audit, test, fix, and improve your Laravel applications by grabbing a copy of Battle Ready Laravel by Ash Allen. Say "no" to technical debt and become a more confident developer!
If you'd like to see what the book is all about, check out my review on it here.