Skip to content

ID Card

The Polish national identity card number (numer dowodu osobistego) consists of three uppercase letters followed by six digits, where the final digit is a checksum computed using the ICAO 9303 weighted algorithm. The letters O and Q are excluded from the series.

use SlashLab\Numerik\Numerik;
// Boolean validation
Numerik::idCard()->isValid('ABC123454'); // true
// Lowercase input and hyphens are stripped during normalisation
Numerik::idCard()->isValid('abc-123-454'); // true
// Rich result
$result = Numerik::idCard()->validate('ABC123454');
$result->isValid; // true
// Parse to value object
$idCard = Numerik::idCard()->parse('ABC123454');
// Null on failure instead of exception
$idCard = Numerik::idCard()->tryParse('bad-input'); // null

parse() returns a SlashLab\Numerik\ValueObjects\IdCard instance or throws on failure. tryParse() returns a SlashLab\Numerik\ValueObjects\IdCard instance or null if parsing fails.

MethodReturn typeDescription
getRaw()stringThe original input, untouched.
getNormalized()string3 uppercase letters + 6 digits, e.g. ABC123454.
__toString()stringSame as getNormalized().
MethodReturn typeDescription
getSeries()stringFirst 3 letters — the document series, e.g. ABC.
getSequentialNumber()string5-digit sequential number (positions 4–8), e.g. 12345.
getCheckDigit()stringSingle check digit at position 9, e.g. 4.
$idCard = Numerik::idCard()->parse('ABC123454');
$idCard->getRaw(); // 'ABC123454'
$idCard->getNormalized(); // 'ABC123454'
$idCard->getSeries(); // 'ABC'
$idCard->getSequentialNumber(); // '12345'
$idCard->getCheckDigit(); // '4'
// Lowercase and hyphens normalise to the same value
$idCard = Numerik::idCard()->parse('abc-123-454');
$idCard->getRaw(); // 'abc-123-454'
$idCard->getNormalized(); // 'ABC123454'
  1. Reject inputs over 32 characters; fail with InvalidLength.
  2. Strip spaces and hyphens. Convert to uppercase.
  3. Assert exactly 9 characters remain; fail with InvalidLength.
  4. Assert the first 3 characters are letters; fail with InvalidCharacters.
  5. Assert the series contains no O or Q; fail with InvalidFormat.
  6. Assert characters 4–9 are digits; fail with InvalidCharacters.
  7. Apply the ICAO 9303 checksum over positions 1–8; fail with InvalidChecksum if the result does not match position 9. See Algorithms.
ReasonValueWhen
InvalidLengthinvalid_lengthNumber is not exactly 9 characters after normalisation, or raw input exceeds 32 characters.
InvalidCharactersinvalid_charactersNon-letter characters in the series, or non-digit characters in the number portion.
InvalidFormatinvalid_formatSeries contains the letter O or Q.
InvalidChecksuminvalid_checksumICAO 9303 check digit does not match.
  • Passport — same ICAO 9303 checksum algorithm; identifies the same person in an international context.
  • PESEL — universal personal identifier linked to the same individual.
If this saved you time → ☕ Buy me a coffee