jschaedl/iban
A PHP package for validating, formatting, and generating IBANs using country-specific structure and checksum rules, helping ensure bank account numbers are correct before storage or payment processing.
Install with Composer; the package has no Laravel auto-discovery and no service provider, so nothing needs registering:
composer require jschaedl/iban
Look first at the single entry point, Jschaedl\Iban\IBAN. Everything is a plain value object built from a string:
use Jschaedl\Iban\IBAN;
$iban = new IBAN('DE89370400440532013000');
$iban->isValid(); // bool — format + mod-97 checksum
$iban->getCountryCode(); // "DE"
$iban->getBBAN(); // "370400440532013000"
$iban->getBankIdentifier(); // "37040044"
$iban->getAccountNumber(); // "0532013000"
$iban->toFormat(); // "DE89 3704 0044 0532 0130 00"
Your first real use case in a Laravel app is validating a user-submitted payout/refund IBAN in a form request, then storing a normalized copy: strip spaces, uppercase, persist the compact form, display the formatted form. Treat the library as a pure validator/parser — it tells you whether the string is structurally a valid IBAN, never whether the account exists.
Custom validation rule. Wrap IBAN in an Illuminate\Contracts\Validation\Rule so it slots into FormRequests and inline Validator::make calls identically:
class ValidIban implements Rule
{
public function passes($attribute, $value): bool
{
$normalized = strtoupper(str_replace(' ', '', (string) $value));
try {
return (new IBAN($normalized))->isValid();
} catch (\Throwable) {
return false;
}
}
public function message(): string
{
return 'The :attribute is not a valid IBAN.';
}
}
Normalize at the boundary. Always normalize before constructing: users paste IBANs with spaces, lowercase, and non-breaking spaces. Do this once in a FormRequest prepareForValidation() or in a value-object named constructor, not scattered through controllers.
Value object + Eloquent accessor. Keep the compact IBAN in the database column and expose formatting via an accessor:
protected function ibanFormatted(): Attribute
{
return Attribute::get(fn () => (new IBAN($this->iban))->toFormat());
}
Pre-payment gate. In a SEPA/payout flow, run validation immediately before dispatching to your payment provider, not only at signup — IBANs get edited. Pair this with provider-side verification (name/account match); format validity is a cheap pre-check, not a substitute.
No facade/singleton needed. The class is stateless and cheap to instantiate; binding it in a service provider adds ceremony without benefit. If you want a single seam for swapping libraries later, introduce a thin IbanService interface in your domain and inject the package behind it — this makes the eventual deprecation migration a one-file change.
Test data. Use a fixed table of known-valid IBANs across your supported countries in factories/seeders rather than generating at runtime; deterministic fixtures catch checksum regressions and keep tests readable.
symfony/validator's Iban constraint (already available if you use Laravel's validator stack) or globalcitizen/php-iban; keep this assessment's integration patterns but swap the implementation.isValid() vs. the constructor. Depending on input, the constructor may throw for structurally unparseable strings while isValid() returns false for bad checksums. Always wrap construction in try/catch in validation rules, as shown above, or you will turn a bad user input into a 500.getBankIdentifier() / getAccountNumber() are layout-dependent. They reflect the registry's BBAN split for that country, not a universal rule. Don't assume their lengths or semantics across countries; some countries don't define a bank identifier at all.IbanValidator/IbanParser contract now. When you move to symfony/validator or php-iban, your FormRequests, accessors, and payout services stay untouched.How can I help you explore Laravel packages today?