PHPackages                             sasa-b/php-bihupp-qrcode - 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. [Payment Processing](/categories/payments)
4. /
5. sasa-b/php-bihupp-qrcode

ActiveLibrary[Payment Processing](/categories/payments)

sasa-b/php-bihupp-qrcode
========================

Library implementing the BIHUPP QR Code standard for representing bank payment instructions as QR Codes

0.2.3(1mo ago)013MITPHPPHP ^8.3

Since Apr 11Pushed 1mo agoCompare

[ Source](https://github.com/sasa-b/php-bihupp-qrcode)[ Packagist](https://packagist.org/packages/sasa-b/php-bihupp-qrcode)[ RSS](/packages/sasa-b-php-bihupp-qrcode/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (1)Dependencies (7)Versions (8)Used By (0)

php-bihupp-qrcode
=================

[](#php-bihupp-qrcode)

 [![BIHUPP QR code example](doc/test.svg)](doc/test.svg)

PHP biblioteka koja implementira BIHUPP10 standard QR koda za instrukcije bankovnog plaćanja u Bosni i Hercegovini.

BIHUPP (Bosansko-hercegovački unutrašnji platni promet) definiše strukturirani tekstualni sadržaj koji se može enkodirati u obliku QR koda, koji banke skeniraju kako bi automatski popunile naloge za plaćanje. Ovaj format je ustanovljen od strane [Udruženja Banaka Bosne i Hercegovine](https://ubbih.ba/).

Dodavanje QR koda u definisanom formatu na računima omogućava krajnjim korisnicima plaćanje pomoću skeniranja QR koda kroz njihovo mobilno bankarstvo.

Za Kotlin biblioteku idite na [kotlin-bihupp-qrcode](https://github.com/sasa-b/kotlin-bihupp-qrcode).

**Da biste verifikovali validnost QR koda ili da ga generišete ručno, koristite [s-co.tech/bihupp-qrcode-verifikator](https://s-co.tech/bihupp-qrcode-verifikator)**

---

PHP library implementing the **BIHUPP** QR Code standard for bank payment instructions in Bosnia and Herzegovina.

BIHUPP (*Bosansko-Hercegovački Unutrašnji Platni Promet*) defines a structured text payload that can be encoded as a QR code that banks scan to pre-fill payment forms. This format was established by the [Association of Banks of Bosnia and Herzegovina](https://ubbih.ba/).

Adding a QR code in the defined format to invoices enables end-users to make payments by scanning the QR code through their mobile banking app.

For Kotlin library go to [kotlin-bihupp-qrcode](https://github.com/sasa-b/kotlin-bihupp-qrcode).

**To verify validity of the QR Code or to generate one manually, use [s-co.tech/bihupp-qrcode-verifikator](https://s-co.tech/bihupp-qrcode-verifikator)**

Table of contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Usage](#usage)
    - [Standard bank transfer](#standard-bank-transfer)
    - [Omitting the sender](#omitting-the-sender)
    - [Multiple recipient accounts](#multiple-recipient-accounts)
    - [Including a sender phone number](#including-a-sender-phone-number)
    - [Public revenue payment](#public-revenue-payment-tax-fees-etc)
    - [Reading the payload string](#reading-the-payload-string)
- [QR code output](#qr-code-output)
    - [SVG (default)](#svg-default)
    - [PNG / JPEG — GD extension](#png--jpeg--gd-extension)
    - [PNG / JPEG — Imagick extension](#png--jpeg--imagick-extension)
    - [Base64 data-URI link](#base64-data-uri-link)
    - [Custom renderer](#custom-renderer)
- [Reading a QR code](#reading-a-qr-code)
- [Field reference](#field-reference)
    - [`PaymentInstruction` constructor](#paymentinstruction-constructor)
    - [Field constraints](#field-constraints)
    - [Allowed character set](#allowed-character-set)
- [Amount handling](#amount-handling)
- [Payment priority](#payment-priority)
- [Exception handling](#exception-handling)
- [Contribute](#contribute)
- [License](#license)

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

[](#requirements)

- PHP 8.3+
- [`chillerlan/php-qrcode`](https://github.com/chillerlan/php-qrcode) ^6.0
- [`khanamiryan/qrcode-detector-decoder`](https://github.com/khanamiryan/php-qrcode-detector-decoder) ^2.0 *(required for QR code reading)*

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

[](#installation)

```
composer require sasa-b/php-bihupp-qrcode
```

Quick start
-----------

[](#quick-start)

```
use Sco\BihuppQRCode\PaymentInstruction\Address\Address;
use Sco\BihuppQRCode\PaymentInstruction\Address\AddressLine1;
use Sco\BihuppQRCode\PaymentInstruction\Address\AddressLine2;
use Sco\BihuppQRCode\PaymentInstruction\Detail\Account;
use Sco\BihuppQRCode\PaymentInstruction\Detail\Amount;
use Sco\BihuppQRCode\PaymentInstruction\Detail\PaymentPurpose;
use Sco\BihuppQRCode\PaymentInstruction\Detail\PaymentReference;
use Sco\BihuppQRCode\PaymentInstruction\Detail\Sender;
use Sco\BihuppQRCode\PaymentInstruction\Name;
use Sco\BihuppQRCode\PaymentInstruction\PaymentInstruction;
use Sco\BihuppQRCode\PaymentInstruction\Recipient\Recipient;
use Sco\BihuppQRCode\PaymentInstruction\Recipient\RecipientAccount;

$instruction = new PaymentInstruction(
    sender: new Sender(
        name: Name::individual('Marko', 'Marković'),
        address: new Address(
            addressLine1: AddressLine1::from('Ulica Meše Selimovića', '12'),
            addressLine2: AddressLine2::from('78000', 'Banja Luka'),
        ),
        account: new Account('1234567890123456'),
    ),
    recipient: new Recipient(
        name: Name::business('Vodovod d.o.o.'),
        address: new Address(
            addressLine1: AddressLine1::from('Kralja Petra I Karađorđevića', '97'),
            addressLine2: AddressLine2::from('78000', 'Banja Luka'),
        ),
        account: new RecipientAccount(new Account('9876543210987654')),
    ),
    purpose: new PaymentPurpose('Račun za vodu - april 2024'),
    reference: new PaymentReference('1234-5678-001'),
    amount: new Amount('9862'), // amount in pennies (= 98.62 BAM)
);

// Render as SVG (default)
$svg = $instruction->toQRCode();
```

Usage
-----

[](#usage)

### Standard bank transfer

[](#standard-bank-transfer)

```
use Sco\BihuppQRCode\PaymentInstruction\Detail\PaymentPriority;

$instruction = new PaymentInstruction(
    sender: $sender,
    recipient: $recipient,
    purpose: new PaymentPurpose('Invoice payment'),
    reference: new PaymentReference('INV-2024-001'),
    amount: new Amount('10000'),           // 100.00 BAM
    paymentPriority: PaymentPriority::regular(), // defaults to regular ('N')
);
```

### Omitting the sender

[](#omitting-the-sender)

When `sender` is omitted, the bank pre-fills payer details from the logged-in user's session.

```
use Sco\BihuppQRCode\PaymentInstruction\Detail\Sender;

$instruction = new PaymentInstruction(
    sender: null,
    recipient: $recipient,
    purpose: new PaymentPurpose('Troškovi vode'),
    reference: new PaymentReference('1445-26554-11222'),
    amount: new Amount('9862'),
);
```

### Multiple recipient accounts

[](#multiple-recipient-accounts)

Up to 20 recipient accounts can be specified.

```
use Sco\BihuppQRCode\PaymentInstruction\Detail\Account;
use Sco\BihuppQRCode\PaymentInstruction\Recipient\RecipientAccount;

$account = new RecipientAccount(
    new Account('1234567890123456'),
    new Account('9876543210987654'),
    new Account('1111222233334444'),
);
```

### Including a sender phone number

[](#including-a-sender-phone-number)

```
use Sco\BihuppQRCode\PaymentInstruction\Recipient\PhoneNumber;

$sender = new Sender(
    name: Name::individual('Ana', 'Anić'),
    address: new Address(
        addressLine1: AddressLine1::from('Kralja Tomislava', '5'),
        addressLine2: AddressLine2::from('88000', 'Mostar'),
    ),
    account: new Account('1234567890123456'),
    phoneNumber: new PhoneNumber('+38761234567'), // E.164 format, "+" prefix required
);
```

### Public revenue payment (tax, fees, etc.)

[](#public-revenue-payment-tax-fees-etc)

Public revenue payments require additional fields grouped in a `PublicRevenueInstruction` object.

```
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenueInstruction;
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenue\BudgetOrgCode;
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenue\MunicipalCode;
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenue\PaymentReference as PublicRevenuePaymentReference;
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenue\PaymentType;
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenue\RevenueType;
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenue\SenderTaxId;
use Sco\BihuppQRCode\PaymentInstruction\PublicRevenue\TaxPeriodDate;

$instruction = new PaymentInstruction(
    sender: new Sender(
        name: Name::business('Example Company d.o.o.'),
        address: new Address(
            addressLine1: AddressLine1::from('Veselina Masleše', '20'),
            addressLine2: AddressLine2::from('78000', 'Banja Luka'),
        ),
        account: new Account('1234567890123456'),
    ),
    recipient: new Recipient(
        name: new Name('Trezor'),
        address: new Address(
            addressLine1: AddressLine1::from('Aleja Svetog Save', '13'),
            addressLine2: AddressLine2::from('78000', 'Banja Luka'),
        ),
        account: new RecipientAccount(new Account('1610000010680092')),
    ),
    purpose: new PaymentPurpose('Porez na dobit'),
    reference: null,
    amount: new Amount('500000'), // 5000.00 BAM
    publicRevenue: new PublicRevenueInstruction(
        senderTaxId: new SenderTaxId('4200730150004'),  // 13-digit tax ID (JIB/JMBG)
        paymentType: new PaymentType('3'),
        revenueType: new RevenueType('712115'),
        taxPeriodStartDate: TaxPeriodDate::fromDate(new DateTimeImmutable('2024-01-01')),
        taxPeriodEndDate: TaxPeriodDate::fromDate(new DateTimeImmutable('2024-12-31')),
        municipalCode: new MunicipalCode('077'),
        budgetOrgCode: new BudgetOrgCode('1200200'),
        paymentReference: new PublicRevenuePaymentReference('7110578163'),
    ),
);
```

### Reading the payload string

[](#reading-the-payload-string)

`PaymentInstruction` implements `Stringable`. Cast it to `string` to inspect or store the raw BIHUPP payload, or get an array of lines with `lines()`:

```
echo (string) $instruction;
// BIHUPP10
// Example Company d.o.o.
// Zmaja od Bosne 75
// 71000 Sarajevo
// ...

var_dump($instruction->lines());
```

QR code output
--------------

[](#qr-code-output)

### SVG (default)

[](#svg-default)

```
$svg = $instruction->toQRCode(); // returns SVG XML string
```

### PNG / JPEG — GD extension

[](#png--jpeg--gd-extension)

Requires the [`gd`](https://www.php.net/manual/en/book.image.php) extension. Throws `MissingImageExtension` if it is not loaded.

```
use Sco\BihuppQRCode\QRCode\RenderStrategy\GDPng;
use Sco\BihuppQRCode\QRCode\RenderStrategy\GDJpeg;

$png  = $instruction->toQRCode(renderStrategy: new GDPng());  // PNG binary
$jpeg = $instruction->toQRCode(renderStrategy: new GDJpeg()); // JPEG binary
```

### PNG / JPEG — Imagick extension

[](#png--jpeg--imagick-extension)

Requires the [`imagick`](https://www.php.net/manual/en/book.imagick.php) extension. Throws `MissingImageExtension` if it is not loaded.

```
use Sco\BihuppQRCode\QRCode\RenderStrategy\ImagickPng;
use Sco\BihuppQRCode\QRCode\RenderStrategy\ImagickJpeg;

$png  = $instruction->toQRCode(renderStrategy: new ImagickPng());  // PNG binary
$jpeg = $instruction->toQRCode(renderStrategy: new ImagickJpeg()); // JPEG binary
```

### Base64 data-URI link

[](#base64-data-uri-link)

`Base64Link` wraps any `ImageRenderStrategy` and returns a base64 data URI. Defaults to SVG when no strategy is passed.

```
use Sco\BihuppQRCode\QRCode\RenderStrategy\Base64Link;
use Sco\BihuppQRCode\QRCode\RenderStrategy\GDPng;
use Sco\BihuppQRCode\QRCode\RenderStrategy\ImagickJpeg;

$svgUri  = $instruction->toQRCode(renderStrategy: new Base64Link());                  // data:image/svg+xml;base64,...
$pngUri  = $instruction->toQRCode(renderStrategy: new Base64Link(new GDPng()));       // data:image/png;base64,...
$jpegUri = $instruction->toQRCode(renderStrategy: new Base64Link(new ImagickJpeg())); // data:image/jpeg;base64,...
```

### Custom renderer

[](#custom-renderer)

Implement `Renderer` and `RenderStrategy` to integrate any QR library or add custom options (logo overlay, colours, size, etc.):

```
use Sco\BihuppQRCode\PaymentInstruction\PaymentInstruction;
use Sco\BihuppQRCode\QRCode\Renderer;
use Sco\BihuppQRCode\QRCode\RenderStrategy;
use Sco\BihuppQRCode\QRCode\RenderStrategy\Svg;

final readonly class MyRenderer implements Renderer
{
    public function render(PaymentInstruction $data, RenderStrategy $strategy): string
    {
        // use any QR library here
        return myQrLib()->encode((string) $data);
    }
}

$svg = $instruction->toQRCode(renderer: new MyRenderer(), renderStrategy: new Svg());
```

Reading a QR code
-----------------

[](#reading-a-qr-code)

Use `Reader::read()` to scan a BIHUPP QR code image and reconstruct a `PaymentInstruction` from it. Pass either a file path or a binary blob as the source.

```
use Sco\BihuppQRCode\QRCode\Reader;
use Sco\BihuppQRCode\QRCode\ReadSource\Filepath;
use Sco\BihuppQRCode\QRCode\ReadSource\Blob;
use Sco\BihuppQRCode\QRCode\Reader\SuccessScanResult;
use Sco\BihuppQRCode\QRCode\Reader\FailureScanResult;

// From a file path
$result = Reader::scan(new Filepath('/path/to/qrcode.png'));

// From binary image data (e.g. an uploaded file)
$result = Reader::scan(new Blob(file_get_contents('/path/to/qrcode.png')));

if ($result instanceof SuccessScanResult) {
    $instruction = $result->paymentInstruction; // PaymentInstruction
    $raw         = $result->rawPayload;         // raw BIHUPP payload string

    echo $instruction->sender->name->value;     // e.g. "Marko Marković"
    echo $instruction->amount->value;           // e.g. "000000000010000"
} else {
    // $result is FailureScanResult
    echo $result->error->getMessage();          // reason for failure
    // $result->rawPayload is null when the image contained no QR code
}
```

By default GD is used to decode the image. Pass `ImageExtension::Imagick` as the second constructor argument to use Imagick instead:

```
use Sco\BihuppQRCode\QRCode\ImageExtension;

$result = Reader::read(new Filepath('/path/to/qrcode.png', ImageExtension::Imagick));
```

Field reference
---------------

[](#field-reference)

### `PaymentInstruction` constructor

[](#paymentinstruction-constructor)

ParameterTypeRequiredDefaultNotes`sender``Sender`No—Pass `null` to let the bank auto-fill`recipient``Recipient`Yes—`purpose``PaymentPurpose`Yes—Max 110 chars`reference``PaymentReference|null`No—Pass `null` to omit`amount``Amount`Yes—Integer in pennies (pfeninga)`currency``Currency`Yes`BAM`Hardcoded to BAM by standard`paymentPriority``PaymentPriority`No`N` (regular)`publicRevenue``PublicRevenue|null`No`null`Required only for tax/fee payments`version``Version`Yes`BIHUPP10`### Field constraints

[](#field-constraints)

#### Sender / Recipient

[](#sender--recipient)

FieldClassMax lengthFormatName`Name`50Alphanumeric + allowed charsAddress line 1`AddressLine1`50Street + numberAddress line 2`AddressLine2`25Postcode + cityPhone`PhoneNumber`15E.164 (`+` prefix required)Sender account`Account`16Recipient account(s)`RecipientAccount`3391–20 accounts, comma-separated#### Payment detail

[](#payment-detail)

FieldClassMax lengthFormatPurpose`PaymentPurpose`110Reference`Detail\PaymentReference`30Amount`Amount`15Integer pennies (pfeninzi), zero-padded#### Public revenue fields

[](#public-revenue-fields)

FieldClassLengthFormatSender tax ID`SenderTaxId`13Exactly 13 digits (JIB/JMBG)Payment type`PaymentType`1Single digit (`0`–`9`)Revenue type`RevenueType`6Exactly 6 digitsTax period date`TaxPeriodDate`8`DDMMYYYY`Municipal code`MunicipalCode`3Exactly 3 digitsBudget org code`BudgetOrgCode`7Exactly 7 digitsPayment reference`PublicRevenue\PaymentReference`10Exactly 10 digits### Allowed character set

[](#allowed-character-set)

All text fields accept: alphanumeric characters, Serbian/Croatian/Bosnian diacritics (`č ć đ š ž` and their uppercase forms), and the symbols `, : . ? ( ) + ' / -` and space.

Fields with stricter formats (tax IDs, codes, phone numbers) enforce their own format in addition to the above.

Amount handling
---------------

[](#amount-handling)

`Amount` stores the value as an integer number of **pennies (pfeniga)** and zero-pads it to 15 digits in the payload. Use the factory helpers for other input types:

```
Amount::fromInt(9862);         // 98.62 BAM
Amount::fromFloat(98.62);      // 98.62 BAM (strips the decimal separator)
new Amount('9862');            // same, from a string
```

Payment priority
----------------

[](#payment-priority)

```
PaymentPriority::regular();    // 'N' — standard processing
PaymentPriority::urgent();     // 'D' — urgent processing
PaymentPriority::from(Priority::Urgent);
```

Exception handling
------------------

[](#exception-handling)

All validation runs at construction time. Exception types extend `BihuppQRCodeException`.:

ExceptionThrown when`InvalidLengthException`Value exceeds the field's maximum character length`InvalidCharacterException`Value contains characters outside the allowed set`InvalidValueException`Value violates a field-specific format rule (digits-only, `+` prefix, etc.)`MissingImageExtension`A GD or Imagick render strategy is used but the required PHP extension is not loaded`UnknownScanException``Reader::read()` could not decode the image and the underlying library returned no specific errorCatch a specific type, or use `BihuppQRCodeException` to handle any library exception in one clause:

```
use Sco\BihuppQRCode\BihuppQRCodeException;
use Sco\BihuppQRCode\PaymentInstruction\Exception\InvalidLengthException;
use Sco\BihuppQRCode\PaymentInstruction\Exception\InvalidCharacterException;
use Sco\BihuppQRCode\PaymentInstruction\Exception\InvalidValueException;

try {
    $name = new Name(str_repeat('A', 51)); // exceeds 50-char limit
} catch (InvalidLengthException $e) {
    // handle length violation specifically
} catch (BihuppQRCodeException $e) {
    // handle any other library exception
}
```

Contribute
----------

[](#contribute)

Run code quality check before raising PRs.

```
composer c:q # runs php-cs-fixer and PHPStan
```

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance90

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

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 ~1 days

Total

7

Last Release

52d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b69f1d9205d4b96ec1c90ff7bc2503f1d14ea4b0b89b82b406c16f922c634133?d=identicon)[sasa-b](/maintainers/sasa-b)

---

Top Contributors

[![sasa-b](https://avatars.githubusercontent.com/u/18427949?v=4)](https://github.com/sasa-b "sasa-b (29 commits)")

---

Tags

bank-paymentbihuppbihupp10bosniabosnia-and-herzegovinapayment-instructionqrcodeqr codeqrcodebank transferbosniabihuppbihupp10payment instructionhercegovinaplatni promet

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sasa-b-php-bihupp-qrcode/health.svg)

```
[![Health](https://phpackages.com/badges/sasa-b-php-bihupp-qrcode/health.svg)](https://phpackages.com/packages/sasa-b-php-bihupp-qrcode)
```

###  Alternatives

[piggly/php-pix

Uma biblioteca para preparar e gerar o código Pix do Banco Central do Brasil.

106147.5k1](/packages/piggly-php-pix)[paypayopa/php-sdk

PHP SDK for PayPay Open Payment API

18304.2k4](/packages/paypayopa-php-sdk)[saleh7/php-zatca-xml

An unofficial PHP library for generating ZATCA Fatoora e-invoices. This library facilitates the creation of compliant e-invoices, QR Codes, and certificates, as well as the submission of e-invoices to ZATCA's servers. It provides developers with an easy-to-use, customizable, and robust toolkit to integrate and automate ZATCA e-invoicing processes in PHP applications.

5516.0k](/packages/saleh7-php-zatca-xml)[hakito/php-stuzza-eps-banktransfer

Stuzza e-payment standard implementation for PHP

1672.3k2](/packages/hakito-php-stuzza-eps-banktransfer)[sevaske/php-zatca-xml

An unofficial PHP library for generating ZATCA Fatoora e-invoices. This library facilitates the creation of compliant e-invoices, QR Codes, and certificates, as well as the submission of e-invoices to ZATCA's servers. It provides developers with an easy-to-use, customizable, and robust toolkit to integrate and automate ZATCA e-invoicing processes in PHP applications.

218.1k1](/packages/sevaske-php-zatca-xml)[khaledhajsalem/zatca-php

A comprehensive PHP package for ZATCA (Saudi Arabia e-invoicing) invoice processing, signing, and submission

102.1k](/packages/khaledhajsalem-zatca-php)

PHPackages © 2026

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