preface

When I looked at the source code of the new company framework, I found this function, so I searched and encapsulated the id verification class.

At present, everyone’s ID number is mostly 18, of course, do not exclude some old people’s ID number is 15.

If the mandatory requirement is 18, it will be better, because there is no verification code for the 15-digit ID number, so to speak, as long as you understand the general structure, you can make a series of ID numbers.

Of course, if it is just a simple program check, the 18-digit ID card number can also be forged, but the forger needs to pay attention to it.

It is best to call the interface given by relevant departments for verification.

The verification of id card number written in this paper is only for the calculation under relevant rules, which can be done before the interface is called.

Id number rule

15th place: Province (2nd) + prefecture-level city (2nd) + County-level city (2nd) + Year of birth (2nd) + month of birth (2nd) + date of birth (2nd) + Serial number (3rd)

18th: Province (2nd) + prefecture-level city (2nd) + County-level city (2nd) + Year of birth (4th) + month of birth (2nd) + date of birth (2nd) + Serial number (3rd) + parity (1st)

In contrast, 18 had two more birth years and one parity bit than 15.

If the serial number is even, it means a girl, and if the serial number is odd, it means a boy.

Calculation of check bits:

There are 17 digits, which are:

7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2
Copy the code

Multiply the first 17 digits of your ID card by the corresponding digits above and add them up.

And then you take the magnitude of 11 using the sum.

Use the obtained value to find the corresponding character in the following 11 characters. This character is the check bit.

'1'.'0'.'X'.'9'.'8'.'7'.'6'.'5'.'4'.'3'.'2'
Copy the code

15 bit to 18 bit:

From the above analysis, it can be known that as long as the last year’s fractional sum check bit can be supplemented.

In general, you add 19 to the year.

The implementation of a validation class

Through the analysis of the rules of id number, we know that there are several things that can be done:

  • Check whether the identity is correct (generally does not change, and there are not many provinces)
  • Check prefecture-level and county-level cities (consider if you have the resources, but generally not recommended)
  • Check year month day
  • Check code

Of course, since some people may be using a 15-digit ID number, a conversion method is needed, but it is recommended to limit the need for 18-digit ID numbers.

Let’s start implementing:

Initialization:

class IDCardFilter
{
    /** * id card number check **@param  string $idCard
     * @return bool
     */
    public function vaild($idCard)
    {
        // Check whether the id card format is correct
        if (!$this->isCardNumber($idCard)) {
            return false;
        }

        // Convert 15 bits to 18 bits
        $idCard = $this->fifteen2Eighteen($idCard);

        // Check whether the province exists
        if (!$this->checkProvince($idCard)) {
            return false;
        }

        // Check whether the birthday is correct
        if (!$this->checkBirthday($idCard)) {
            return false;
        }

        // Check the verification code
        return $this->checkCode($idCard); }}Copy the code

The above has implemented a check method, which calls a number of methods in the class, one by one implementation.

Check whether it is id card number:

This part of the processing is relatively simple, a regular expression is done.

^\d{15}$^\d{15}$ (^ \ d {and} (\ d | X) $) to match 18 id number.

const REGX = '#(^\d{15}$)|(^\d{17}(\d|X)$)#';

/** * check if it is id number **@param  string $idCard
 * @return boolean
 */
public function isCardNumber($idCard)
{
    return preg_match(self::REGX, $idCard);
}
Copy the code

15 bit to 18 bit:

The logic is not complicated, first determine whether it is 15 bits, then determine the year to be added, and finally generate checksum code and return it.

/** ** 15 bits to 18 bits **@param  string $idCard
 * @return void
 */
public function fifteen2Eighteen($idCard)
{
    if(strlen($idCard) ! =15) {
        return $idCard;
    }

    // If the id sequence code is 996 997 998 999, these are special codes for people over 100 years old
    // $code = array_search(substr($idCard, 12, 3), [996, 997, 998, 999]) ! == false ? '18' : '19';
    // 19 is usually enough
    $code = 'the';
    $idCardBase = substr($idCard, 0.6) . $code . substr($idCard, 6.9);
    return $idCardBase . $this->genCode($idCardBase);
}
Copy the code

Verification code generation:

Detailed calculation rules see above, here will not do repeated elaboration.

/** * Generates the verification code **@param  string $idCardBase
 * @return void
 */
final protected function genCode($idCardBase)
{
    $idCardLength = strlen($idCardBase);
    if($idCardLength ! =17) {
        return false;
    }
    $factor = [7.9.10.5.8.4.2.1.6.3.7.9.10.5.8.4.2];
    $verifyNumbers = ['1'.'0'.'X'.'9'.'8'.'7'.'6'.'5'.'4'.'3'.'2'];
    $sum = 0;
    for ($i = 0; $i < $idCardLength; $i++) {
        $sum += substr($idCardBase, $i, 1) * $factor[$i];
    }
    $index = $sum % 11;
    return $verifyNumbers[$index];
}
Copy the code

Check if the province is correct:

protected $provinces = [
    11= >"Beijing".12= >"Tianjin".13= >"Hebei".14= >"Shanxi".15= >Inner Mongolia.21= >"Liaoning".22= >"Jilin".23= >"Heilongjiang".31= >"Shanghai".32= >"Jiangsu".33= >"Zhejiang".34= >"Anhui province".35= >"Fujian".36= >"Jiangxi".37= >"Shandong".41= >"Henan".42= >"Hubei".43= >"Hunan".44= >"Guangdong".45= >"Guangxi".46= >"Hainan".50= >"Chongqing".51= >"Sichuan".52= >"Guizhou".53= >"Yunnan".54= >"Tibet".61= >"Shaanxi".62= >"Gansu".63= >"Qinghai".64= >"The ningxia".65= >"Xinjiang".71= >"Taiwan".81= >"Hong Kong".82= >"Macau".91= >"Foreign"
];

/** * Check whether the province is correct **@param  string $idCard
 * @return void
 */
public function checkProvince($idCard)
{
    $provinceNumber = substr($idCard, 0.2);
    return isset($this->provinces[$provinceNumber]);
}
Copy the code

Check whether the birthday is correct:

This is also a re match, matching the year, month and day.

/** * Check whether the birthday is correct **@param  string $idCard
 * @return void
 */
public function checkBirthday($idCard)
{
    $regx = '#^\d{6}(\d{4})(\d{2})(\d{2})\d{3}[0-9X]$#';
    if(! preg_match($regx, $idCard, $matches)) {return false;
    }
    array_shift($matches);
    list($year, $month, $day) = $matches;
    return checkdate($month, $day, $year);
}
Copy the code

Check code comparison:

In other words, if you go from 15 to 18, you don’t even have to worry about that.

/** * Parity code comparison **@param  string $idCard
 * @return void
 */
public function checkCode($idCard)
{
    $idCardBase = substr($idCard, 0.17);
    $code = $this->genCode($idCardBase);
    return $idCard == ($idCardBase . $code);
}
Copy the code

The complete code

Portal: IDCardFilter

The last

This feature is novel at best, after all, I haven’t touched it before. I’m happy to add new members to the code snippet.

PHP verifies 15 – and 18-bit id numbers