Home Pemrograman / php / script

Setelah QR Code dan barcode berhasil dibuat, pekerjaan berikutnya adalah membaca kode tersebut dari aplikasi web.

Di bagian ini saya sempat mengira QR Code dan barcode bisa diperlakukan dengan cara yang sama. Ternyata setelah melihat dokumentasi library dan beberapa contoh implementasi scanner berbasis web, perangkat yang digunakan sangat menentukan cara kita menulis program.

QR Code dapat dibaca dari aliran video kamera menggunakan JavaScript. Sementara barcode scanner USB pada umumnya dapat bekerja sebagai keyboard wedge: hasil scan masuk ke elemen input seperti data yang diketik dari keyboard.

Karena itu, pada tutorial ini kita akan membuat satu halaman scanner dengan dua jalur input.

Yang akan kita buat:
QR Code dibaca menggunakan kamera browser dan Nimiq QR Scanner. Barcode 1D dibaca menggunakan scanner USB melalui input HTML. Hasil keduanya kemudian dikirim ke PHP.

Library QR Scanner yang Digunakan

Untuk membaca QR Code dari kamera browser, kita tetap menggunakan Nimiq QR Scanner.

Repository resminya menjelaskan bahwa library ini dapat membaca QR Code dari aliran video webcam dan dari file gambar. Demo resmi Nimiq juga memperlihatkan proses start dan stop scanner, pemilihan kamera, serta hasil QR yang terdeteksi.

Sumber library:

Nimiq QR Scanner di GitHub
Nimiq QR Scanner Releases
Demo Resmi Nimiq QR Scanner

Pada project yang sedang kita gunakan, library ditempatkan di:

C:\xampp\htdocs\absensi\libs\qr-scanner-master

File yang digunakan:

C:\xampp\htdocs\absensi\libs\qr-scanner-master\qr-scanner.min.js
C:\xampp\htdocs\absensi\libs\qr-scanner-master\qr-scanner-worker.min.js

Artikel ini sengaja mengikuti struktur file tersebut agar tetap sama dengan project sebelumnya.

Penting:
Nimiq QR Scanner pada tutorial ini digunakan untuk membaca QR Code. Untuk barcode 1D dari scanner USB, kita tidak memaksa kamera QR membaca barcode. Scanner USB ditangani sebagai input keyboard pada halaman HTML.

Kenapa Scanner QR dan Barcode Dipisahkan?

Kalau dilihat dari hasil akhirnya, keduanya memang sama-sama menghasilkan sebuah kode.

Misalnya:

RL000123

Namun cara kode tersebut masuk ke browser berbeda.

Scanner Cara Membaca Input ke Web
QR kamera Video kamera Callback JavaScript
Barcode scanner USB Laser/imager scanner Seperti keyboard

Panduan integrasi scanner USB dari IDAutomation menjelaskan penggunaan scanner dalam mode keyboard wedge untuk aplikasi. Microsoft juga mendokumentasikan konsep keyboard wedge sebagai cara memasukkan hasil scan pada posisi kursor seperti input keyboard.

Artinya, untuk barcode scanner USB kita cukup menyiapkan input yang selalu siap menerima hasil scan.

Struktur Folder Project

Contoh project kita masih berada di XAMPP:

C:\xampp\htdocs\absensi

Struktur sederhananya:

absensi
│
├── libs
│   └── qr-scanner-master
│       ├── qr-scanner.min.js
│       └── qr-scanner-worker.min.js
│
├── scanner.php
├── proses_scan.php
└── index.php

Kita akan membuat halaman utama scanner pada scanner.php.

File proses_scan.php digunakan untuk menerima kode dari browser.

Membuat Tampilan Scanner

Buat file:

scanner.php

Kita mulai dari HTML sederhana.

<div class="scanner-box">

    <h2>Scan QR Code</h2>

    <video id="qr-video"></video>

    <div id="hasil-qr">
        Belum ada QR terbaca
    </div>

</div>

<div class="scanner-box">

    <h2>Scan Barcode</h2>

    <input
        type="text"
        id="barcode-input"
        placeholder="Scan barcode di sini"
        autocomplete="off"
    >

    <div id="hasil-barcode">
        Belum ada barcode terbaca
    </div>

</div>

Ada dua area.

Elemen video digunakan untuk preview kamera QR.

Elemen input digunakan untuk menerima data dari barcode scanner USB.

Membuat Scanner QR Code dari Kamera Browser

