diff --git a/README.md b/README.md index c7b8e42..6ba2dfd 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,47 @@ $response = $checker->check(); echo $response; // true ``` +### Formal validation + +Use the Validator to verify if the given codice fiscale is formally valid. The additional configuration array for the `Validator` has the given available keys: +- "omocodiaAllowed": whether to allow or not omocodia, defaults to true; +- "century": for people over 100 years old, it is not possibile to derive unambiguously birth year, so you can specify the century (for example '18' for a person birth in 1899). It allows to check birth date existence. Defaults to null (auto calculation of the century). + +```php +use CodiceFiscale\Validator; + +$codiceFiscale = "RSSMRA85T10A562S"; + +$validator = new Validator($codiceFiscale); + +$response = $validator->isFormallyValid(); +echo $response; // true +``` + +### Inverse calculation + +Use the InverseCalculator to extract birth date, gender and the belfiore code from the given codice fiscale. The additional configuration array for the `InverseCalculator` has the keys already described for the `Validator`. + +```php +use CodiceFiscale\InverseCalculator; + +$codiceFiscale = "RSSMRA85T10A562S"; + +$inverseCalculator = new InverseCalculator($codiceFiscale); + +$subject = $inverseCalculator->getSubject(); +var_dump($response); +// object(CodiceFiscale\Subject)[449] +// private 'name' => null +// private 'surname' => null +// private 'birthDate' => +// object(DateTime)[452] +// public 'date' => string '1985-12-10 00:00:00.000000' (length=26) +// public 'timezone_type' => int 3 +// public 'timezone' => string 'Europe/Berlin' (length=13) +// private 'gender' => string 'M' (length=1) +// private 'belfioreCode' => string 'A562' (length=4) +``` Test ---- diff --git a/src/CodiceFiscale/AbstractCalculator.php b/src/CodiceFiscale/AbstractCalculator.php new file mode 100644 index 0000000..566a46f --- /dev/null +++ b/src/CodiceFiscale/AbstractCalculator.php @@ -0,0 +1,170 @@ + + */ +abstract class AbstractCalculator +{ + + // women char + const CHR_WOMEN = 'F'; + + // male char + const CHR_MALE = 'M'; + + /** + * Array of all available months. + */ + protected $months = array( + '1' => 'A', + '2' => 'B', + '3' => 'C', + '4' => 'D', + '5' => 'E', + '6' => 'H', + '7' => 'L', + '8' => 'M', + '9' => 'P', + '10' => 'R', + '11' => 'S', + '12' => 'T', + ); + + /** + * Array of all avaialable odd characters. + */ + protected $odd = array( + '0' => 1, + '1' => 0, + '2' => 5, + '3' => 7, + '4' => 9, + '5' => 13, + '6' => 15, + '7' => 17, + '8' => 19, + '9' => 21, + 'A' => 1, + 'B' => 0, + 'C' => 5, + 'D' => 7, + 'E' => 9, + 'F' => 13, + 'G' => 15, + 'H' => 17, + 'I' => 19, + 'J' => 21, + 'K' => 2, + 'L' => 4, + 'M' => 18, + 'N' => 20, + 'O' => 11, + 'P' => 3, + 'Q' => 6, + 'R' => 8, + 'S' => 12, + 'T' => 14, + 'U' => 16, + 'V' => 10, + 'W' => 22, + 'X' => 25, + 'Y' => 24, + 'Z' => 23, + ); + + /** + * Array of all avaialable even characters. + */ + protected $even = array( + '0' => 0, + '1' => 1, + '2' => 2, + '3' => 3, + '4' => 4, + '5' => 5, + '6' => 6, + '7' => 7, + '8' => 8, + '9' => 9, + 'A' => 0, + 'B' => 1, + 'C' => 2, + 'D' => 3, + 'E' => 4, + 'F' => 5, + 'G' => 6, + 'H' => 7, + 'I' => 8, + 'J' => 9, + 'K' => 10, + 'L' => 11, + 'M' => 12, + 'N' => 13, + 'O' => 14, + 'P' => 15, + 'Q' => 16, + 'R' => 17, + 'S' => 18, + 'T' => 19, + 'U' => 20, + 'V' => 21, + 'W' => 22, + 'X' => 23, + 'Y' => 24, + 'Z' => 25, + ); + + + /** + * Array of all avaialable omocodia characters. + */ + protected $omocodiaCodes = array( + '0' => 'L', + '1' => 'M', + '2' => 'N', + '3' => 'P', + '4' => 'Q', + '5' => 'R', + '6' => 'S', + '7' => 'T', + '8' => 'U', + '9' => 'V', + ); + + /** + * Calculate the sum by the given dictionary for the given temporary codice fiscale. + * + * @param $temporaryCodiceFiscale The temporary codice fiscale. + * @param $dictionaryArray The dictionary array. + * @param $i The start index value. + * @returns Returns the sum by the given dictionary for the given temporary codice fiscale. + */ + protected function calculateSumByDictionary($temporaryCodiceFiscale, $dictionaryArray, $i) + { + $sum = 0; + for (; $i < 15; $i = $i + 2) { + $k = $temporaryCodiceFiscale{$i}; + $sum = $sum + $dictionaryArray[$k]; + } + + return $sum; + } + + /** + * Calculate the check digit. + * + * @param $temporaryCodiceFiscale The first part of the codice fiscale. + * @returns Returns the check digit part of the codice fiscale. + */ + protected function calculateCheckDigit($temporaryCodiceFiscale) + { + $sumEven = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->even, 1); + $sumOdd = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->odd, 0); + + return chr(($sumOdd + $sumEven) % 26 + 65); + } +} diff --git a/src/CodiceFiscale/Calculator.php b/src/CodiceFiscale/Calculator.php index d8cfe10..8de8ecf 100644 --- a/src/CodiceFiscale/Calculator.php +++ b/src/CodiceFiscale/Calculator.php @@ -7,7 +7,7 @@ * * @author davidepastore */ -class Calculator +class Calculator extends AbstractCalculator { private $subject; private $omocodiaLevel = 0; @@ -17,124 +17,6 @@ class Calculator */ private $vowels = array('A', 'E', 'I', 'O', 'U'); - /** - * Array of all available months. - */ - private $months = array( - '1' => 'A', - '2' => 'B', - '3' => 'C', - '4' => 'D', - '5' => 'E', - '6' => 'H', - '7' => 'L', - '8' => 'M', - '9' => 'P', - '10' => 'R', - '11' => 'S', - '12' => 'T', - ); - - /** - * Array of all avaialable odd characters. - */ - private $odd = array( - '0' => 1, - '1' => 0, - '2' => 5, - '3' => 7, - '4' => 9, - '5' => 13, - '6' => 15, - '7' => 17, - '8' => 19, - '9' => 21, - 'A' => 1, - 'B' => 0, - 'C' => 5, - 'D' => 7, - 'E' => 9, - 'F' => 13, - 'G' => 15, - 'H' => 17, - 'I' => 19, - 'J' => 21, - 'K' => 2, - 'L' => 4, - 'M' => 18, - 'N' => 20, - 'O' => 11, - 'P' => 3, - 'Q' => 6, - 'R' => 8, - 'S' => 12, - 'T' => 14, - 'U' => 16, - 'V' => 10, - 'W' => 22, - 'X' => 25, - 'Y' => 24, - 'Z' => 23, - ); - - /** - * Array of all avaialable even characters. - */ - private $even = array( - '0' => 0, - '1' => 1, - '2' => 2, - '3' => 3, - '4' => 4, - '5' => 5, - '6' => 6, - '7' => 7, - '8' => 8, - '9' => 9, - 'A' => 0, - 'B' => 1, - 'C' => 2, - 'D' => 3, - 'E' => 4, - 'F' => 5, - 'G' => 6, - 'H' => 7, - 'I' => 8, - 'J' => 9, - 'K' => 10, - 'L' => 11, - 'M' => 12, - 'N' => 13, - 'O' => 14, - 'P' => 15, - 'Q' => 16, - 'R' => 17, - 'S' => 18, - 'T' => 19, - 'U' => 20, - 'V' => 21, - 'W' => 22, - 'X' => 23, - 'Y' => 24, - 'Z' => 25, - ); - - /** - * Array of all avaialable omocodia characters. - */ - private $omocodiaCodes = array( - '0' => 'L', - '1' => 'M', - '2' => 'N', - '3' => 'P', - '4' => 'Q', - '5' => 'R', - '6' => 'S', - '7' => 'T', - '8' => 'U', - '9' => 'V', - ); - /** * Create a Codice Fiscale instance. * @@ -244,7 +126,7 @@ private function calculateBirthDateAndGender() $year = $this->subject->getBirthDate()->format('y'); $month = $this->months[$this->subject->getBirthDate()->format('n')]; $day = $this->subject->getBirthDate()->format('d'); - if (strtoupper($this->subject->getGender()) == 'F') { + if (strtoupper($this->subject->getGender()) == self::CHR_WOMEN) { $day += 40; } @@ -261,39 +143,6 @@ private function calculateBelfioreCode() return strtoupper($this->subject->getBelfioreCode()); } - /** - * Calculate the check digit. - * - * @param $temporaryCodiceFiscale The first part of the codice fiscale. - * @returns Returns the check digit part of the codice fiscale. - */ - private function calculateCheckDigit($temporaryCodiceFiscale) - { - $sumEven = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->even, 1); - $sumOdd = $this->calculateSumByDictionary($temporaryCodiceFiscale, $this->odd, 0); - - return chr(($sumOdd + $sumEven) % 26 + 65); - } - - /** - * Calculate the sum by the given dictionary for the given temporary codice fiscale. - * - * @param $temporaryCodiceFiscale The temporary codice fiscale. - * @param $dictionaryArray The dictionary array. - * @param $i The start index value. - * @returns Returns the sum by the given dictionary for the given temporary codice fiscale. - */ - private function calculateSumByDictionary($temporaryCodiceFiscale, $dictionaryArray, $i) - { - $sum = 0; - for (; $i < 15; $i = $i + 2) { - $k = $temporaryCodiceFiscale{$i}; - $sum = $sum + $dictionaryArray[$k]; - } - - return $sum; - } - /** * Calculate the omocodia case (additional translation). * diff --git a/src/CodiceFiscale/InverseCalculator.php b/src/CodiceFiscale/InverseCalculator.php new file mode 100644 index 0000000..a5d0357 --- /dev/null +++ b/src/CodiceFiscale/InverseCalculator.php @@ -0,0 +1,55 @@ + + */ +class InverseCalculator extends Validator +{ + private $belfioreCode = null; + + /** + * Create an InverseCalculator instance. + * + * @param string $codiceFiscale the codice fiscale to validate + * @param array $properties An array with additional properties. + */ + public function __construct($codiceFiscale, $properties = array()) + { + parent::__construct($codiceFiscale, $properties); + + if ($this->isFormallyValid()) { + $codiceFiscaleWithoutOmocodia = $this->getCodiceFiscaleWithoutOmocodia(); + + // calculate belfiore code + $this->belfioreCode = substr($codiceFiscaleWithoutOmocodia, 11, 4); + } + } + + /** + * Return the belfiore code + * + * @return string + */ + public function getBelfioreCode() + { + return $this->belfioreCode; + } + + /** + * Return the Subject calculated from codice fiscale + * + * @return \CodiceFiscale\Subject + */ + public function getSubject() + { + return new Subject(array( + "gender" => $this->getGender(), + "birthDate" => $this->getBirthDate(), + "belfioreCode" => $this->getBelfioreCode() + )); + } +} diff --git a/src/CodiceFiscale/Validator.php b/src/CodiceFiscale/Validator.php new file mode 100644 index 0000000..e0d2ff0 --- /dev/null +++ b/src/CodiceFiscale/Validator.php @@ -0,0 +1,271 @@ + + */ +class Validator extends AbstractCalculator +{ + private $regexs = array( + 0 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z][0-9]{3}[a-z]$/i', + 1 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z][0-9]{2}[a-z]{2}$/i', + 2 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z][0-9][a-z]{3}$/i', + 3 => '/^[a-z]{6}[0-9]{2}[a-z][0-9]{2}[a-z]{5}$/i', + 4 => '/^[a-z]{6}[0-9]{2}[a-z][0-9][a-z]{6}$/i', + 5 => '/^[a-z]{6}[0-9]{2}[a-z]{8}$/i', + 6 => '/^[a-z]{6}[0-9][a-z]{9}$/i', + 7 => '/^[a-z]{16}$/i', + ); + private $omocodiaPositions = array(14, 13, 12, 10, 9, 7, 6); + + private $codiceFiscale; + private $omocodiaAllowed = true; + private $century = null; + + private $foundOmocodiaLevel = null; + private $codiceFiscaleWithoutOmocodia = null; + private $birthDate = null; + private $gender = null; + + private $error = null; + private $isValid = false; + + /** + * Create a Validator instance. + * + * @param string $codiceFiscale the codice fiscale to validate + * @param array $properties An array with additional properties. + */ + public function __construct($codiceFiscale, $properties = array()) + { + $this->codiceFiscale = strtoupper($codiceFiscale); + + if (array_key_exists('omocodiaAllowed', $properties)) { + $this->omocodiaAllowed = $properties['omocodiaAllowed']; + } + + if (array_key_exists('century', $properties)) { + $this->century = $properties['century']; + } + + try { + $this->validateLength(); + + $this->validateFormat(); + + $this->validateCheckDigit(); + + $this->validateAndReplaceOmocodia(); + + $this->validateBirthDateAndGender(); + + $this->isValid = true; + } catch (\Exception $e) { + $this->error = $e->getMessage(); + } + } + + /** + * Validates length + * + * @throws \Exception + */ + private function validateLength() + { + // check empty + if (empty($this->codiceFiscale)) { + throw new \Exception('The codice fiscale to validate is empty'); + } + + // check length + if (strlen($this->codiceFiscale) !== 16) { + throw new \Exception('The codice fiscale to validate has an invalid length'); + } + } + + /** + * Validates format + * + * @throws \Exception + */ + private function validateFormat() + { + $regexpValid = false; + if (!$this->omocodiaAllowed) { + // just one regex + if (preg_match($this->regexs[0], $this->codiceFiscale)) { + $this->foundOmocodiaLevel = 0; + $regexpValid = true; + } + } else { + // all the regex + $omocodiaLevelApplied = 0; + foreach ($this->regexs as $regex) { + if (preg_match($regex, $this->codiceFiscale)) { + $this->foundOmocodiaLevel = $omocodiaLevelApplied; + $regexpValid = true; + break; + } + $omocodiaLevelApplied++; + } + } + + if (!$regexpValid) { + throw new \Exception('The codice fiscale to validate has an invalid format'); + } + } + + /** + * Validates check digit + * + * @throws \Exception + */ + private function validateCheckDigit() + { + $checkDigit = $this->calculateCheckDigit($this->codiceFiscale); + if ($checkDigit != $this->codiceFiscale[15]) { + throw new \Exception('The codice fiscale to validate has an invalid control character'); + } + } + + /** + * Validates omocodia and replace with matching chars + * + * @throws \Exception + */ + private function validateAndReplaceOmocodia() + { + // check and replace omocodie + $this->codiceFiscaleWithoutOmocodia = $this->codiceFiscale; + for ($omocodiaCheck = 0; $omocodiaCheck < $this->foundOmocodiaLevel; $omocodiaCheck++) { + $positionToCheck = $this->omocodiaPositions[$omocodiaCheck]; + $charToCheck = $this->codiceFiscaleWithoutOmocodia[$positionToCheck]; + if (!in_array($charToCheck, $this->omocodiaCodes)) { + throw new \Exception('The codice fiscale to validate has an invalid character'); + } + $this->codiceFiscaleWithoutOmocodia[$positionToCheck] = array_search($charToCheck, $this->omocodiaCodes); + } + } + + /** + * Validates birthdate and gender + * + * @throws \Exception + */ + private function validateBirthDateAndGender() + { + // calculate day and sex + $day = (int) substr($this->codiceFiscaleWithoutOmocodia, 9, 2); + $this->gender = $day > 40 ? self::CHR_WOMEN : self::CHR_MALE; + + if ($this->gender === self::CHR_WOMEN) { + $day -= 40; + } + + // check day + if ($day > 31) { + throw new \Exception('The codice fiscale to validate has invalid characters for birth day'); + } + + // check month + $monthChar = substr($this->codiceFiscaleWithoutOmocodia, 8, 1); + if (!in_array($monthChar, $this->months)) { + throw new \Exception('The codice fiscale to validate has an invalid character for birth month'); + } + + // calculate month, year and century + $month = array_search($monthChar, $this->months); + $year = substr($this->codiceFiscaleWithoutOmocodia, 6, 2); + $century = $this->calculateCentury($year); + + // validate and calculate birth date + if (!checkdate($month, $day, $century.$year)) { + throw new \Exception('The codice fiscale to validate has an non existent birth date'); + } + + $this->birthDate = new \DateTime(); + $this->birthDate->setDate($century.$year, $month, $day)->setTime(0, 0, 0)->format('Y-m-d'); + } + + /** + * + * @param string $year + * @return string + */ + private function calculateCentury($year) + { + $currentDate = new \DateTime(); + $currentYear = $currentDate->format('y'); + if (!is_null($this->century)) { + $century = $this->century; + } else { + $currentCentury = substr($currentDate->format('Y'), 0, 2); + $century = $year < $currentYear ? $currentCentury : $currentCentury - 1; + } + + return $century; + } + + /** + * Return the validation error + * + * @return string + */ + public function getError() + { + return $this->error; + } + + /** + * Return true if the provided codice fiscale is valid, false otherwise + * + * @return boolean + */ + public function isFormallyValid() + { + return $this->isValid; + } + + /** + * Return true if the provided codice fiscale is an omocodia, false otherwise + * + * @return boolean + */ + public function isOmocodia() + { + return $this->foundOmocodiaLevel > 0; + } + + /** + * Return the provided codice fiscale, cleaned up by omocodia + * + * @return string + */ + protected function getCodiceFiscaleWithoutOmocodia() + { + return $this->codiceFiscaleWithoutOmocodia; + } + + /** + * Return the birth date + * + * @return \DateTime + */ + protected function getBirthDate() + { + return $this->birthDate; + } + + /** + * Return the gender + * + * @return string + */ + protected function getGender() + { + return $this->gender; + } +} diff --git a/test/CodiceFiscale/InverseCalculatorTest.php b/test/CodiceFiscale/InverseCalculatorTest.php new file mode 100644 index 0000000..ece87c1 --- /dev/null +++ b/test/CodiceFiscale/InverseCalculatorTest.php @@ -0,0 +1,220 @@ + + */ +class InverseCalculatorTest extends \PHPUnit_Framework_TestCase +{ + /** + * Test for inverse calculate. + * + * @dataProvider calculateProvider + */ + public function testInverseCalculate($codiceFiscale, $omocodiaAllowed, $century, $expectedSubject) + { + $inverseCalculator = new InverseCalculator($codiceFiscale, array( + 'omocodiaAllowed' => $omocodiaAllowed, + 'century' => $century + )); + $actual = $inverseCalculator->getSubject(); + $this->assertEquals($expectedSubject->getBelfioreCode(), $actual->getBelfioreCode()); + $this->assertEquals($expectedSubject->getBirthDate(), $actual->getBirthDate()); + $this->assertEquals($expectedSubject->getGender(), $actual->getGender()); + $this->assertEquals(null, $actual->getName()); + $this->assertEquals(null, $actual->getSurname()); + } + + + /** + * The calculate data provider. + */ + public function calculateProvider() + { + return array( + array( + 'RSSMRA85T10A562S', + true, + null, + new Subject( + array( + 'birthDate' => '1985-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ), + ), + array( + 'SNTRRT63E08H501T', + true, + null, + new Subject( + array( + 'birthDate' => '1963-05-08', + 'gender' => 'M', + 'belfioreCode' => 'H501', + ) + ) + ), + array( + 'RSSDVD89T10A562S', + true, + null, + new Subject( + array( + 'birthDate' => '1989-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ) + ), + array( + 'MNTMRA70M71C615I', + true, + 18, + new Subject( + array( + 'birthDate' => '1870-08-31', + 'gender' => 'F', + 'belfioreCode' => 'C615', + ) + ) + ), + array( + 'RSSMRA85T10A562S', + true, + null, + new Subject( + array( + 'birthDate' => '1985-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ), + ), + array( + 'RSSGFR85T10A562I', + true, + null, + new Subject( + array( + 'birthDate' => '1985-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ), + ), + array( + 'FOXMRA85T10A562G', + true, + null, + new Subject( + array( + 'birthDate' => '1985-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ), + ), + array( + 'RSSXXX85T10A562R', + true, + null, + new Subject( + array( + 'birthDate' => '1985-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ) + ), + array( + 'SNTRRT63E08H50ML', + true, + null, + new Subject( + array( + 'birthDate' => '1963-05-08', + 'gender' => 'M', + 'belfioreCode' => 'H501', + ) + ) + ), + array( + 'RSSMRA85T10A56NH', + true, + null, + new Subject( + array( + 'birthDate' => '1985-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ) + ), + array( + 'RSSMRA85T10ARSNO', + true, + null, + new Subject( + array( + 'birthDate' => '1985-12-10', + 'gender' => 'M', + 'belfioreCode' => 'A562', + ) + ), + ), + array( + 'DRSMRA90A01F839W', + true, + null, + new Subject( + array( + 'birthDate' => '1990-01-01', + 'gender' => 'M', + 'belfioreCode' => 'F839', + ) + ) + ), + array( + 'RSSNPL90A41F839J', + true, + null, + new Subject( + array( + 'birthDate' => '1990-01-01', + 'gender' => 'F', + 'belfioreCode' => 'F839', + ) + ) + ), + array( + 'DSSMRA90A01F839X', + true, + null, + new Subject( + array( + 'birthDate' => '1990-01-01', + 'gender' => 'M', + 'belfioreCode' => 'F839', + ) + ), + ), + array( + 'DRALYU90A01F839U', + true, + null, + new Subject( + array( + 'birthDate' => '1990-01-01', + 'gender' => 'M', + 'belfioreCode' => 'F839', + ) + ) + ), + ); + } +} diff --git a/test/CodiceFiscale/ValidatorTest.php b/test/CodiceFiscale/ValidatorTest.php new file mode 100644 index 0000000..bfffb06 --- /dev/null +++ b/test/CodiceFiscale/ValidatorTest.php @@ -0,0 +1,120 @@ + + */ +class ValidatorTest extends \PHPUnit_Framework_TestCase +{ + /** + * Test for validator. + * + * @dataProvider validatorProvider + */ + public function testValidationTrue($codiceFiscaleToValidate, $omocodiaAllowed, $secular, $isFormallyValid, $isOmocodia = false) + { + $validator = new Validator($codiceFiscaleToValidate, + array('omocodiaAllowed' => $omocodiaAllowed, + 'secular' => $secular) + ); + + $actual = $validator->isFormallyValid(); + $this->assertEquals($isFormallyValid, $actual); + + $this->{$isFormallyValid ? "assertEquals" : "assertNotEquals"}(null, $validator->getError()); + + if ($isFormallyValid && $isOmocodia) { + $this->assertEquals($isOmocodia, $validator->isOmocodia()); + } + } + + /** + * The validator provider. + */ + public function validatorProvider() + { + return array( + // valid + array( + 'RSSMRA85T10A562S', + true, + false, + true, + ), + // valid altough omocodia not allowed + array( + 'RSSMRA85T10A562S', + false, + false, + true, + ), + // check digit + array( + 'RSSMRA85T10A562T', + true, + false, + false, + ), + // valid with omocodia + array( + 'SNTRRT63E08H50ML', + true, + false, + true, + true + ), + // empty + array( + '', + true, + false, + false, + ), + // length + array( + 'RSSMRA85T10A562', + true, + false, + false, + ), + // regexp + array( + 'RS3MRA85T10A562S', + true, + false, + false, + ), + // birth day + array( + 'RSSMRA85T99A562U', + true, + false, + false, + ), + // omocodia character + array( + 'RSSMRA85T10A56AO', + true, + false, + false, + ), + // month + array( + 'RSSMRA85Z10A562B', + true, + false, + false, + ), + // date + array( + 'RSSMRA85B30A562G', + true, + false, + false, + ), + ); + } +}