payum/iso4217
PHP library providing ISO 4217 currency data, including three-letter codes, numeric codes, names, minor units, and related metadata. Lightweight and dependency-free, it offers a simple API for looking up and validating currencies in payment and e-commerce apps. Part of the Payum ecosystem.
The whole public surface is two classes, so read them in this order before writing any integration code:
src/Currency.php — the value object. Every getter you will ever call (getAlpha3(), getNumeric(), getExp(), getName()) is defined here.src/ISO4217.php — the lookup registry. Check which methods exist (getByAlpha3(), getByNumeric(), findByAlpha3(), …), whether misses throw or return null, and whether input is normalized to upper case.Install and sanity-check in a Tinker session:
composer require payum/iso4217
php artisan tinker
use Payum\ISO4217\ISO4217;
$iso = new ISO4217();
$usd = $iso->getByAlpha3('USD');
$usd->getAlpha3(); // "USD"
$usd->getNumeric(); // "840"
$usd->getExp(); // 2 (exponent / minor unit)
$usd->getName(); // "US Dollar"
Your first real use case is almost always validation: a currency field arrives from a checkout form, an invoice import, or an API payload, and you need to reject anything that is not a real ISO 4217 code before it reaches a payment gateway or a database column. Do that with findByAlpha3() (null on miss) rather than getByAlpha3() (throws) so validation reads as a predicate.
Bind one instance in the container. The dataset is static, so loading it once per request is enough. In AppServiceProvider::register():
$this->app->singleton(ISO4217::class, fn () => new ISO4217());
Custom validation rule. Wrap the lookup in a rule so every form request and API endpoint shares the same definition:
class CurrencyCode implements ValidationRule
{
public function __construct(private ISO4217 $iso) {}
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! is_string($value) || $this->iso->findByAlpha3(strtoupper($value)) === null) {
$fail("The {$attribute} is not a valid ISO 4217 currency code.");
}
}
}
Minor-unit conversion for gateway calls. Payments libraries want integer amounts in the currency's smallest unit, and getExp() is exactly the exponent to scale by:
$currency = $iso->getByAlpha3($order->currency);
$amount = (int) round($order->total * (10 ** $currency->getExp()));
Store $order->total as a decimal and $order->currency as a char(3), and pass the scaled integer to Payum/Stripe/etc. This keeps rounding rules in one place instead of scattering * 100 through the codebase.
Reference-table seeding. If you need currency dropdowns, a join table, or numeric-code reconciliation from bank/ISO 8583 files, generate a migration seeder once from the library and stop querying it at runtime:
foreach ($iso->all() as $c) { CurrencyModel::updateOrCreate(['alpha3' => $c->getAlpha3()], [...]); }
Check for an all()-style iterator; otherwise reflect over the private data array in a one-off artisan command and commit the generated seed.
Numeric-code imports. Bank statements and settlement files usually key on the three-digit numeric code (840, 978), so use getByNumeric('840') to map imported rows back to your alpha-3 column. Never cast numeric codes to int — 008 (Albanian lek) and 051 (Armenian dram) legitimately have leading zeros.
Pair with intl for presentation. This package has no symbols or locale formatting. Use NumberFormatter::CURRENCY for display and keep payum/iso4217 for validation and arithmetic.
vendor/.getByAlpha3() throws \InvalidArgumentException on a miss while findByAlpha3() returns null. Confirm this before relying on it, and never let an unvalidated user string reach the throwing variant inside a controller.strtoupper(trim($code)) at the boundary prevents "usd fails validation" bug reports.getExp() can be non-numeric. Precious metals and special codes (XAU, XDR, XXX, XTS) carry "N.A." minor units. If your code does 10 ** getExp() on every currency, guard for null/non-int, or filter to transactable currencies when building dropdowns.Currency objects into queues, sessions, or cache. They are value objects from a third-party package with no stability contract. Persist the alpha-3 string and look it up again — the lookup is a cheap array access.XXX/XTS before showing options. They are testing/placeholder codes and will confuse users and payment gateway validation alike.USD = 2, JPY = 0, BHD = 3, CLF = 4). Write one test that pins the count of currencies so a dependency bump that changes the dataset fails loudly.ISO4217 and Currency are simple and largely undocumented internals; wrapping them behind an App\Support\Currencies interface lets you swap in a maintained data source later without touching call sites.How can I help you explore Laravel packages today?