Repository Nimiq menampilkan pola penggunaan QrScanner dengan elemen video dan callback hasil scan.

Tambahkan script berikut pada halaman:

<script type="module">

import QrScanner from "./libs/qr-scanner-master/qr-scanner.min.js";

const video = document.getElementById("qr-video");
const hasilQr = document.getElementById("hasil-qr");

const scanner = new QrScanner(
    video,
    result => {

        console.log("QR terbaca:", result.data);

        hasilQr.textContent = result.data;

    },
    {
        returnDetailedScanResult: true
    }
);

scanner.start();

</script>

Ketika QR terdeteksi, library menjalankan callback.

Jika isi QR adalah:

RL000123

maka:

result.data

akan berisi nilai tersebut.

Pada tahap pertama, jangan langsung menghubungkan scanner ke database. Tampilkan hasilnya di halaman atau console terlebih dahulu.

Urutan pengujian yang nyaman:
Pastikan kamera terbuka. Pastikan QR terdeteksi. Pastikan nilai muncul di halaman. Setelah tiga bagian tersebut bekerja, baru kirim hasil scan ke PHP.

Memilih Kamera Belakang pada Smartphone

Untuk aplikasi scanner, kamera belakang biasanya lebih nyaman digunakan daripada kamera depan.

Nimiq QR Scanner menyediakan opsi preferredCamera. Repository resminya memberikan contoh penggunaan nilai environment untuk memilih kamera belakang.

const scanner = new QrScanner(
    video,
    result => {
        console.log(result.data);
    },
    {
        preferredCamera: "environment",
        returnDetailedScanResult: true
    }
);

Browser dan perangkat tetap memiliki kendali atas kamera yang tersedia. Karena itu, hasil akhir perlu diuji pada smartphone atau tablet yang benar-benar akan digunakan.

Kamera Tidak Terbuka dari Browser

Ini salah satu masalah yang sering muncul pada implementasi scanner kamera web.

Browser menggunakan getUserMedia() untuk meminta akses kamera. Dokumentasi MDN menjelaskan bahwa fitur tersebut hanya tersedia pada secure context.

localhost dapat digunakan untuk pengembangan lokal.

Namun ketika aplikasi dibuka dari perangkat lain melalui alamat IP HTTP biasa, perilakunya dapat berbeda.

Contoh pengujian lokal:

http://localhost/absensi/scanner.php

Jika halaman akan dibuka dari tablet atau smartphone pada jaringan, pertimbangkan penggunaan HTTPS dan periksa izin kamera browser.

Sebelum membongkar kode, cek empat hal berikut:

  1. Apakah browser memberikan izin kamera?
  2. Apakah halaman berjalan pada secure context?
  3. Apakah path qr-scanner.min.js benar?
  4. Apakah perangkat memiliki kamera yang dapat digunakan browser?

Demo resmi Nimiq QR Scanner juga dapat digunakan sebagai pembanding untuk memastikan kamera dan browser perangkat dapat menjalankan scanner.

Mencegah QR yang Sama Diproses Berkali-kali

Video kamera berjalan terus. QR yang berada di depan kamera dapat terdeteksi lebih dari satu kali.

Ini tidak terlalu terasa ketika kita hanya menampilkan hasil ke console. Masalah mulai muncul ketika callback langsung mencatat absensi atau transaksi.

Kita dapat menyimpan hasil scan terakhir.

let qrTerakhir = "";
let waktuScanTerakhir = 0;

const scanner = new QrScanner(
    video,
    result => {

        const sekarang = Date.now();
        const kode = result.data;

        if (
            kode === qrTerakhir &&
            sekarang - waktuScanTerakhir < 3000
        ) {
            return;
        }

        qrTerakhir = kode;
        waktuScanTerakhir = sekarang;

        prosesKode(kode, "QR");

    },
    {
        preferredCamera: "environment",
        returnDetailedScanResult: true
    }
);

Pada contoh ini, QR yang sama diabaikan selama tiga detik.

Ini membantu di sisi antarmuka. Namun untuk aplikasi absensi atau transaksi, validasi duplikasi tetap harus dilakukan di server.

Membuat Scanner Barcode USB di HTML

Sekarang kita masuk ke barcode.

Untuk scanner USB yang bekerja seperti keyboard, kita tidak membutuhkan library kamera.

Kita membutuhkan Text Box yang menerima hasil scan.

<input
    type="text"
    id="barcode-input"
    placeholder="Scan barcode di sini"
    autocomplete="off"
