Library / SDK
chillerlan/php-qrcode avatar
chillerlan/php-qrcode

chillerlan/php-qrcode: a PHP QR Code generator and reader with a one-line API

A PHP QR Code generator and reader with a user-friendly API.

2,391 stars327 forksPHPApache-2.0

At a glance

What is it?
A Composer package that renders Model 2 QR codes from PHP to PNG, SVG, EPS or PDF, and reads them back through GD or ImageMagick. It is a good fit for server-side PHP work and a poor fit for anything that needs to run without PHP 8.4.
Who is it for?
Adopt it if your stack is PHP 8.4 and you want QR generation and decoding inside the same Composer dependency, with output modules you can extend. Do not adopt it if you are pinned to PHP 8.3 or older, or if you need a reader that works without ext-gd or ext-imagick.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 30 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What chillerlan/php-qrcode actually replaces

The package is a namespaced, cleaned-up PHP implementation of Kazuhiko Arase's QR code generator, with a reader bolted on that comes from a PHP port of the ZXing library. That lineage matters more than any feature list. If you have ever dropped a single-file qrlib.php into a project, this is the structured version of the same idea: classes, a settings container, and output modules you can swap without touching the encoding logic.

The intended user is a PHP developer rendering QR codes on the server. A login page that shows a TOTP enrolment code, an invoice PDF with a payment link, a ticket with a scannable identifier. The README's quickstart uses exactly that first case, an otpauth:// URI for a mobile authenticator. The reader side is for the reverse direction: taking an uploaded image and pulling the payload out of it, which is why the requirements list ext-gd or ext-imagick as mandatory for reading.

It is not a client-side library and not a service. There is a separate JavaScript port published on NPM as @chillerlan/qrcode, and the README points at it explicitly, so the same author covers the browser case through a different package. Choosing this one means you have accepted that QR generation happens in PHP, on your server, inside your request or worker.

Encoding modes, ECC levels and the output module split

The generator produces Model 2 QR codes, versions 1 through 40, with error correction levels L, M, Q and H. The part worth understanding is mixed mode. A single symbol can combine encoding modes: numeric, alphanumeric, 8-bit binary with ECI support, and 13-bit double-byte for kanji (Shift-JIS) and hanzi (GB2312/GB18030, per GBT18284-2000). That is not a cosmetic feature. A URL with a long numeric ID and a short domain encodes far more compactly when the segments are typed correctly, and the difference shows up as a lower version number and a less dense symbol.

The architecture splits encoding from rendering. Output modules are described as flexible and easily extensible, and the built-in set covers GdImage raster formats (avif, bmp, gif, jpeg, png, webp), ImageMagick, markup types such as SVG and HTML, string types such as JSON and plain text, Encapsulated Postscript, and PDF through setasign/fpdf. Because the module boundary is the seam, adding a format means writing an output class rather than editing the encoder. The examples directory reflects that breadth: image.php, imagick.php, eps.php, fpdf.php, html.php, custom_output.php, plus variants for logos, rounded shapes, text and background images.

Each output path carries its own dependency. GD output needs ext-gd. ImageMagick output needs ext-imagick with ImageMagick installed, and ext-fileinfo is required by QRImagick. PDF needs setasign/fpdf. intervention/image is listed as an alternative for GD and ImageMagick output. These are optional extensions, which means a package that installs cleanly can still fail at render time if you picked a module whose extension is missing.

Installing chillerlan/php-qrcode with Composer and rendering a first code

Installation goes through Composer, and the README's terminal example is a single command. Run it from your project root and the package lands in vendor/ alongside its autoloader.

bash
composer require chillerlan/php-qrcode

The README also shows the composer.json form, which pins the PHP requirement and uses a dev-main reference with a commit hash. That form is for tracking development; the accompanying note says to replace dev-main with a version constraint such as ^6.0. Use the released constraint unless you have a reason not to, because the documentation carries a direct warning about branch mismatch.

json
{
	"require": {
		"php": "^8.4",
		"chillerlan/php-qrcode": "dev-main#<commit_hash>"
	}
}

The quickstart is genuinely one line. It encodes an otpauth URI and echoes an img tag whose src is a data URI, which is the shortest path from a string to something a browser will render.

php
$data = 'otpauth://totp/test?secret=B3JX4VCVJDVNXNZ5&issuer=chillerlan.net';

echo '<img src="'.(new QRCode)->render($data).'" alt="QR Code" />';

After that, the README stops being a tutorial. It says to see Advanced usage in the manual and to look in the examples folder, and it adds a warning that deserves attention: use the examples from the branch matching your installed version, with v5.x, v6.x and dev-main listed separately. The main branch is described as active development for future major versions and most likely incompatible with the latest release versions. Copying an example from main into a project running the current release is the most likely way to hit a confusing error.

Where chillerlan/php-qrcode is the wrong tool

The PHP floor is the first hard boundary. The package requires PHP 8.4 or newer, plus ext-mbstring. On a host still running PHP 8.2 or 8.3, this is not a configuration problem to work around; it is a version you cannot install. The repository's topics include let-php5-die, php5-is-dead and php7-is-dead, which tells you the maintainer treats old runtime support as a deliberate non-goal rather than a backlog item.

