konthaina/khqr-php
最新稳定版本:v1.3.0
Composer 安装命令:
composer require konthaina/khqr-php
包简介
KHQR / EMVCo QR payload generator for PHP (merchant presented) with CRC16 (NBC KHQR spec).
关键字:
README 文档
README
KHQR / EMVCo merchant-presented QR payload generator for PHP (Bakong / Cambodia). Includes CRC16 (CRC-16/CCITT-FALSE), MD5, and verification helpers.
Namespace:
Konthaina\KhqrMain class:Konthaina\Khqr\KHQRGenerator
Features
- Generate KHQR payload string (EMV Tag-Length-Value format)
- Supports Individual and Merchant account structures
- Supports Static QR and Dynamic QR
- Optional fields: amount, bill number, mobile number, store label, terminal label, purpose, alternate language, etc.
- CRC16 calculation + verification
- Returns md5 hash of the full QR payload string
Requirements
- PHP >= 8.0
- Composer
Installation
Install via Composer (Packagist)
composer require konthaina/khqr-php
Install from local path (during development)
In your main app composer.json:
{
"repositories": [
{
"type": "path",
"url": "../khqr-php"
}
],
"require": {
"konthaina/khqr-php": "*"
}
}
Then:
composer update
Quick Start
<?php require __DIR__ . '/vendor/autoload.php'; use Konthaina\Khqr\KHQRGenerator; $khqr = new KHQRGenerator(KHQRGenerator::MERCHANT_TYPE_INDIVIDUAL); $result = $khqr->setBakongAccountId('kon_thaina@cadi') ->setMerchantName('Konthaina Co., Ltd.') ->setCurrency('USD') ->setAmount(25.75) ->setExpirationDuration(120) ->setMerchantCity('Phnom Penh') ->setBillNumber('#12345') ->generate(); echo $result['qr'] . PHP_EOL; echo "md5: {$result['md5']}\n"; echo "createdTimestamp: {$result['createdTimestamp']}\n"; echo "expirationTimestamp: {$result['expirationTimestamp']}\n"; echo "verify: " . (KHQRGenerator::verify($result['qr']) ? "OK" : "FAIL") . PHP_EOL;
Returned structure:
[ 'qr' => '000201...', 'timestamp' => '1700000000000', 'createdTimestamp' => '1700000000000', 'expirationTimestamp' => '1700000120000', // null for static mode 'type' => 'individual|merchant', 'md5' => '...' ]
Static QR vs Dynamic QR
- Static QR uses POI=11 and includes Tag 99 sub-tag 00 as the create timestamp.
- Dynamic QR is the default mode (POI=12) and includes Tag 99 sub-tag 00 as the create timestamp plus sub-tag 01 as the expiration timestamp.
- Dynamic QR defaults to expiring 300 seconds after creation. Use
setExpirationTimestamp(...)orsetExpirationDuration(...)to control it. - For a "no amount" QR, use static mode.
Static example:
$result = (new KHQRGenerator(KHQRGenerator::MERCHANT_TYPE_INDIVIDUAL)) ->setStatic(true) ->setBakongAccountId('kon_thaina@cadi') ->setMerchantName('Konthaina Co., Ltd.') ->setCurrency('USD') ->setMerchantCity('Phnom Penh') ->generate();
Timestamp example:
$result = (new KHQRGenerator(KHQRGenerator::MERCHANT_TYPE_INDIVIDUAL)) ->setBakongAccountId('kon_thaina@cadi') ->setMerchantName('Konthaina Co., Ltd.') ->setCurrency('USD') ->setAmount(25.75) ->setCreatedTimestamp('1755076232336') ->setExpirationTimestamp('1755076292336') ->generate();
Both timestamp values are 13-digit Unix timestamps in milliseconds.
Merchant Type Examples
Individual (Tag 29)
$khqr = new KHQRGenerator(KHQRGenerator::MERCHANT_TYPE_INDIVIDUAL); $result = $khqr->setBakongAccountId('john_smith@devb') ->setMerchantName('John Smith') ->setAccountInformation('85512233455') ->setAcquiringBank('Dev Bank') ->setCurrency('USD') ->setAmount(5.00) ->generate();
Merchant (Tag 30)
$khqr = new KHQRGenerator(KHQRGenerator::MERCHANT_TYPE_MERCHANT); $result = $khqr->setBakongAccountId('merchant@bank') ->setMerchantId('123456') ->setMerchantName('ABC Store') ->setAcquiringBank('ABC Bank') ->setCurrency('KHR') ->setAmount(50000) ->generate();
Verify KHQR (CRC)
use Konthaina\Khqr\KHQRGenerator; $isValid = KHQRGenerator::verify($qrString);
Verify Transaction by MD5 (Bakong Open API)
Requires a Bakong Open API access token.
use Konthaina\Khqr\BakongApiClient; use Konthaina\Khqr\KHQRGenerator; $client = new BakongApiClient('YOUR_ACCESS_TOKEN'); // uses default Bakong base URL $response = $client->checkTransactionByMd5($result['md5']); $response = $client->checkTransactionByQr($result['qr']); $response = KHQRGenerator::checkTransactionByMd5WithToken($result['md5'], 'YOUR_ACCESS_TOKEN'); // Optional: custom base URL $client = new BakongApiClient('https://api-bakong.nbc.gov.kh', 'YOUR_ACCESS_TOKEN');
Renew Access Token (Bakong Open API)
Based on Bakong Open API POST /v1/renew_token:
use Konthaina\Khqr\BakongApiClient; use Konthaina\Khqr\KHQRGenerator; $response = BakongApiClient::renewToken('your-email@example.com'); // Optional: custom base URL and timeout $response = BakongApiClient::renewToken('your-email@example.com', 'https://api-bakong.nbc.gov.kh', 30); // Convenience wrapper $response = KHQRGenerator::renewBakongToken('your-email@example.com');
Verify MD5 Output
Success
{
"responseCode": 0,
"responseMessage": "Getting transaction successfully.",
"errorCode": null,
"data": {
"hash": "e40a....",
"fromAccountId": "developer@cmcb",
"toAccountId": "developer@devb",
"currency": "USD",
"amount": 1.0,
"description": "",
"createdDateMs": 1605774370608.0,
"acknowledgedDateMs": 1605774422421.0
}
}
Not found
{
"data": null,
"errorCode": 1,
"responseCode": 1,
"responseMessage": "Transaction could not be found. Please check and try again."
}
Fields / Limits
The generator truncates fields based on common KHQR limits used in the code:
- Bakong account id: 32
- Merchant name: 25
- Merchant ID: 32
- Acquiring bank: 32
- Account information: 32
- City: 15
- Bill number: 25
- Mobile number: 25
- Store label: 25
- Terminal label: 25
- Purpose: 25
- Language preference: 2
- Merchant name alternate: 25
- City alternate: 15
- UPI account info: 31
- Created timestamp: 13 digits, Unix milliseconds
- Expiration timestamp: 13 digits, Unix milliseconds
Note: EMV length uses byte length. If you use Khmer or Unicode characters, byte length may differ from character count.
Development / Testing
Install dev dependencies:
composer install
Run tests:
vendor/bin/phpunit
Generate autoload:
composer dump-autoload
Release to GitHub / Packagist
Create a new version tag when you update the library:
git add . git commit -m "Release: vX.Y.Z" git tag vX.Y.Z git push origin main git push origin vX.Y.Z
Packagist will pick up tags like vX.Y.Z as stable versions (if webhook enabled).
License
MIT
统计信息
- 总下载量: 351
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 2
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-01-20