PHP code example of bitdreamit / laravel-qz-tray

1. Go to this page and download the library: Download bitdreamit/laravel-qz-tray library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

bitdreamit / laravel-qz-tray example snippets


return [

    // Paths where the auto-generated certificate and key are stored
    'cert_path' => storage_path('qz/digital-certificate.txt'),
    'key_path'  => storage_path('qz/private-key.pem'),
    'cert_ttl'  => 3600, // seconds the browser may cache the cert

    // Certificate generation settings
    'certificate' => [
        'validity_days' => 7300,      // ~20 years
        'algorithm'     => 'sha256',
        'key_bits'      => 2048,
        'subject' => [
            'countryName'      => 'US',
            'organizationName' => 'My Company',
            'commonName'       => 'My App QZ Tray',
            'emailAddress'     => '[email protected]',
        ],
    ],

    // Auto-generate on first boot (safe for development, use artisan in production)
    'auto_generate_cert' => env('QZ_AUTO_GENERATE_CERT', false),

    // Allow HTTP endpoint to generate cert (disabled by default — security risk)
    'allow_public_cert_generate' => env('QZ_ALLOW_PUBLIC_CERT_GENERATE', false),

    // Default printer name (optional — users can pick via modal)
    'default_printer'           => env('QZ_DEFAULT_PRINTER'),
    'allow_printer_switch'      => true,
    'remember_printer_per_page' => true,   // Remember per URL path
    'printer_cache_duration'    => 86400,  // seconds (24 hours)

    // v1.1.0+: which identity wins when a request matches more than one
    // (device UUID, authenticated user, session)? 'device' first is correct
    // for shared/kiosk workstations where the physical machine — not who's
    // logged in — determines the printer. Use ['user', 'device', 'session']
    // if printer choice should follow a person between machines instead.
    'identity_priority' => ['device', 'user', 'session'],

    // v1.1.1+: primary key type for qz_print_jobs. Read at migration time —
    // set BEFORE first `php artisan migrate`. 'uuid' (default): id is a
    // uuid, safe to hand straight to the client (used as-is by
    // GET /qz/jobs and DELETE /qz/jobs/{id}). 'bigint': plain
    // auto-increment id.
    'id_type' => env('QZ_JOB_ID_TYPE', 'uuid'),

    // v1.1.3+: 'v7' (default) — time-ordered uuid, much better DB index
    // locality than v4 for a write-heavy table (v4 scatters inserts
    // randomly across the B-tree; v7's leading timestamp keeps them
    // appending near the end). Falls back to v4 automatically on Laravel
    // 10.x (no native Str::uuid7()) or if generation fails for any reason.
    'uuid_version' => env('QZ_UUID_VERSION', 'v7'),

    // QZ Tray WebSocket connection
    'websocket' => [
        'host'    => env('QZ_WEBSOCKET_HOST', 'localhost'),
        'port'    => env('QZ_WEBSOCKET_PORT', 8181),  // QZ Tray default
        'retries' => 1,
        'timeout' => 10,
    ],

    // Browser fallback when QZ Tray is not running
    'fallback' => [
        'enabled'         => true,   // Open browser print dialog as fallback
        'open_in_new_tab' => true,
        'show_warning'    => true,
    ],

    // Keyboard shortcut to open printer selector
    'hotkey' => [
        'enabled'     => true,
        'combination' => 'ctrl+shift+p',
    ],

    // Route configuration
    'routes' => [
        'prefix'     => 'qz',        // All routes: /qz/...
        'middleware' => ['web'],      // Add 'auth' here to protect routes
        'throttle'   => '60,1',
    ],

    // Print job logging
    'logging' => [
        'enabled' => env('QZ_LOGGING_ENABLED', false),
        'channel' => env('QZ_LOGGING_CHANNEL', 'stack'),
        'level'   => env('QZ_LOGGING_LEVEL', 'info'),
    ],

];

// config/qz-tray.php
'routes' => [
    'prefix'     => 'qz',
    'middleware' => ['web', 'auth'],  // Require login
],

'certificate' => [
    'validity_days' => 7300,
    'algorithm'     => 'sha256',
    'key_bits'      => 2048,
    'subject' => [
        'countryName'            => 'GB',         // ISO country code
        'stateOrProvinceName'    => 'London',
        'localityName'           => 'London',
        'organizationName'       => 'Acme Corp',
        'organizationalUnitName' => 'IT Department',
        'commonName'             => 'Acme Print Service',
        'emailAddress'           => '[email protected]',
    ],
],

// routes/console.php (Laravel 11+) or app/Console/Kernel.php's schedule() method
Schedule::command('qz:prune-preferences --older-than=90')->weekly();

// routes/web.php
Route::get('/invoices/{invoice}/pdf', function (Invoice $invoice) {
    $pdf = PDF::loadView('invoices.pdf', compact('invoice'));
    return $pdf->stream('invoice-'.$invoice->number.'.pdf');
})->name('invoices.pdf');

