Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple PHP class to check the validity of an identity card and to get some basic information like the age of the person.
<?php
/**
* PHP class to check the validity of an identity card and to get some basic information like the age of the person.
*
* @author PHP-einfach.de <https://www.php-einfach.de/diverses/personalausweis-ueberpruefen/>
* @author Sebastian Krätzig <info@ts3-tools.info>
*/
class IdentityCard
{
/**
* Constructor
*/
public function __construct()
{
// constructor
}
/**
* Checks, if the identity card is a new type
*
* @param string $identity_card_identifier Unique identity card identifier
* @return boolean True, when the identity card is a new type, False when an old type
* @throws Exception Returns an exception, when the type could not be identified
*/
private function is_new_identity_card_type($identity_card_identifier = null)
{
if ($identity_card_identifier == null OR empty(trim($identity_card_identifier)))
{
throw new Exception("No unique identity card identifier was provided.");
}
// @todo Regex could be improved: https://de.wikipedia.org/wiki/Ausweisnummer
if (!preg_match('/^[0-9A-Z]{10,11}\s[0-9]{7}\s[0-9A-Z]{7,8}\s[0-9]{1}$/', $identity_card_identifier))
{
throw new Exception("Unknown identity card type.");
}
$splits = explode(" ", strtoupper($identity_card_identifier));
if (strlen($splits[0]) == 11 && strlen($splits[1]) == 7 && strlen($splits[2]) == 7 && strlen($splits[3]) == 1)
{
return false;
}
return true;
}
/**
* Helper function to validate the identity card checksums
*
* @param string $id
* @param string $checksum
* @return boolean True, when the checksum is valid
*/
private function validate_checksum($id, $checknumber)
{
$p = 7;
$sum = 0;
for($i=0; $i < strlen($id); $i++)
{
$char = $id[$i];
if ($char >= '0' && $char <= '9')
{
$int = intval($char);
} else {
$int = ord($char)-55;
}
$sum += $int*$p;
if ($p==1)
{
$p=7;
} elseif ($p==3) {
$p=1;
} elseif ($p==7) {
$p=3;
}
}
$last_number = substr(strval($sum), -1);
if ($last_number != $checknumber)
{
return false;
}
return true;
}
/**
* Checks, if the identity cards checksum is valid
*
* @param string $identity_card_identifier Unique identity card identifier
* @return boolean True, when the identity card checksum is valid, False when it's invalid
* @throws Exception Returns an exception, when the type could not be identified
*/
public function identity_card_checksum_is_valid($identity_card_identifier)
{
$splits = explode(" ", strtoupper($identity_card_identifier));
$checksums = array();
$checksums[] = array(substr($splits[0],0,9), substr($splits[0],9,1));
$checksums[] = array(substr($splits[1],0,6), substr($splits[1],6,1));
$checksums[] = array(substr($splits[2],0,6), substr($splits[2],6,1));
$checksums[] = array(substr($splits[0],0,10).substr($splits[1],0,7).substr($splits[2],0,7), $splits[3]);
foreach($checksums as $checksum)
{
if (! $this->validate_checksum($checksum[0], $checksum[1]))
{
return false;
}
}
return true;
}
/**
* Checks, if the identity card is expired
*
* @param string $identity_card_identifier Unique identity card identifier
* @return boolean True, when the identity card is expired, False when it's still valid
*/
public function identity_card_expired($identity_card_identifier)
{
$splits = explode(" ", $identity_card_identifier);
$valid_until = mktime(0,0,0, substr($splits[2], 2, 2) , substr($splits[2], 4, 2) , "20".substr($splits[2], 0, 2));
if (time() < $valid_until)
{
return false;
}
return true;
}
/**
* Returns information about the person and identity card based on the unique identity card identifier
*
* @param string $identity_card_identifier Unique identity card identifier
* @return stdClass $data An object with information about the person (eg. birthday, identity card expiry date, country of origin, ...)
* @throws Exception Returns an exception, when the type could not be identified
*/
public function identity_card_info($identity_card_identifier)
{
$splits = explode(" ", $identity_card_identifier);
$data = new stdClass();
$data->birthday = new stdClass();
$data->birthday->day = $splits[1][4].$splits[1][5];
$data->birthday->month = $splits[1][2].$splits[1][3];
$data->birthday->year = ($splits[1][0].$splits[1][1] > intval(date('y'))) ? '19'.$splits[1][0].$splits[1][1] : '20'.$splits[1][0].$splits[1][1];
$data->identity_card = new stdClass();
$data->identity_card->expiry = new stdClass();
$data->identity_card->expiry->day = $splits[2][4].$splits[2][5];
$data->identity_card->expiry->month = $splits[2][2].$splits[2][3];
$data->identity_card->expiry->year = '20'.$splits[2][0].$splits[2][1];
try {
$is_new_identity_card_type = $this->is_new_identity_card_type($identity_card_identifier);
} catch (Exception $exception) {
throw new Exception($exception->getMessage());
}
if ($is_new_identity_card_type)
{
$data->country_of_origin = $splits[2][7];
} else {
$data->country_of_origin = $splits[0][10];
}
$data->authority_code = substr($splits[0], 0, 4);
return $data;
}
}
@Sebi94nbg
Copy link
Author

Sebi94nbg commented Sep 5, 2021

Example usage:

/**
 * New identity card since November 2010:
 * 
 * L1: IDD<<IdentityCardNumber<<<<<<<
 * L2: 5555<88888<<<<<<CheckNumber
 * 
 * Alter Personalausweis bis 2010:
 * 
 * L2: IdentityCardNumber<<5555<<88888<<<<<CheckNumber
 *
 * Required format for the PHP class: "IdentityCardNumber 5555 88888 CheckNumber" (divided by single spaces)
 */

// New identity card (Erika Mustermann)
$identity_card_identifier = "T220001293 6408125 2010315D 4";
// Old identity card (Erika Mustermann)
//$identity_card_identifier = "1220001297D 6408125 1710319 8";

$identity_card = new IdentityCard();

if(! $identity_card->identity_card_checksum_is_valid($identity_card_identifier))
{
    exit("Invalid identity card (checksum)!");
}

echo "Identity card information:<pre>";
try {
    $data = $identity_card->identity_card_info($identity_card_identifier);
} catch (Exception $exception) {
    exit("Error: ".$exception->getMessage());
}
print_r($data);

if($identity_card->identity_card_expired($identity_card_identifier))
{
    exit("Identity card expired!");
}

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment