PHPackages                             istorebox/omnipay-benefitgateway - 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. istorebox/omnipay-benefitgateway

ActiveLibrary[Payment Processing](/categories/payments)

istorebox/omnipay-benefitgateway
================================

Benefit Payment Gateway driver for the Omnipay payment processing library

v2.0.0(yesterday)00MITPHPPHP ^8.2CI passing

Since Jun 9Pushed yesterdayCompare

[ Source](https://github.com/iStoreBox-Dev/omnipay-benefitgateway-v2)[ Packagist](https://packagist.org/packages/istorebox/omnipay-benefitgateway)[ Docs](https://github.com/iStoreBox-Dev/omnipay-benefitgateway-v2)[ RSS](/packages/istorebox-omnipay-benefitgateway/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

Omnipay: Benefit Payment Gateway
================================

[](#omnipay-benefit-payment-gateway)

[![PHP](https://camo.githubusercontent.com/187240af044d09d5b14a1d9d9ebdf3f7a993e4c7bc09bdb46b4ba661a891bf5b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d626c7565)](https://www.php.net)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)[![CI](https://github.com/iStoreBox-Dev/omnipay-benefitgateway-v2/actions/workflows/ci.yml/badge.svg)](https://github.com/iStoreBox-Dev/omnipay-benefitgateway-v2/actions/workflows/ci.yml)

A **Benefit Payment Gateway** driver for the [Omnipay](https://github.com/thephpleague/omnipay) PHP payment processing library.

Benefit is the leading payment network in Bahrain, enabling merchants to accept payments in **Bahraini Dinar (BHD)**.

---

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

[](#requirements)

RequirementVersionPHP`^8.2`ext-opensslanyomnipay/common`^3.1`---

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

[](#installation)

```
composer require istorebox/omnipay-benefitgateway
```

---

Configuration
-------------

[](#configuration)

Obtain the following credentials from your Benefit merchant account:

ParameterTypeDescription`id``string`Merchant / Portal ID issued by Benefit`password``string`Gateway password issued by Benefit`resource_key``string`**Exactly 32-byte** AES-256 encryption key issued by Benefit`currency``string`ISO 4217 alpha code — **must be `BHD`**`langid``string`Payment page language: `USA` (English, default) or `ARA` (Arabic)`testMode``bool``true` → sandbox, `false` (default) → production```
use Omnipay\Omnipay;

$gateway = Omnipay::create('BenefitGateway');

$gateway->setId('YOUR_MERCHANT_ID');
$gateway->setPassword('YOUR_GATEWAY_PASSWORD');
$gateway->setResourceKey('YOUR_EXACTLY_32_BYTE_KEY_HERE!!'); // must be 32 bytes
$gateway->setCurrency('BHD');
$gateway->setLangId('USA');    // or 'ARA' for Arabic
$gateway->setTestMode(false);  // true for sandbox
```

> ⚠️ **Security**: The `resource_key` must be **exactly 32 bytes**. The driver will throw an `\InvalidArgumentException` immediately if the key length is wrong — this prevents silent encryption failures.

---

Usage
-----

[](#usage)

### 1 — Initiate a Purchase

[](#1--initiate-a-purchase)

Redirects the customer to the Benefit-hosted payment page.

```
$response = $gateway->purchase([
    'amount'        => '1.000',              // 3 decimal places for BHD
    'transactionId' => 'ORDER-' . time(),   // your unique order/track ID
    'returnUrl'     => 'https://yoursite.com/payment/return',
    'cancelUrl'     => 'https://yoursite.com/payment/cancel',
])->send();

if ($response->isRedirect()) {
    $response->redirect();
    // or: header('Location: ' . $response->getRedirectUrl());
}
```

> **Note**: The gateway `password` is included inside the AES-encrypted `trandata` blob only. It is **never** exposed as a plain query string parameter in the redirect URL.

### 2 — Complete a Purchase (Callback)

[](#2--complete-a-purchase-callback)

Benefit POSTs the encrypted result back to your `returnUrl`. Handle it:

```
$response = $gateway->completePurchase()->send();
// trandata is decrypted automatically using your resource_key

if ($response->isSuccessful()) {
    $paymentId = $response->getTransactionReference(); // Benefit payment ID
    $orderId   = $response->getTransactionId();        // your order/track ID
    $authCode  = $response->getAuthCode();             // authorisation code
    $refId     = $response->getReferenceId();          // reference number

    // Mark order as paid ...

} elseif ($response->isCancelled()) {
    // Customer clicked Cancel on the Benefit page

} elseif ($response->isTimedOut()) {
    // Bank host communication timed out — advise customer to retry

} else {
    $error = $response->getMessage(); // e.g. 'NOT CAPTURED'
    // Handle failure ...
}
```

#### Passing Callback Data Manually

[](#passing-callback-data-manually)

Useful in controllers or tests where you want to pass POST data explicitly:

```
$response = $gateway->completePurchase([
    'request_data' => $request->post(),
])->send();
```

---

Response Methods
----------------

[](#response-methods)

### `completePurchase` Response

[](#completepurchase-response)

MethodReturnsDescription`isSuccessful()``bool``true` only when `result === 'CAPTURED'``isCancelled()``bool``true` when `result === 'CANCELED'``isTimedOut()``bool``true` when `result === 'HOSTIMEOUT'``getCode()``string|null`Raw result from Benefit (`CAPTURED`, `NOT CAPTURED`, `CANCELED`, `HOSTIMEOUT`)`getMessage()``string|null`Result string or `ErrorText` on failure`getTransactionReference()``string|null`Benefit-assigned `paymentid``getTransactionId()``string|null`Your merchant `trackid` echoed back`getAuthCode()``string|null`Authorization code (`auth`)`getReferenceId()``string|null`Reference number (`ref`)---

How Encryption Works
--------------------

[](#how-encryption-works)

The Benefit gateway uses **AES-256-CBC** with a fixed IV (`PGKEYENCDECIVSPC`) and PKCS#5 padding, as required by the Benefit integration specification.

- **Purchase**: request parameters (including `id` and `password`) are encrypted into a hex string and sent as `trandata` in the redirect URL.
- **completePurchase**: the `trandata` POST field is URL-decoded, then hex-decoded, then AES-decrypted and parsed back into key-value pairs.
- All encryption/decryption is handled by `Omnipay\BenefitGateway\Crypto\AesEncryptor` — you never call it directly.

---

Error Handling
--------------

[](#error-handling)

ExceptionTrigger`InvalidRequestException`Required parameter missing (`id`, `amount`, `resource_key`, `paymentid`, etc.)`InvalidRequestException`Unsupported or missing currency code`InvalidRequestException`AES decryption failure on callback (wraps `RuntimeException`)`\InvalidArgumentException``resource_key` is not exactly 32 bytes`\InvalidArgumentException``setLangId()` called with value other than `USA` or `ARA``\InvalidArgumentException`Unknown currency passed to `CurrencyCodeResolver``\RuntimeException`OpenSSL failure, invalid hex, or corrupted cipher data---

Testing
-------

[](#testing)

```
composer install
composer test
```

Enable sandbox mode to route requests to the Benefit test environment:

```
https://www.test.benefit-gateway.bh/payment/PaymentHTTP.htm

```

---

Supported Currencies
--------------------

[](#supported-currencies)

The driver includes a full ISO 4217 currency map used internally for numeric code resolution. Pass `BHD` for all live Bahrain transactions.

You can also use `CurrencyCodeResolver` directly:

```
use Omnipay\BenefitGateway\Currency\CurrencyCodeResolver;

CurrencyCodeResolver::numericCode('BHD'); // '048'
CurrencyCodeResolver::getName('BHD');     // 'Bahraini Dinar'
CurrencyCodeResolver::isSupported('XYZ'); // false
```

---

Changelog
---------

[](#changelog)

### v2.1.0

[](#v210)

- **Security**: Validate AES key is exactly 32 bytes before any encrypt/decrypt operation
- **Security**: Strip `password` from plaintext redirect URL — password only travels inside AES-encrypted `trandata`
- **Security**: URL-decode `trandata` before `hex2bin` to handle Benefit POST encoding correctly
- **Security**: Guard `base64_decode` and `hex2bin` false returns with explicit `RuntimeException`
- **Robustness**: Add `resource_key` validation in `CompletePurchaseRequest`
- **Robustness**: Wrap decryption `RuntimeException` as `InvalidRequestException` with context
- **Robustness**: Add empty-string guard in `pkcs5Unpad` after successful decrypt
- **Feature**: `langid` is now configurable (`USA` / `ARA`) via `setLangId()` on Gateway and PurchaseRequest
- **Feature**: Add `isCancelled()` and `isTimedOut()` to `CompletePurchaseResponse`
- **Feature**: Add `CurrencyCodeResolver::getName()` and `::all()` methods
- **DX**: Add `suggest` section to `composer.json`
- **Tests**: Add `AesEncryptorTest` — 9 test cases covering round-trip, key length, encoding, errors
- **Tests**: Add `CurrencyCodeResolverTest` — 12 test cases covering codes, names, case-insensitivity, duplicates
- **Tests**: Expand `GatewayTest` — add `isCancelled`, `isTimedOut`, password-not-in-URL, `resource_key` missing tests
- **CI**: Add GitHub Actions workflow for PHP 8.2 and 8.3 matrix

### v2.0.0

[](#v200)

- Require PHP `^8.2`, drop PHP 7.x
- Strict types and full return-type declarations
- Replace global helpers with `Crypto\AesEncryptor` and `Currency\CurrencyCodeResolver`
- Fix duplicate currency keys in ISO 4217 map
- Add `getAuthCode()`, `getReferenceId()`, `getCode()` to response
- Fluent setter interface
- PHPUnit v11 config
- MIT LICENSE

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity45

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

Unknown

Total

1

Last Release

1d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/cdcf64cc6e227706f12be1f25865d69917283b6768d1803bce8be819c1957ec8?d=identicon)[iStoreBox-Dev](/maintainers/iStoreBox-Dev)

---

Top Contributors

[![iStoreBox-Dev](https://avatars.githubusercontent.com/u/114222092?v=4)](https://github.com/iStoreBox-Dev "iStoreBox-Dev (7 commits)")

---

Tags

paymentomnipaybenefit gatewaybahrainbhd

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/istorebox-omnipay-benefitgateway/health.svg)

```
[![Health](https://phpackages.com/badges/istorebox-omnipay-benefitgateway/health.svg)](https://phpackages.com/packages/istorebox-omnipay-benefitgateway)
```

###  Alternatives

[lokielse/omnipay-alipay

Alipay gateway for Omnipay payment processing library

586422.2k11](/packages/lokielse-omnipay-alipay)[omnipay/mollie

Mollie driver for the Omnipay payment processing library

631.8M10](/packages/omnipay-mollie)[silverstripe/silverstripe-omnipay

SilverStripe Omnipay Payment Module

38108.5k17](/packages/silverstripe-silverstripe-omnipay)[sudiptpa/omnipay-nabtransact

National Australia Bank (NAB) Transact driver for the Omnipay payment processing library.

1018.7k](/packages/sudiptpa-omnipay-nabtransact)[lucassmacedo/omnipay-mercadopago

MercadoPago gateway for OmniPay

155.1k](/packages/lucassmacedo-omnipay-mercadopago)

PHPackages © 2026

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