PHPackages                             crazy-goat/scanmephp - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. crazy-goat/scanmephp

ActiveComposer-plugin[Utility &amp; Helpers](/categories/utility)

crazy-goat/scanmephp
====================

Pure PHP QR code generator with zero dependencies

v0.4.11(4mo ago)071[4 issues](https://github.com/crazy-goat/ScanMePHP/issues)MITPHPPHP &gt;=8.1CI passing

Since Mar 16Pushed 4mo agoCompare

[ Source](https://github.com/crazy-goat/ScanMePHP)[ Packagist](https://packagist.org/packages/crazy-goat/scanmephp)[ Docs](https://github.com/crazy-goat/ScanMePHP)[ RSS](/packages/crazy-goat-scanmephp/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (3)Versions (19)Used By (0)

ScanMePHP
=========

[](#scanmephp)

**The fastest pure PHP QR code generator with optional native C++ acceleration.**

Generate QR codes in PHP without dependencies — then go **10× faster** with a single C++ library. Zero bloat, maximum speed, production-ready.

QR encoding algorithms are based on [Nayuki's QR Code generator](https://www.nayuki.io/page/qr-code-generator-library).

Why ScanMePHP?
--------------

[](#why-scanmephp)

**🚀 Blazing Fast — 3-Tier Performance**

- **Native C++ via FFI**: 10–12× faster than pure PHP (sub-millisecond generation)
- **64-bit Optimized**: 2× faster with int-pair bit packing (no extensions needed)
- **Portable Fallback**: Works on any PHP 8.1+, 32-bit or 64-bit

Auto-selects the fastest encoder available — no configuration needed.

**📦 Zero Dependencies**

- No Composer packages to install
- No GD, Imagick, or extensions required
- Single `composer require`, instant QR codes

**🎨 8 Output Formats**SVG, PNG (pure PHP, 1-bit), HTML (div/table), ASCII (3 styles). Works in terminals, browsers, emails, and print.

**🔧 Full QR Spec Support**

- All versions v1–v40 (17 to 2953 bytes)
- All error correction levels (L/M/Q/H)
- Custom styling, colors, labels, dark mode

Features
--------

[](#features)

- **Zero dependencies** — no external packages, no PHP extensions required
- **8 built-in renderers** — SVG, PNG, HTML (div/table), ASCII (full/half/simple blocks)
- **All QR versions** — v1–v40, all error correction levels (L/M/Q/H)
- **High performance** — 3 encoder tiers: native C++ FFI (10–12× faster), FastEncoder (2×), portable Encoder
- **Customizable** — module styles, colors, labels, dark mode, margins
- **Type-safe** — strict types, enums, readonly properties, PHP 8.1+ idioms

Installation
------------

[](#installation)

```
composer require crazy-goat/scanmephp
```

Binary Auto-Download
--------------------

[](#binary-auto-download)

When you install or update the package via Composer, the library will automatically:

1. Detect your platform (Linux glibc/musl, macOS Intel/ARM, Windows)
2. Try to download and install the PHP extension (`scanmeqr`) — **fastest option** (13–21× faster)
3. Fall back to FFI library if extension is not available — **10–12× faster**
4. Use pure PHP encoder as final fallback — works everywhere

### PHP Extension Installation (Recommended)

[](#php-extension-installation-recommended)

The PHP extension provides the best performance. The Composer plugin will attempt to download it automatically.

#### Auto-Download

[](#auto-download)

During `composer install` or `composer update`, the plugin will:

1. Check if the `scanmeqr` extension is already loaded
2. Download the appropriate prebuilt binary for your platform
3. Provide instructions to enable it in `php.ini`

#### Manual Installation

[](#manual-installation)

1. Download the appropriate binary from [GitHub Releases](https://github.com/crazy-goat/ScanMePHP/releases):

PlatformPHP 8.1PHP 8.2PHP 8.3PHP 8.4Linux (glibc)`php-ext-linux-glibc-x86_64-php81.so``php-ext-linux-glibc-x86_64-php82.so``php-ext-linux-glibc-x86_64-php83.so``php-ext-linux-glibc-x86_64-php84.so`Linux (musl/Alpine)`php-ext-linux-musl-x86_64-php81.so``php-ext-linux-musl-x86_64-php82.so``php-ext-linux-musl-x86_64-php83.so``php-ext-linux-musl-x86_64-php84.so`macOS Intel`php-ext-macos-x86_64-php81.so``php-ext-macos-x86_64-php82.so``php-ext-macos-x86_64-php83.so``php-ext-macos-x86_64-php84.so`macOS Apple Silicon`php-ext-macos-arm64-php81.so``php-ext-macos-arm64-php82.so``php-ext-macos-arm64-php83.so``php-ext-macos-arm64-php84.so`> **Note:** Binaries are built for specific PHP versions due to ABI compatibility. Make sure to download the binary matching your PHP version (check with `php -v`).

2. Copy to your PHP extensions directory:

    ```
    cp php-ext-linux-glibc-x86_64.so $(php-config --extension-dir)/
    ```
3. Add to your `php.ini`:

    ```
    extension=scanmeqr.so
    ```
4. Restart your web server or PHP-FPM:

    ```
    sudo systemctl restart php-fpm
    # or
    sudo systemctl restart apache2
    ```
5. Verify installation:

    ```
    php -m | grep scanmeqr
    ```

#### Building from Source

[](#building-from-source)

Requirements:

- PHP 8.1+ with `php-dev`/`phpize`
- CMake 3.10+
- C++ compiler (g++ or clang++)
- Make

```
# Build the C++ library first
cd clib
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
cd ..

# Build the PHP extension
cd php-ext
phpize
./configure --with-scanmeqr="$PWD/../clib"
make -j$(nproc)
make install
cd ..
```

Then add `extension=scanmeqr.so` to your `php.ini`.

### FFI Library Installation

[](#ffi-library-installation)

If the PHP extension is not available, the plugin will download the FFI library instead.

#### Requirements for Auto-Download

[](#requirements-for-auto-download)

- FFI extension (`extension=ffi` in php.ini)
- cURL extension for downloading
- Write permissions to `ffi-binaries/` directory in your project

#### Manual Binary Installation

[](#manual-binary-installation)

If auto-download doesn't work, you can manually download binaries from the [GitHub releases page](https://github.com/crazy-goat/scanmephp/releases) and place them in your project directory.

Prebuilt FFI library binaries are available for:

PlatformBinaryLinux (glibc)`libscanme_qr-linux-glibc-x86_64.so`Linux (musl/Alpine)`libscanme_qr-linux-musl-x86_64.so`macOS Intel`libscanme_qr-macos-x86_64.dylib`macOS Apple Silicon`libscanme_qr-macos-arm64.dylib`Windows x86\_64`scanme_qr-windows-x86_64.dll`Quick Start
-----------

[](#quick-start)

```
use CrazyGoat\ScanMePHP\QRCode;

$qr = new QRCode('https://example.com');
echo $qr->render();
```

Renderers
---------

[](#renderers)

ScanMePHP ships with 8 renderers. Each implements `RendererInterface` and can be passed as the `engine` parameter.

RendererOutputConstructor Options`FullBlocksRenderer`ASCII `█` blocks`sideMargin` (int, default: 0)`HalfBlocksRenderer`ASCII `▀▄█` compact`sideMargin` (int, default: 0)`SimpleRenderer`ASCII `●` dots`sideMargin` (int, default: 0)`SvgRenderer`SVG XML`moduleSize` (int, default: 10)`PngRenderer`PNG image (1-bit)`moduleSize` (int, default: 10)`HtmlDivRenderer`HTML `` grid`moduleSize` (int, default: 10), `fullHtml` (bool, default: false)`HtmlTableRenderer`HTML ```moduleSize` (int, default: 10), `fullHtml` (bool, default: false)### ASCII — FullBlocksRenderer (default)

[](#ascii--fullblocksrenderer-default)

**Example:** [qrcode\_fullblocks.txt](examples/generated-assets/qrcode_fullblocks.txt)

```
use CrazyGoat\ScanMePHP\QRCode;
use CrazyGoat\ScanMePHP\QRCodeConfig;
use CrazyGoat\ScanMePHP\Renderer\FullBlocksRenderer;

$config = new QRCodeConfig(
    engine: new FullBlocksRenderer(sideMargin: 4),
    label: 'ScanMePHP',
);
$qr = new QRCode('https://example.com', $config);
echo $qr->render();
```

### ASCII — HalfBlocksRenderer

[](#ascii--halfblocksrenderer)

**Example:** [qrcode\_halfblocks.txt](examples/generated-assets/qrcode_halfblocks.txt)

Compact output — two rows per character using `▀▄█` half-block characters.

```
use CrazyGoat\ScanMePHP\Renderer\HalfBlocksRenderer;

$config = new QRCodeConfig(
    engine: new HalfBlocksRenderer(sideMargin: 4),
);
```

### ASCII — SimpleRenderer

[](#ascii--simplerenderer)

**Example:** [qrcode\_simple.txt](examples/generated-assets/qrcode_simple.txt)

Uses `●` dots. Works in terminals without full Unicode block support.

```
use CrazyGoat\ScanMePHP\Renderer\SimpleRenderer;

$config = new QRCodeConfig(
    engine: new SimpleRenderer(sideMargin: 4),
);
```

### SVG — SvgRenderer

[](#svg--svgrenderer)

**Examples:** [qrcode.svg](examples/generated-assets/qrcode.svg) | [qrcode\_rounded.svg](examples/generated-assets/qrcode_rounded.svg) | [qrcode\_dark.svg](examples/generated-assets/qrcode_dark.svg) | [qrcode\_with\_label.svg](examples/generated-assets/qrcode_with_label.svg)

```
use CrazyGoat\ScanMePHP\Renderer\SvgRenderer;
use CrazyGoat\ScanMePHP\ModuleStyle;

$config = new QRCodeConfig(
    engine: new SvgRenderer(moduleSize: 12),
    moduleStyle: ModuleStyle::Rounded, // Square, Rounded, or Dot
    label: 'Scan Me!',
);
$qr = new QRCode('https://example.com', $config);
$qr->saveToFile('qrcode.svg');
```

### PNG — PngRenderer

[](#png--pngrenderer)

**Examples:** [qrcode.png](examples/generated-assets/qrcode.png) | [qrcode\_small.png](examples/generated-assets/qrcode_small.png) | [qrcode\_large.png](examples/generated-assets/qrcode_large.png) | [qrcode\_high\_ecc.png](examples/generated-assets/qrcode_high_ecc.png)

Generates valid PNG files in pure PHP — no GD, no Imagick, no external libraries. Black and white only, 1-bit monochrome. Ideal for email attachments, API responses, and print.

> **Note:** Labels are not supported in PNG output (no font engine). Passing a `label` will throw a `RenderException`.

```
use CrazyGoat\ScanMePHP\Renderer\PngRenderer;

$config = new QRCodeConfig(
    engine: new PngRenderer(moduleSize: 10),
);
$qr = new QRCode('https://example.com', $config);
$qr->saveToFile('qrcode.png');

// Or use as data URI (e.g. in  tags)
$dataUri = $qr->getDataUri(); // data:image/png;base64,...
```

### HTML — HtmlDivRenderer

[](#html--htmldivrenderer)

**Examples:** [qrcode\_div.html](examples/generated-assets/qrcode_div.html) | [qrcode\_div\_full.html](examples/generated-assets/qrcode_div_full.html) | [qrcode\_div\_inverted.html](examples/generated-assets/qrcode_div_inverted.html) | [qrcode\_div\_label.html](examples/generated-assets/qrcode_div_label.html)

Renders QR as a `` flexbox grid with inline styles. No external CSS needed.

```
use CrazyGoat\ScanMePHP\Renderer\HtmlDivRenderer;

$config = new QRCodeConfig(
    engine: new HtmlDivRenderer(moduleSize: 10, fullHtml: false),
    label: 'ScanMePHP',
);
$qr = new QRCode('https://example.com', $config);

// Fragment only (for embedding)
$html = $qr->render();

// Full HTML page
$config = new QRCodeConfig(
    engine: new HtmlDivRenderer(fullHtml: true),
);
```

### HTML — HtmlTableRenderer

[](#html--htmltablerenderer)

**Examples:** [qrcode\_table.html](examples/generated-assets/qrcode_table.html) | [qrcode\_table\_full.html](examples/generated-assets/qrcode_table_full.html) | [qrcode\_table\_inverted.html](examples/generated-assets/qrcode_table_inverted.html) | [qrcode\_table\_label.html](examples/generated-assets/qrcode_table_label.html)

Same as above but uses `` with `` elements.

```
use CrazyGoat\ScanMePHP\Renderer\HtmlTableRenderer;

$config = new QRCodeConfig(
    engine: new HtmlTableRenderer(moduleSize: 8, fullHtml: true),
);
```

Configuration
-------------

[](#configuration)

All options are set via `QRCodeConfig`:

```
use CrazyGoat\ScanMePHP\QRCodeConfig;
use CrazyGoat\ScanMePHP\ErrorCorrectionLevel;
use CrazyGoat\ScanMePHP\ModuleStyle;
use CrazyGoat\ScanMePHP\Renderer\SvgRenderer;

$config = new QRCodeConfig(
    engine: new SvgRenderer(),                          // renderer instance
    errorCorrectionLevel: ErrorCorrectionLevel::Medium,  // Low, Medium, Quartile, High
    label: 'My QR Code',                                // optional label below QR
    size: 0,                                             // QR version 1-40, 0 = auto
    margin: 4,                                           // quiet zone in modules
    foregroundColor: '#000000',
    backgroundColor: '#FFFFFF',
    moduleStyle: ModuleStyle::Square,                    // Square, Rounded, Dot (SVG only)
    invert: false,                                       // swap foreground/background
);
```

Dark Mode (Inverted)
--------------------

[](#dark-mode-inverted)

```
$config = new QRCodeConfig(
    engine: new FullBlocksRenderer(sideMargin: 4),
    invert: true,
    label: 'Dark Mode',
);
```

For SVG/HTML renderers, set explicit colors:

```
$config = new QRCodeConfig(
    engine: new SvgRenderer(),
    invert: true,
    foregroundColor: '#FFFFFF',
    backgroundColor: '#000000',
);
```

Output Methods
--------------

[](#output-methods)

```
$qr = new QRCode('https://example.com', $config);

$qr->render();              // returns string
$qr->saveToFile('qr.svg');  // writes to file
$qr->getDataUri();          // data:image/svg+xml;base64,...
$qr->toBase64();            // raw base64
$qr->toHttpResponse();      // sends Content-Type header, outputs, exits
$qr->getMatrix();           // raw Matrix object
$qr->validate();            // true if data fits in QR version
echo $qr;                   // __toString() calls render()
```

Custom Renderer
---------------

[](#custom-renderer)

Implement `RendererInterface`:

```
use CrazyGoat\ScanMePHP\RendererInterface;
use CrazyGoat\ScanMePHP\Matrix;
use CrazyGoat\ScanMePHP\RenderOptions;

class MyCustomRenderer implements RendererInterface
{
    public function render(Matrix $matrix, RenderOptions $options): string
    {
        $size = $matrix->getSize();
        for ($y = 0; $y < $size; $y++) {
            for ($x = 0; $x < $size; $x++) {
                $isDark = $matrix->get($x, $y);
                // ... your rendering logic
            }
        }
        return $output;
    }

    public function getContentType(): string
    {
        return 'text/plain';
    }
}
```

Performance
-----------

[](#performance)

ScanMePHP includes four encoder implementations. `QRCode` auto-selects the fastest available:

EncoderVersionsRequirementsRelative Speed`NativeEncoderExt`v1–v2764-bit PHP + `scanmeqr` extension**13–21×** faster`FfiEncoder`v1–v4064-bit PHP + FFI + `libscanme_qr.so`**10–12×** faster`FastEncoder`v1–v2764-bit PHP**~2×** faster`Encoder`v1–v40any PHP 8.1+baseline### Capacity (Byte Mode)

[](#capacity-byte-mode)

Maximum data length for URL/text encoding (Byte mode) at different QR versions:

VersionSizeL (Low)M (Medium)Q (Quartile)H (High)v121×211714117v1057×57271213151119v27125×12514651125805625v40177×177**2953****2331****1663****1273****Note:** FastEncoder and FfiEncoder support up to v27 (1465 bytes max). For larger data, the portable Encoder (v1–v40) is automatically used.

### Benchmark Results

[](#benchmark-results)

Measured on PHP 8.4, 200 iterations per case, median latency:

Test caseEncoderFastEncoderFfiEncoderSpeedup (Encoder/FFI)v1 (21×21) L0.72 ms0.38 ms0.07 ms**10×**v2 (25×25) M1.03 ms0.52 ms0.10 ms**10×**v5 (37×37) M2.48 ms1.18 ms0.25 ms**10×**v10 (57×57) M7.71 ms3.35 ms0.75 ms**10×**All three encoders produce identical, spec-compliant QR codes verified against [nayuki's reference implementation](https://www.nayuki.io/page/qr-code-generator-library).

Run the benchmark yourself:

```
php bench/benchmark_encoder.php        # 200 iterations
php bench/benchmark_encoder.php 500    # 500 iterations
```

See [BENCHMARK.md](BENCHMARK.md) for full results with percentiles.

### Building the C++ Library (optional)

[](#building-the-c-library-optional)

The native C++ encoder is optional — ScanMePHP works without it. To enable `FfiEncoder`:

```
cmake -B clib/build -S clib -DCMAKE_BUILD_TYPE=Release
cmake --build clib/build -j$(nproc)
cp clib/build/libscanme_qr.so .
```

Then pass the library path when creating the encoder:

```
use CrazyGoat\ScanMePHP\FfiEncoder;

$encoder = new FfiEncoder(__DIR__ . '/libscanme_qr.so');
$qr = new QRCode('https://example.com', encoder: $encoder);
```

Or let `QRCode` auto-detect it (looks for `clib/build/libscanme_qr.so` in the project root).

### Prebuilt Binaries

[](#prebuilt-binaries)

Prebuilt binaries are available from [GitHub Releases](https://github.com/crazy-goat/ScanMePHP/releases). Download the appropriate binary for your platform:

#### PHP Extension Binaries (Recommended)

[](#php-extension-binaries-recommended)

PlatformBinaryDownloadLinux (glibc)`php-ext-linux-glibc-x86_64.so`[Latest Release](../../releases/latest)Linux (musl/Alpine)`php-ext-linux-musl-x86_64.so`[Latest Release](../../releases/latest)macOS Intel`php-ext-macos-x86_64.so`[Latest Release](../../releases/latest)macOS Apple Silicon`php-ext-macos-arm64.so`[Latest Release](../../releases/latest)#### FFI Library Binaries

[](#ffi-library-binaries)

PlatformBinaryDownloadLinux (glibc)`libscanme_qr-linux-glibc-x86_64.so`[Latest Release](../../releases/latest)Linux (musl/Alpine)`libscanme_qr-linux-musl-x86_64.so`[Latest Release](../../releases/latest)macOS Intel`libscanme_qr-macos-x86_64.dylib`[Latest Release](../../releases/latest)macOS Apple Silicon`libscanme_qr-macos-arm64.dylib`[Latest Release](../../releases/latest)Windows x86\_64`scanme_qr-windows-x86_64.dll`[Latest Release](../../releases/latest)Place the downloaded binary in your project directory. The `FfiEncoder` will automatically detect and load it.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.1
- No extensions required
- No external dependencies
- Optional: C++20 compiler + CMake for native FFI encoder

Testing
-------

[](#testing)

```
composer test
```

Examples
--------

[](#examples)

See the `examples/` directory. Run any example:

```
php examples/ascii_fullblocks.php
php examples/svg_example.php
php examples/png_example.php
php examples/html_div.php
php examples/html_table.php
```

Generated output files are saved to `examples/generated-assets/`.

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

34

—

LowBetter than 74% of packages

Maintenance74

Regular maintenance activity

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

15

Last Release

144d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/26042352?v=4)[Crazy Goat Software](/maintainers/crazy-goat)[@crazy-goat](https://github.com/crazy-goat)

---

Top Contributors

[![s2x](https://avatars.githubusercontent.com/u/196585?v=4)](https://github.com/s2x "s2x (15 commits)")

---

Tags

phpqrcodeqrgeneratorbarcode

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/crazy-goat-scanmephp/health.svg)

```
[![Health](https://phpackages.com/badges/crazy-goat-scanmephp/health.svg)](https://phpackages.com/packages/crazy-goat-scanmephp)
```

###  Alternatives

[endroid/qr-code

Endroid QR Code

4.8k76.5M530](/packages/endroid-qr-code)[tuncaybahadir/quar

A simple QR Code generation tool for your projects with Laravel 10, 11, 12, 13 versions, php 8.2, 8.3, 8.4 and 8.5

82133.8k6](/packages/tuncaybahadir-quar)[akira/laravel-qrcode

A clean, modern, and easy-to-use QR code generator for Laravel

497.2k](/packages/akira-laravel-qrcode)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