>

Kemudian JavaScript mendengarkan tombol Enter.

const barcodeInput = document.getElementById("barcode-input");
const hasilBarcode = document.getElementById("hasil-barcode");

barcodeInput.addEventListener("keydown", function(event) {

    if (event.key === "Enter") {

        event.preventDefault();

        const kode = barcodeInput.value.trim();

        if (kode === "") {
            return;
        }

        hasilBarcode.textContent = kode;

        console.log("Barcode terbaca:", kode);

        barcodeInput.value = "";

    }

});

Banyak scanner dapat dikonfigurasi untuk mengirim suffix Enter setelah barcode berhasil dibaca.

Jika scanner Anda tidak mengirim Enter, event di atas tidak akan langsung berjalan. Periksa konfigurasi scanner atau gunakan strategi pembacaan input yang sesuai dengan perangkat.

Pastikan Input Barcode Selalu Fokus

Salah satu masalah yang sering terjadi pada halaman scanner barcode adalah fokus berpindah ke tombol atau area lain.

Akibatnya, scanner mengirim kode tetapi karakter masuk ke tempat yang salah.

Kita dapat mengembalikan fokus ke input barcode.

barcodeInput.focus();

document.addEventListener("click", function() {
    barcodeInput.focus();
});

Setelah barcode selesai diproses:

barcodeInput.value = "";
barcodeInput.focus();

Untuk aplikasi kiosk atau meja scan khusus, pola seperti ini cukup membantu.

Namun jika halaman memiliki banyak form yang harus diisi manual, jangan memaksa fokus kembali pada setiap klik. Sesuaikan dengan alur kerja halaman.

Menyatukan Hasil QR dan Barcode

Sampai tahap ini kita memiliki dua hasil.

QR kamera menghasilkan:

result.data

Barcode scanner menghasilkan:

barcodeInput.value

Keduanya sebenarnya dapat dikirim ke satu fungsi.

function prosesKode(kode, jenis) {

    console.log("Jenis:", jenis);
    console.log("Kode:", kode);

}

Pada QR scanner:

prosesKode(result.data, "QR");

Pada barcode scanner:

prosesKode(kode, "BARCODE");

Dengan pola ini, bagian yang mengirim data ke PHP tidak perlu ditulis dua kali.

Mengirim Hasil Scanner ke PHP

Sekarang ubah fungsi prosesKode().

function prosesKode(kode, jenis) {

    fetch("proses_scan.php", {
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        body:
            "kode=" + encodeURIComponent(kode) +
            "&jenis=" + encodeURIComponent(jenis)
    })
    .then(response => response.json())
    .then(data => {

        console.log(data);

    })
    .catch(error => {

        console.error("Terjadi kesalahan:", error);

    });

}

QR dan barcode sekarang menggunakan endpoint yang sama:

proses_scan.php

Membuat proses_scan.php

Buat file:

proses_scan.php

Isi contoh awal:

<?php

header('Content-Type: application/json');

$kode  = trim($_POST['kode'] ?? '');
$jenis = trim($_POST['jenis'] ?? '');

if ($kode === '') {

    echo json_encode([
        'status' => false,
        'message' => 'Kode kosong'
    ]);

    exit;
}

echo json_encode([
    'status' => true,
    'jenis' => $jenis,
    'kode' => $kode
]);

?>

Untuk tahap pengujian, PHP hanya mengembalikan data yang diterima.

Jika QR dipindai:

{
    "status": true,
    "jenis": "QR",
    "kode": "RL000123"
}

Jika barcode dipindai:

{
    "status": true,
    "jenis": "BARCODE",
    "kode": "RL000123"
}

Setelah alur ini bekerja, kita dapat menghubungkannya dengan database.

Mencari Data Berdasarkan Kode

Anggap kita memiliki tabel:

barang

Dengan field:

id_barang
kode_barang
nama_barang

Kita dapat mencari data berdasarkan kode.

SELECT id_barang, kode_barang, nama_barang
FROM barang
WHERE kode_barang = ?
LIMIT 1

Jika QR Code dan barcode menggunakan identitas yang sama, keduanya dapat menemukan barang yang sama.

Misalnya QR berisi:

RL000123

Barcode Code 39 juga merepresentasikan:

RL000123

Maka database tidak perlu memiliki field kode QR dan kode barcode yang berbeda hanya karena media scannya berbeda.

