Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Qr Code Reader Laravel Package

libern/qr-code-reader

A PHP/Laravel library that reads and decodes QR codes from image files. Its simple API returns the decoded text, making it easy to scan uploaded or stored QR images in your app. Includes Laravel service provider integration and supports common image formats.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package

    composer require libern/qr-code-reader
    

    The package is a thin wrapper around a decoder binary/jar, so installation is only half the job — the runtime prerequisites matter more than the Composer step.

  2. Verify the runtime prerequisites before writing any code

    • The decoder is shelled out to, so exec()/shell_exec() must not be in disable_functions.
    • If your install depends on the ZXing Java CLI, the host needs a JRE: java -version. In Docker add default-jre-headless (Debian) or openjdk11-jre-headless (Alpine).
    • Confirm the package's bundled binary/jar is present under vendor/libern/qr-code-reader — deploy scripts that prune non-PHP files will break it.
  3. Look here first

    • src/QRCodeReader.php — the decode() method and how it builds the shell command. This tells you exactly what path format, quoting, and return values you get.
    • src/QRCodeReaderServiceProvider.php — whether it binds a singleton and whether auto-discovery (extra.laravel.providers) is set.
    • src/Facades/ — if a facade is shipped, alias it; otherwise resolve from the container.
  4. First use case — decode an uploaded image

    use Libern\QRCodeReader\QRCodeReader;
    
    $reader = app(QRCodeReader::class);
    $text = $reader->decode(storage_path('app/qr/inbound.png'));
    
    // Treat empty/null as "no QR found" — the package does not throw on failure.
    if (blank($text)) {
        abort(422, 'No QR code detected.');
    }
    
  5. Smoke-test with a known fixture before building features: generate a QR with simplesoftwareio/simple-qrcode or endroid/qr-code, decode it, assert round-trip. This immediately proves Java/exec/permissions are working.

Implementation Patterns

Wrap it in your own interface. The package exposes a concrete class, and you will want to swap it eventually (see Gotchas). Define App\Contracts\QrDecoder with decode(string $absolutePath): ?string and a ZXingQrDecoder adapter that delegates to QRCodeReader. Bind it in a service provider. Every call site then depends on your contract, not Libern\....

// AppServiceProvider::register()
$this->app->bind(QrDecoder::class, ZXingQrDecoder::class);

// ZXingQrDecoder
public function decode(string $path): ?string
{
    $result = trim((string) app(QRCodeReader::class)->decode($path));
    return $result === '' ? null : $result;
}

Controller flow for uploads. Validate (mimes:png,jpg,jpeg,gif, max:5120) → store on a private disk → decode by absolute path → unlink in finally. Never pass the client's original filename into the decoder.

public function store(DecodeQrRequest $request, QrDecoder $decoder)
{
    $path = $request->file('image')->store('qr/tmp', 'local');
    $absolute = Storage::disk('local')->path($path);
    try {
        $text = $decoder->decode($absolute);
        return $text ? response()->json(['text' => $text])
                     : response()->json(['error' => 'not found'], 422);
    } finally {
        Storage::disk('local')->delete($path);
    }
}

Push decoding to a queue. Each invocation spawns a process (and a JVM if Java-backed), costing hundreds of milliseconds. For user uploads or bulk imports, dispatch a DecodeQrCode job, then broadcast/notify. This keeps request latency flat and gives you retries and failure logging for free.

class DecodeQrCode implements ShouldQueue
{
    public int $tries = 2;
    public function __construct(public string $diskPath) {}
    public function handle(QrDecoder $decoder): void
    {
        $text = $decoder->decode(Storage::disk('local')->path($this->diskPath));
        QrDecoded::dispatch($this->diskPath, $text);
    }
}

Batch / artisan command. A php artisan qr:decode {path} command is invaluable for ops debugging and for importing a folder of images. Process files one by one and log failures rather than aborting the run.

Cache by content hash. sha1_file() → cache the decoded payload for an hour. Re-scanning the same uploaded asset (e.g., in a retry) then costs zero processes.

Temporary files for base64/data-URI payloads. Write bytes to tempnam(sys_get_temp_dir(), 'qr_'), decode, delete. Don't try to feed the decoder a data URI.

Round-trip testing. Use a generation library in tests to produce a QR, decode it, assert equality — this catches environment regressions (Java removed from CI image) that a mocked test would hide. Keep a checked-in fixture image for a fast unit-level test too.

Gotchas and Tips

  • The Java/exec dependency is the #1 failure point. Shared hosting commonly disables exec, and slim containers omit a JRE. Both fail silently — you get an empty string, not an exception. Add a health check and fail loudly at boot in non-production.
  • Silent failures. decode() returning empty could mean "no QR", "bad path", "java not found", or "non-zero exit". When debugging, reproduce the underlying command manually (java -jar … image.png) to separate package issues from environment issues. Wrap the call with your own logging of the raw output.
  • Shell quoting and user input. If the package's command construction is naive, spaces or Unicode in paths break decoding, and a crafted filename can be an injection vector. Always copy the upload to a randomized, sanitized filename under storage before decoding.
  • JVM startup cost dominates. Expect ~200–800 ms per decode. Never loop over dozens of images inside a web request; batch in a job or command. There is no warm JVM with the CLI invocation model.
  • Encoding. Non-ASCII payloads can come back mangled if the forked process isn't told to use UTF-8 (a -Dfile.encoding=UTF-8 flag on the Java side). Test with an accented/emoji payload, not just https://example.com.
  • Format limits. Raster images only; no PDF, no multi-page, no multi-symbol scanning. Large or high-resolution images can be slow or hit memory limits — downscale or reject oversized uploads.
  • Absolute paths only. Relative paths resolve against the PHP process CWD, not your app root. Use Storage::disk()->path() or storage_path().
  • No meaningful config to publish. The binary/jar location is effectively hardcoded relative to the package. This is why you must not strip vendor/libern/qr-code-reader during deploy, and why a fork is sometimes easier than fighting the path.
  • Maintenance risk. Last release was December 2020 with low activity. Pin the exact version in composer.json, run it against your PHP version in CI (PHP 8.1+ may surface deprecations), and keep the adapter layer so you can move to khanamiryan/qrcode-detector-decoder (pure PHP, ext-gd, no Java) or a hosted decoding API without touching call sites.
  • Treat decoded content as untrusted. A QR payload is attacker-controlled text. If you act on URLs (login-with-QR, redirects), validate the scheme and host; never redirect($text) directly.
  • Cross-platform drift. Dev on Windows and prod on Linux behave differently around quoting and path separators. Keep the command construction (or your adapter) tested in the same container you deploy.
  • Extension point. Laravel's container is your lever: rebind QrDecoder, alias the facade to your adapter, and optionally add a QrDecoder fake in tests so feature tests don't require a JRE at all.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource