Library / SDK
alcohol/iso3166 avatar
alcohol/iso3166

league/iso3166 gives PHP a country code table that is not a mystery blob

A PHP library providing ISO 3166-1 data.

700 stars68 forksPHPMIT

At a glance

What is it?
league/iso3166 packages ISO 3166-1 country data for PHP with lookup by name, alpha-2, alpha-3 or numeric code, and returns a plain array. It is a small, MIT licensed library with a stated scope, and its real value is that the data is a dataset you can inspect rather than a service you have to trust.
Who is it for?
league/iso3166 suits a PHP application that needs country codes for a form, a shipping rule or a data mapping and wants the answer to be an array it can read, cache and assert on in a test, since the lookup surface is four methods and the output is documented field by field.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 57 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the standard actually covers, and what this package leaves out

The package's own note is the first thing to read, and it defines the boundary. This package is limited to ISO 3166-1 data, a subset of ISO 3166. That matters more than it sounds, because people often reach for a country list when they want regions, provinces or time zones, and none of those are here. The README explains what ISO 3166-1 is, describing it as part of the ISO 3166 standard published by the International Organization for Standardization, defining codes for the names of countries, dependent territories, and special areas of geographical interest, with the official name of the standard being Codes for the representation of names of countries and their subdivisions, Part 1: Country codes. It defines three sets of country codes. The alpha-2 codes are the two-letter ones, described as the most widely used of the three and used most prominently for the internet's country code top level domains, with a few exceptions. The alpha-3 codes are three letters and allow a better visual association between the code and the country name than alpha-2. The numeric codes are three digits, identical to those developed and maintained by the United Nations Statistics Division, with the advantage of script independence, and therefore useful for people or systems using non-Latin scripts. So the three code systems exist for different reasons, and a library that returns all three at once lets you pick the one your data model already uses.

Four lookup methods, one plain array back

The API is small enough to read in one screen, and that is the design. The quick guide in the README shows the same object constructed and a different method called for each of the code systems.

php
$data = (new League\ISO3166\ISO3166)->name($name);
$data = (new League\ISO3166\ISO3166)->alpha2($alpha2);
$data = (new League\ISO3166\ISO3166)->alpha3($alpha3);
$data = (new League\ISO3166\ISO3166)->numeric($numeric);

The class is League\ISO3166\ISO3166, and each method takes the value you have and returns the record. The return value is an array, and the documented sample for the Netherlands shows exactly which keys you get.

php
[
    'name' => 'Netherlands',
    'alpha2' => 'NL',
    'alpha3' => 'NLD',
    'numeric' => '528',
    'currency' => [
        'EUR',
    ]
]

So a lookup by alpha-2 gives you the name, the alpha-3 form, the numeric form and a currency list, and the currency is a list rather than a single string because a country can have more than one. That shape is the point of the library. There is no hydration step, no entity, no lazy loading and no database. You get an array, and you can assert on it in a unit test with the same ease you would assert on a JSON fixture. For a form that stores a country code next to an address, or a pricing rule that switches on the numeric code, that is the whole requirement, and a library that returned an opaque object with getters would make the test awkward for no gain.

Installation through Composer, and the sourcing of the data

Installation is a single Composer requirement.

sh
$ composer require league/iso3166

The repository root confirms this is a normal Composer package rather than a framework plugin. There is a composer.json, a src/ directory holding the code and a tests/ directory for the test suite, with phpunit.xml.dist configuring the run and a .php-cs-fixer.dist.php file for code style, so the project follows the tooling conventions of the PHP library ecosystem rather than inventing its own. Static analysis is set up too, with phpstan.neon.dist and a phpstan-baseline.neon, and coverage is tracked through Codecov. The data source is credited explicitly, and this is the part worth reading carefully if you care about the licence of what you ship. The source is ISO 3166-1 by Wikipedia, licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License, plus www.iso.org. The project itself is MIT licensed, so your code is unencumbered, but the underlying text that the data was derived from carries a share alike obligation, which is a different thing from MIT and is worth a legal review if you redistribute the dataset itself rather than using the library.

Where the data can go stale, and who is responsible for it

The README's note on freshness is unusually direct about the risk. The maintainer writes that they do their best to keep the data up to date, but asks readers to open an issue if they find errors or omissions. That is the honest characterisation of a hand maintained dataset: it is accurate most of the time and it is not automatically synchronised with the ISO registry. For country codes the churn rate is very low, and a change to an alpha-2 assignment or a name string is rare, so the practical risk is a typo or an omission rather than a systematic drift. Still, the failure mode matters. A country that is missing from the table does not throw an obvious error at the point of use, it fails a validation somewhere downstream, and a validation that silently accepts an unknown code is worse than one that rejects it. There is a second dimension to freshness, which is version pinning. The recent release list shows 4.5.0 on 2026-08-27, 4.4.0 on 2026-01-02 and 4.3.3 on 2025-06-05, and a data update in a package like this is a major version event because the contents change, so a deployment that pins a version gets a frozen snapshot of the table. The repository carries a CHANGELOG.md, which is where you look to see whether a version bump moved names, added entries or changed a code.

What this package will not give you

Three limits are worth being concrete about. The first is scope, already noted, that there are no subdivisions, so a checkout form that needs a province or a state cannot be built on this data and needs a different dataset. The second is the currency field. The sample shows a currency list with a single entry, EUR, for the Netherlands, and the documentation does not promise a complete, maintained currency table with its own metadata, so treat that key as a convenience value that came with the record rather than as a feature you can build a pricing engine on. The third is what the library does not do at all. There is no normalisation, no fuzzy matching and no validation helper, so a user who types Netherlands, Holland and The Netherlands has to be handled by your own code before you call the name method, and the fact that a lookup can be performed by name does not mean it is tolerant of the many ways names are written in real input. The deeper point is that a data package is a dependency on a snapshot, and a snapshot is something you can vendor. If your application needs a handful of countries for a dropdown, copying the relevant rows into your own project removes the dependency and the update question entirely, and the library's value grows as the number of countries you need grows.

Where it sits against the alternatives

The alternative is not another package so much as a different way of getting the same table. Intl, the PHP extension that wraps ICU, exposes country and locale data as part of the platform, which means no Composer dependency and no data snapshot of your own, at the cost of a different API shape and of data that belongs to the ICU release your PHP build carries. A country list published as a JSON or PHP file in your own repository gives you a table you control, with no runtime dependency at all, and the maintenance burden lands on you, which is why the churn argument rarely favours it once the list gets long. Against those two, league/iso3166 sits in the middle. It is a real dependency with real releases, so a scheduled update is a Composer operation rather than a data migration, and it exposes a documented and stable lookup surface rather than a platform's locale conventions. What it does not do is solve normalisation or currency metadata, and it does not extend beyond ISO 3166-1. If your requirement is a country dropdown in a PHP form, this library is a reasonable default and the decision is close to a tie. If your requirement is regional codes, international dialling or a money table, none of the three routes is short.

Editorial conclusion

league/iso3166 suits a PHP application that needs country codes for a form, a shipping rule or a data mapping and wants the answer to be an array it can read, cache and assert on in a test, since the lookup surface is four methods and the output is documented field by field. It is the wrong tool if you need subdivisions, because the README states plainly that the package is limited to ISO 3166-1, a subset of ISO 3166, so a region or province table is out of scope, and it is the wrong tool if you want a currency list, since currency appears in the data sample as a single EUR entry for the Netherlands and nothing in the documentation promises a complete currency table. Before you adopt it, pin the version, note that 4.5.0 shipped on 2026-08-27, and check the CHANGELOG.md file in the repository to see what moved, then open the data sample in the README against your own expectations before you rely on it.

Frequently asked questions

How do I install league/iso3166?

Run composer require league/iso3166. The package is on Packagist under the name league/iso3166 and the documentation site is iso3166.thephpleague.com, with a using section that covers the full API.

What does a league/iso3166 lookup return?

An array with the name, alpha2, alpha3 and numeric keys, plus a currency list. The documented sample for the Netherlands returns the name Netherlands, alpha2 NL, alpha3 NLD, numeric 528 and a currency array containing EUR.

Does league/iso3166 include states, provinces or regions?

No. The README states that this package is limited to ISO 3166-1 data, a subset of ISO 3166, and ISO 3166-1 defines codes for countries, dependent territories and special areas of geographical interest rather than country subdivisions.

Official sources

  1. alcohol/iso3166 on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/alcohol-iso3166.svg)](https://hysenlabs.com/projects/alcohol-iso3166)

Was this useful?