视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
PHP验证身份证格式
2020-11-03 23:12:10 责编:小采
文档


互联网公司对身份证验证的需求越来越多,然而普通的小公司是无法对接门的身份认证系统的。几乎都是在网上买一些大的互联网公司的一些认证服务。即使是便宜一些的认证价格也达到了10万次/万元。也就是一角钱一次了,还是挺贵哈。所以为了减少公司的开支,我们在拿到用户提交的身份证信息去认证前应该自己先检验一下身份证的格式,如果连最基本的身份证格式就不满足的话,我们完全可以直接驳回,不必走接下来的花钱认证流程了,而且也可以建立一个用户身份证表,把每次认证通过的数据存起来,以后每次都先从自己系统里的用户身份证表查询,查不到再去走认证流程,最大化节省公司开支。
这里提供一个初步验证身份证格式的PHP身份证验证类。该类只提供一个静态方法isValid接口,使用起来也很简单,只需要使用IdentityCard::isValid即可验证。可以放到自己项目中当做工具类。该方法可以同时验证15位的老身份证和18位的新身份证格式
PHP版本: >=7.0.0
注: 如果PHP版本低于7.0版本只需要把类中方法的参数取消掉即可使用。

class IdentityCard
{
 /**
 * 校验身份证号是否合法
 * @param string $num 待校验的身份证号
 * @return bool
 */
 public static function isValid(string $num)
 {
 //老身份证长度15位,新身份证长度18位
 $length = strlen($num);
 if ($length == 15) { //如果是15位身份证

 //15位身份证没有字母
 if (!is_numeric($num)) {
 return false;
 }
 // 省市县(6位)
 $areaNum = substr($num, 0, 6);
 // 出生年月(6位)
 $dateNum = substr($num, 6, 6);

 } else if ($length == 18) { //如果是18位身份证

 //基本格式校验
 if (!preg_match('/^d{17}[0-9xX]$/', $num)) {
 return false;
 }
 // 省市县(6位)
 $areaNum = substr($num, 0, 6);
 // 出生年月日(8位)
 $dateNum = substr($num, 6, 8);

 } else { //假身份证
 return false;
 }

 //验证地区
 if (!self::isAreaCodeValid($areaNum)) {
 return false;
 }

 //验证日期
 if (!self::isDateValid($dateNum)) {
 return false;
 }

 //验证最后一位
 if (!self::isVerifyCodeValid($num)) {
 return false;
 }

 return true;
 }

 /**
 * 省市自治区校验
 * @param string $area 省、直辖市代码
 * @return bool
 */
 private static function isAreaCodeValid(string $area) {
 $provinceCode = substr($area, 0, 2);

 // 根据GB/T2260—999,省市代码11到65
 if (11 <= $provinceCode && $provinceCode <= 65) {
 return true;
 } else {
 return false;
 }
 }

 /**
 * 验证出生日期合法性
 * @param string $date 日期
 * @return bool
 */
 private static function isDateValid(string $date) {
 if (strlen($date) == 6) { //15位身份证号没有年份,这里拼上年份
 $date = '19'.$date;
 }
 $year = intval(substr($date, 0, 4));
 $month = intval(substr($date, 4, 2));
 $day = intval(substr($date, 6, 2));

 //日期基本格式校验
 if (!checkdate($month, $day, $year)) {
 return false;
 }

 //日期格式正确,但是逻辑存在问题(如:年份大于当前年)
 $currYear = date('Y');
 if ($year > $currYear) {
 return false;
 }
 return true;
 }

 /**
 * 验证18位身份证最后一位
 * @param string $num 待校验的身份证号
 * @return bool
 */
 private static function isVerifyCodeValid(string $num)
 {
 if (strlen($num) == 18) {
 $factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
 $tokens = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];

 $checkSum = 0;
 for ($i = 0; $i < 17; $i++) {
 $checkSum += intval($num{$i}) * $factor[$i];
 }

 $mod = $checkSum % 11;
 $token = $tokens[$mod];

 $lastChar = strtoupper($num{17});

 if ($lastChar != $token) {
 return false;
 }
 }
 return true;
 }
}

使用示例:

// 测试
$num = '33071919610920021X';
if (IdentityCard::isValid($num)) {
 echo '身份证格式正确';
} else {
 echo '身份证格式不正确';
}

下面是身份证编码各个部分的含义:

//=============新的18位身份证号码各位的含义:=======================
//1-2位省、自治区、直辖市代码;11-65
//3-4位地级市、盟、自治州代码;
//5-6位县、县级市、区代码;
//7-14位出生年月日,比如19670401代表1967年4月1日;
//15-17位为顺序号,其中17位男为单数,女为双数;
//18位为校验码,0-9和X,由公式随机产生。
//举例:
//130503 19670401 0012这个身份证号的含义: 13为河北,05为邢台,03为桥西区,出生日期为1967年4月1日,顺序号为001,2为验证码
//===========15位身份证号码各位的含义:=======================
//1-2位省、自治区、直辖市代码;
//3-4位地级市、盟、自治州代码;
//5-6位县、县级市、区代码;
//7-12位出生年月日,比如670401代表1967年4月1日,这是和18位号码的第一个区别;
//13-15位为顺序号,其中15位男为单数,女为双数;
//与18位身份证号的第二个区别:没有最后一位的验证码。
//举例:
//130503 670401 001的含义; 13为河北,05为邢台,03为桥西区,出生日期为1967年4月1日,顺序号为001。

下载本文
显示全文
专题