Prinsip yang saya sarankan:
Jika QR dan barcode memang digunakan untuk barang yang sama, pertahankan satu kode identitas. Kamera dan scanner hanyalah dua cara berbeda untuk memasukkan kode tersebut.

Contoh proses_scan.php dengan PDO

Setelah pengujian dasar berhasil, endpoint dapat dikembangkan menggunakan PDO dan prepared statement.

<?php

header('Content-Type: application/json');

$kode  = trim($_POST['kode'] ?? '');
$jenis = trim($_POST['jenis'] ?? '');

if ($kode === '') {

    echo json_encode([
        'status' => false,
        'message' => 'Kode kosong'
    ]);

    exit;
}

$pdo = new PDO(
    'mysql:host=localhost;dbname=absensi;charset=utf8mb4',
    'root',
    ''
);

$pdo->setAttribute(
    PDO::ATTR_ERRMODE,
    PDO::ERRMODE_EXCEPTION
);

$stmt = $pdo->prepare(
    'SELECT id_barang, kode_barang, nama_barang
     FROM barang
     WHERE kode_barang = ?
     LIMIT 1'
);

$stmt->execute([$kode]);

$barang = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$barang) {

    echo json_encode([
        'status' => false,
        'message' => 'Data tidak ditemukan'
    ]);

    exit;
}

echo json_encode([
    'status' => true,
    'jenis' => $jenis,
    'data' => $barang
]);

?>

Prepared statement digunakan agar nilai hasil scan tidak ditempel langsung ke string SQL.

Jangan menganggap isi QR atau barcode selalu aman hanya karena kode dibuat oleh aplikasi kita. Endpoint tetap harus memvalidasi input.

Menampilkan Hasil Scan di Halaman

Supaya petugas tidak harus membuka console browser, tampilkan hasil dari PHP.

function prosesKode(kode, jenis) {

    fetch("proses_scan.php", {
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        body:
            "kode=" + encodeURIComponent(kode) +
            "&jenis=" + encodeURIComponent(jenis)
    })
    .then(response => response.json())
    .then(data => {

        const hasil = document.getElementById("hasil-scan");

        if (!data.status) {

            hasil.innerHTML =
                "<strong>Gagal:</strong> " +
                data.message;

            return;
        }

        hasil.innerHTML =
            "<strong>" +
            data.data.kode_barang +
            "</strong><br>" +
            data.data.nama_barang;

    });

}

Tambahkan area hasil:

<div id="hasil-scan">
    Silakan scan QR Code atau barcode
</div>

Sekarang satu halaman dapat menerima QR dari kamera atau barcode dari scanner USB.

Contoh scanner.php yang Lebih Lengkap

Berikut contoh yang menggabungkan bagian utama scanner.

<!DOCTYPE html>
<html lang="id">

<head>

    <meta charset="UTF-8">

    <meta
        name="viewport"
        content="width=device-width, initial-scale=1"
    >

    <title>Scanner QR dan Barcode</title>

</head>

<body>

    <h1>Scanner QR dan Barcode</h1>

    <h2>Kamera QR</h2>

    <video
        id="qr-video"
        style="width:100%;max-width:500px"
    ></video>

    <h2>Barcode Scanner</h2>

    <input
        type="text"
        id="barcode-input"
        placeholder="Scan barcode"
        autocomplete="off"
    >

    <hr>

    <div id="hasil-scan">
        Silakan scan QR Code atau barcode
    </div>

    <script type="module">

    import QrScanner
    from "./libs/qr-scanner-master/qr-scanner.min.js";

    const video =
        document.getElementById("qr-video");

    const barcodeInput =
        document.getElementById("barcode-input");

    const hasil =
        document.getElementById("hasil-scan");

    let qrTerakhir = "";
    let waktuScanTerakhir = 0;

    function prosesKode(kode, jenis) {

        fetch("proses_scan.php", {
            method: "POST",
            headers: {
                "Content-Type":
                "application/x-www-form-urlencoded"
            },
            body:
                "kode=" + encodeURIComponent(kode) +
                "&jenis=" + encodeURIComponent(jenis)
        })
        .then(response => response.json())
        .then(data => {

            if (!data.status) {

                hasil.textContent = data.message;

                return;
            }

            hasil.innerHTML =
                "<strong>" +
                data.data.kode_barang +
                "</strong><br>" +
                data.data.nama_barang;

        });

    }

    const scanner = new QrScanner(
        video,
        result => {

            const kode = result.data;
            const sekarang = Date.now();

            if (
                kode === qrTerakhir &&
                sekarang - waktuScanTerakhir < 3000
            ) {
                return;
            }

            qrTerakhir = kode;
            waktuScanTerakhir = sekarang;

            prosesKode(kode, "QR");

        },
        {
            preferredCamera: "environment",
            returnDetailedScanResult: true
        }
    );

    scanner.start();

    barcodeInput.addEventListener(
        "keydown",
        function(event) {

            if (event.key !== "Enter") {
                return;
            }

            event.preventDefault();

            const kode =
                barcodeInput.value.trim();

            if (kode === "") {
                return;
            }

            prosesKode(kode, "BARCODE");

            barcodeInput.value = "";
            barcodeInput.focus();

        }
    );

    </script>