Route::get('/api/labels/{product}/zpl', function (Product $product) {
    $zpl = "^XA\n"
         . "^FO50,50^ADN,36,20^FD{$product->name}^FS\n"
         . "^FO50,100^BCN,80,Y,N,N^FD{$product->barcode}^FS\n"
         . "^XZ";

    return response($zpl, 200, ['Content-Type' => 'text/plain']);
});

// Laravel controller
public function printReceipt(Order $order)
{
    $lines = [];
    $lines[] = "\x1B\x40";        // Init
    $lines[] = "\x1B\x61\x01";    // Center
    $lines[] = $order->store_name . "\n";
    $lines[] = "\x1B\x61\x00";    // Left

    foreach ($order->items as $item) {
        $lines[] = str_pad($item->name, 24) . str_pad('$'.$item->price, 8, ' ', STR_PAD_LEFT) . "\n";
    }

    $lines[] = "\n\n\n";
    $lines[] = "\x1D\x56\x41";    // Cut

    return response(implode('', $lines), 200, [
        'Content-Type' => 'application/octet-stream',
    ]);
}

// app/Http/Controllers/OrderController.php

public function store(Request $request)
{
    $order = Order::create($request->validated());

    // Return page with auto-print directive
    return view('orders.created', [
        'order'    => $order,
        'autoPrint' => true,
        'printUrl'  => route('orders.pdf', $order),
    ]);
}

return redirect()->route('orders.show', $order)
    ->with('auto_print', route('orders.pdf', $order));

use Illuminate\Support\Facades\DB;

$jobs = DB::table('qz_print_jobs')
    ->where('user_id', auth()->id())
    ->where('status', 'completed')
    ->orderByDesc('created_at')
    ->paginate(20);

// config/qz-tray.php
'logging' => [
    'enabled' => true,
    'channel' => 'daily',
    'level'   => 'info',
],

// POST /qz/print, POST /qz/printer — either param name works, same column.
// Must match config('qz-tray.id_type') — a bigint value on a uuid-configured
// install (or vice versa) fails validation.
[
    'tenant_id' => '482',                                     // id_type = 'bigint'
    'project_id' => 'b2b1f6c0-3b3d-4c9a-9e2e-1a2b3c4d5e6f',    // id_type = 'uuid'
]

// config/qz-tray.php
'tenant_id_resolver' => fn ($request) => auth()->user()?->tenant_id,

// or for a package like stancl/tenancy:
'tenant_id_resolver' => fn ($request) => tenant('id'),

$jobs = DB::table('qz_print_jobs')
    ->where('tenant_id', auth()->user()->tenant_id)
    ->where('status', 'completed')
    ->orderByDesc('created_at')
    ->paginate(20);

// config/qz-tray.php
'routes' => [
    'prefix'     => 'qz',
    'middleware' => ['web', 'auth'],  // Require authenticated user
],

'middleware' => ['web', 'auth', 'verified', 'role:printer'],

// config/qz-tray.php
'routes' => [
    'throttle' => '60,1',  // 60 requests per minute per IP
],

// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    // Do NOT add 'qz/sign' here
];
bash
composer qz:install          # publishes config, migrations, views, JS/CSS assets, generates your cert
php artisan migrate             # creates qz_print_jobs + qz_printer_preferences
bash
php artisan qz:install
bash
> php artisan qz:install --force
> 
bash
php artisan migrate
bash
php artisan vendor:publish --provider="Bitdreamit\QzTray\QzTrayServiceProvider"
bash
php artisan vendor:publish --tag=qz-assets --force
bash
php artisan qz:generate-certificate
bash
php artisan qz:generate-certificate --force

🔐 Generating QZ Tray certificate...
  Generating private key...
  Creating certificate signing request...
✅ Certificate generated successfully!
  📄 Certificate: /var/www/storage/qz/digital-certificate.txt
  🔑 Private key:  /var/www/storage/qz/private-key.pem
  ⏳ Validity: 7300 days (20 years)

📋 Certificate Details:
  Subject:     /C=US/O=My Company/CN=My App QZ Tray
  Valid From:  2025-01-01 00:00:00
  Valid Until: 2045-01-01 00:00:00
  Algorithm:   RSA
bash
php artisan qz:generate-certificate --force
bash
php artisan qz:generate-certificate
bash
php artisan qz:generate-certificate --force

src/
├── QzTrayServiceProvider.php           ← Registers routes, commands, views
├── Http/
│   └── Controllers/
│       └── QzSecurityController.php    ← All route handlers (security, printers, jobs, cache)
└── Console/
    └── Commands/
        ├── InstallQzTray.php           ← php artisan qz:install
        ├── GenerateCertificate.php     ← php artisan qz:generate-certificate
        ├── ClearQzCache.php            ← php artisan qz:clear-cache
        └── PrunePreferences.php        ← php artisan qz:prune-preferences
bash
   php artisan vendor:publish --tag=qz-assets --force
   php artisan vendor:publish --tag=qz-config --force
   
bash
   php artisan qz:generate-certificate --force
   
bash
   php artisan migrate