The reader has its own constraint. Either ext-gd or ext-imagick is required for decoding, and the README states this with an exclamation mark. A minimal PHP build without image extensions can generate codes but cannot read them. If your deployment image is stripped down for size, that is a real fork in the road: you either add an image extension or you move decoding somewhere else.

There is also a scope limit that the README does not spell out but the reader's provenance implies. The decoder is a port of ZXing via a PHP library, and the examples include a reflectance.php file, which points at the kind of preprocessing that camera-captured images often need. For clean, machine-generated images the reader is the right shape. For photographs of a screen at an angle, expect to do work on the image before handing it over, and expect that work to be yours.

Finally, the README carries a disclaimer about molten CPUs, misled applications and failed log-ins, ending with use at your own risk. It is written with a wink, but the underlying point is real: a QR code that encodes the wrong payload produces a code that scans perfectly and sends the user somewhere wrong. Nothing in the library validates that your otpauth URI is correct.

How it compares to endroid/qr-code and to a JavaScript port

endroid/qr-code is the other PHP package people arrive at when searching for this problem, and the difference is in what the package is built around. The chillerlan package is organized around encoding modes and an extensible output module system, with the reader as a second capability from the same codebase. The endroid package is organized around the writer and its integrations with Symfony and Twig, which matters if your application is already a Symfony app and you want the QR code wired into the framework's configuration rather than instantiated by hand. If you are outside Symfony, that integration is weight you are not using.

The JavaScript port is a different axis entirely. @chillerlan/qrcode on NPM moves generation to the browser, which removes the server round trip and the PHP requirement, and moves the payload into client-side code. That is the wrong direction for anything containing a secret, including the otpauth example in the README's own quickstart. Server-side rendering with this package keeps the secret out of the page source; the NPM port does not.

The reader comparison is the one that is genuinely thin. The README attributes the reader to a PHP port of a specific detector-decoder library, and that library appears in the related searches as its own subject. If you only need decoding and not generation, evaluating that library directly is reasonable, since this package's reader descends from it. What you gain by staying here is one dependency and one API surface instead of two.

Maintenance, version pinning and licence obligations

The repository is not archived, and the last push was on 2026-08-31. Releases are versioned and dated: 6.0.1 on 2026-03-30, 6.0.0 on 2026-03-14, and 5.0.5 on 2025-11-24. The gap between the 6.0.x line and the last push suggests ongoing work that has not yet been cut as a release, which matches the README's statement that main is development for future major versions.

The upgrade cost is concentrated in the major version boundary. The README instructs users to take examples from the branch matching their installed version and lists v5.0.x, v6.0.x and main as separate example sets. That is a maintenance tax on every major bump: your copy-pasted snippets and any subclassed output modules need checking against the new branch. Pin with a constraint such as ^6.0 rather than tracking dev-main, because dev-main is explicitly described as likely incompatible with the latest release.

On licensing, the package itself is Apache-2.0. The repository carries both LICENSE-ASL-2.0 and LICENSE-MIT, and the NOTICE file records that parts of the code are ported to PHP from the ZXing project under the Apache License, Version 2.0. The documentation is separately licensed under CC BY 4.0, which is a different licence from the code and applies to the docs directory, not to what you ship. If you redistribute the library, the NOTICE and attribution obligations travel with it. The README also opens a trademark notice about the word QR, though the text is truncated in the repository README. This is a summary of what the repository states, not legal advice.

Editorial conclusion

Adopt it if your stack is PHP 8.4 and you want QR generation and decoding inside the same Composer dependency, with output modules you can extend. Do not adopt it if you are pinned to PHP 8.3 or older, or if you need a reader that works without ext-gd or ext-imagick. Before committing, verify three things: that your runtime satisfies PHP 8.4 with ext-mbstring, that the examples you copy come from the branch matching your installed version, and that the output module you intend to use has its optional extension installed. The README's own warning is the one to take literally: the main branch is active development for future major versions and is most likely incompatible with the latest release versions.

Frequently asked questions

What PHP version does chillerlan/php-qrcode require?

PHP 8.4 or newer, with ext-mbstring required. GD and ImageMagick are optional for generation but one of them is mandatory for the reader.

How do I install chillerlan/php-qrcode?

Through Composer, with the command composer require chillerlan/php-qrcode. The README also shows a composer.json form using a dev-main reference with a commit hash, which it says to replace with a version constraint such as ^6.0.

Can chillerlan/php-qrcode render SVG instead of a raster image?

Yes. SVG is listed among the built-in markup output types, alongside HTML, and the examples directory contains SVG-related files including SVGConvert.js and imagickConvertSVGtoPNG.php.

Does chillerlan/php-qrcode include a QR code reader?

It does. The reader is based on a PHP port of the ZXing library, and the README states that either ext-gd or ext-imagick is required for it.

How do I generate my own QR Ph?

In PHP, the README's quickstart is a single expression: (new QRCode)->render($data) returns a data URI you can drop into an img tag's src attribute. The example payload is an otpauth:// URI for a mobile authenticator.

Official sources

  1. chillerlan/php-qrcode on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/chillerlan-php-qrcode.svg)](https://hysenlabs.com/projects/chillerlan-php-qrcode)