[Update: here is a service that can be used either in browser or as an API to check multiple personal codes, using the functions described below: https://pr.lapas.info/ak]
Below is a simple function for PHP to check if a number is a valid Lithuanian personal identification number. As I made it for Codeigniter 4, it is included in a class (that can be easily integrated into CI4 framework), but if you want, you can use it as a standalone function.
By default it does not consider valid the numbers with future dates (as people at the time of validation cannot have such numbers). But it might be modified easily to allow for such theoretical numbers.
To check an ID outside the Codeigniter 4 validation context, you would do something like this:
$check = new CustomRules(); $error = ''; $code = '36709010185'; echo $check->valid_lt_id($code, $error) ? 'ok' : $error; // prints "Lithuanian Personal Identification Number is not valid: // wrong control number" $error = ''; $code = '36709010186'; echo $check->valid_lt_id($code, $error) ? 'ok' : $error; // prints "ok"
To use the class within your Codeigniter 4 project follow the instructions in documentation. You may also want to add translation to the messages if the function should work not only in English (again, see documentation examples for that).
So, here is the class with the relevant function:
/** * Codeigniter 4 validation rule for Lithuanian personal idntification number */ class CustomRules { public function valid_lt_id($value, ?string &$error = null): bool { $valid = true; $error_msg = ''; //check length/type if ($valid && (strlen($value) !== 11 || !is_numeric($value))) { $valid = false; $error_msg = 'length not equal to 11 numbers, or not all numbers'; } $digits = str_split($value); //check date for validity if ($valid) { if (in_array($digits[0], [1, 2])) { $prefix = '18'; } elseif (in_array($digits[0], [3, 4])) { $prefix = '19'; } elseif (in_array($digits[0], [5, 6])) { $prefix = '20'; } else { $prefix = '21'; } $fullDate = $prefix . substr($value, 1, 6); $dateFormat = 'Ymd'; // Create a DateTime object from the provided date string $date = DateTime::createFromFormat($dateFormat, $fullDate); // Check if the date is valid and the input format is correct $valid = $date && $date->format($dateFormat) === ($fullDate); if (!$valid) { $error_msg = 'wrong date inside number'; } } // check date for not future if ($valid) { $valid = $fullDate <= date('Ymd'); if (!$valid) { $error_msg = 'date in the future cannot be correct'; } } // check control number if ($valid) { $last = null; $s = $digits[0] * 1 + $digits[1] * 2 + $digits[2] * 3 + $digits[3] * 4 + $digits[4] * 5 + $digits[5] * 6 + $digits[6] * 7 + $digits[7] * 8 + $digits[8] * 9 + $digits[9] * 1; if (($s % 11) !== 10) { $last = $s % 11; } else { $s = $digits[0] * 3 + $digits[1] * 4 + $digits[2] * 5 + $digits[3] * 6 + $digits[4] * 7 + $digits[5] * 8 + $digits[6] * 9 + $digits[7] * 1 + $digits[8] * 2 + $digits[9] * 3; if (($s % 11) !== 10) { $last = $s % 11; } else { $last = 0; } } $valid = $digits[10] == $last; if (!$valid) { $error_msg = 'wrong control number'; } } //check if the order number is not zero, should never be if ($valid && (string) substr($value, 7, 3) === '000') { $valid = false; $error_msg = 'wrong registration number'; } if ($valid) { return true; } // $error = lang('myerrors.invalidCode'); $error = 'Lithuanian Personal Identification Number is not valid: ' . $error_msg; return false; } }
Lithuanian person identification number structure is described in this Wikipedia article. The most complicated part is the last digit – control number. So, if you ever need to fake such numbers for tests, below I provide a function that, upon receiving an otherwise soundly composed personal identification number will spit it out with the 11th digit calculated correctly.
/** * This function adds/updates the 11th digit to the Lithuanian Personal * Identification Number supplied as parameter to function thus making it * a valid number. */ function completeLPIN(int $code): int { if (strlen($code) < 10) { throw new Exception( 'Too few digits; Lithuanian personal code has ' . '11 digits, and this function has to receive at ' . 'least the first 10.' ); // exception saying "too few numbers" here } $ak = str_split($code); $last = null; $s = $ak[0] * 1 + $ak[1] * 2 + $ak[2] * 3 + $ak[3] * 4 + $ak[4] * 5 + $ak[5] * 6 + $ak[6] * 7 + $ak[7] * 8 + $ak[8] * 9 + $ak[9] * 1; if (($s % 11) !== 10) { $last = $s % 11; } else { $s = $ak[0] * 3 + $ak[1] * 4 + $ak[2] * 5 + $ak[3] * 6 + $ak[4] * 7 + $ak[5] * 8 + $ak[6] * 9 + $ak[7] * 1 + $ak[8] * 2 + $ak[9] * 3; if (($s % 11) !== 10) { $last = $s % 11; } else { $last = 0; } } return substr($code, 0, 10) . $last; } echo completeLPIN(3770909012); // would output: // 37709090123
Leave a Reply