</body>

</html>

Contoh ini sengaja dibuat sederhana. Tujuannya agar alur QR, barcode, dan PHP terlihat jelas.

Kesalahan yang Sering Terjadi

Menganggap Nimiq QR Scanner membaca semua barcode

Library yang kita gunakan di sini adalah QR scanner. Artikel ini tidak menggunakan Nimiq untuk membaca Code 39 dari kamera.

Barcode 1D diterima dari scanner USB sebagai input keyboard.

Langsung memasukkan hasil scan ke database

Uji nilai scan terlebih dahulu.

Tampilkan di console atau halaman.

Pastikan nilai:

RL000123

benar-benar diterima sebagai:

RL000123

Setelah itu baru jalankan query database.

QR diproses berulang kali

Kamera dapat membaca QR yang sama berkali-kali selama kode masih berada di depan kamera.

Gunakan jeda di sisi JavaScript dan validasi duplikasi di server.

Barcode scanner tidak mengirim Enter

Contoh JavaScript kita memproses barcode ketika tombol Enter diterima.

Periksa suffix scanner. Setiap perangkat dapat memiliki konfigurasi yang berbeda.

Kamera bekerja di localhost tetapi tidak di tablet

Periksa secure context dan izin kamera. Dokumentasi MDN untuk getUserMedia() menjelaskan persyaratan secure context.

Urutan Pengujian yang Saya Sarankan

Setelah membaca dokumentasi library dan beberapa pembahasan integrasi scanner, saya lebih menyukai pengujian bertahap.

  1. Buka demo resmi Nimiq QR Scanner pada perangkat.
  2. Pastikan kamera dapat membaca QR.
  3. Jalankan scanner.php.
  4. Tampilkan hasil QR di console.
  5. Uji barcode scanner di Notepad.
  6. Uji barcode scanner pada input HTML.
  7. Satukan QR dan barcode ke fungsi prosesKode().
  8. Kirim kode ke PHP.
  9. Pastikan JSON dari PHP benar.
  10. Baru hubungkan ke database.

Dengan urutan ini, kita tidak menebak-nebak ketika sistem gagal.

Jika barcode gagal di Notepad, masalah kemungkinan bukan PHP.

Jika demo QR resmi tidak dapat membuka kamera, periksa browser, izin kamera, dan konteks halaman sebelum mengubah kode project.

Kesimpulan

Membuat scanner QR Code dan barcode di aplikasi web lebih mudah jika kita memisahkan cara kerja perangkatnya.

QR Code dibaca dari kamera browser menggunakan Nimiq QR Scanner.

Library tetap ditempatkan di:

C:\xampp\htdocs\absensi\libs\qr-scanner-master

Dengan file:

qr-scanner.min.js
qr-scanner-worker.min.js

Barcode 1D dari scanner USB tidak perlu dipaksa masuk melalui library QR. Scanner yang bekerja sebagai keyboard wedge dapat mengisi input HTML, lalu JavaScript memproses kode ketika suffix seperti Enter diterima.

Hasil QR dan barcode kemudian dapat disatukan dalam satu fungsi JavaScript dan dikirim ke endpoint PHP yang sama.

Dengan pendekatan tersebut, aplikasi dapat menggunakan kamera smartphone atau tablet untuk QR Code dan scanner USB untuk barcode tanpa membuat dua sistem pencarian data yang terpisah.

Keduanya cukup mengirim satu kode identitas ke PHP. Server kemudian mencari kode tersebut di database dan menjalankan proses sesuai kebutuhan aplikasi.

Baca juga :

Tidak ada komentar

Posting Komentar

Punya pertanyaan, saran, atau kritik seputar topik ini? Yuk, tulis di kolom komentar.

to Top