身份证校验算法

验证原理

我国的18位公民身份号码是特征组合是由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

第1、2位表示省级行政区。第1位数字是以前的大区制代码。第2位是大区所在省市编码。全国共分为8个大区:华北(1)、东北(2)、华东(3)、中南(4)、西南(5)、西北(6)、台湾(7)和港澳(8)。

第3、4位表示地级行政区。其中,01-20,51-70表示地级市(除儋州市);21-50表示地区、自治州、盟;90表示省直辖县级行政单位(含儋州市);直辖市身份证中01表示市辖区,02表示县。

第5、6位表示县级行政区。01-18表示市辖区或地区、自治州、盟辖县级市;21-80表示县、旗;81-99表示省直辖县级行政单位。

第7~14位表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。例如:2023年10月1日就用20231001表示。

第15~17位表示在同一地址码所标识的区域范围内,对同年、月、日出生的人员编定的顺序号。其中第十七位奇数分给男性,偶数分给女性。

第18位为根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2计算出来的检验码。如果某人的尾号为10,那么就得用X来代替,这是罗马数字十,正确读法是十,不读艾克斯或叉。

代码实现

/**
 * 校验身份证
 */
function is_idcard($id)
{
    $id = strtoupper($id);
    $regx = '/(^\d{15}$)|(^\d{17}([0-9]|X)$)/';
    $arr_split = array();
    if (!preg_match($regx, $id)) {
        return false;
    }
    if (15 == strlen($id)) {
        //检查15位
        $regx = '/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/';

        @preg_match($regx, $id, $arr_split);
        //检查生日日期是否正确
        $dtm_birth =
            '19' . $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
        if (!strtotime($dtm_birth)) {
            return false;
        } else {
            return true;
        }
    }
    //检查18位
    else {
        $regx = '/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/';
        @preg_match($regx, $id, $arr_split);
        $dtm_birth = $arr_split[2] . '/' . $arr_split[3] . '/' . $arr_split[4];
        if (!strtotime($dtm_birth)) {
            //检查生日日期是否正确
            return false;
        } else {
            //检验18位身份证的校验码是否正确。
            //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
            $arr_int = array(
                7,
                9,
                10,
                5,
                8,
                4,
                2,
                1,
                6,
                3,
                7,
                9,
                10,
                5,
                8,
                4,
                2,
            );
            $arr_ch = array(
                '1',
                '0',
                'X',
                '9',
                '8',
                '7',
                '6',
                '5',
                '4',
                '3',
                '2',
            );
            $sign = 0;
            for ($i = 0; $i < 17; $i++) {
                $b = (int) $id[$i];
                $w = $arr_int[$i];
                $sign += $b * $w;
            }
            $n = $sign % 11;
            $val_num = $arr_ch[$n];
            if ($val_num != substr($id, 17, 1)) {
                // 校验位失败
                return false;
            }
        }
        // 成功,这里还可以进行前6位验证,也可以对17位进行性别验证
        return true;
    }
}

此处评论已关闭