• 售前

  • 售后

热门帖子
入门百科

PHP校验15位和18位身份证号的类封装

[复制链接]
爱之关怀阿飞米 显示全部楼层 发表于 2021-10-26 13:06:03 |阅读模式 打印 上一主题 下一主题
新公司框架源码的时间,发现了这个功能,于是搜刮一番并封装了一下身份证号校验的类。
目前各人的身份证号大多是 18 位的,当然,也不扫除有些老人的身份证号是 15 位的。
如果逼迫要求是 18 位的话,会比力好,由于 15 位的身份证号没有校验码,可以说,只要相识大概布局,随手都可以造出一系列身份证号码来。
当然,如果只是单纯的步伐校验, 18 位的身份证号码也可以伪造,就是必要伪造者花点心思。
最好的还是调用相干部门给的接口,举行校验。
本文所编写的身份证号码校验,只是针对相干规则下的计算,是调用接口前能做的变乱。
身份证号规则
15位:省份(2位) + 地级市(2位) + 县级市(2位) + 出生年(2位) + 出生月(2位) + 出生日(2位) + 序次号(3位)
18位:省份(2位) + 地级市(2位) + 县级市(2位) + 出生年(4位) + 出生月(2位) + 出生日(2位) + 序次号(3位) + 校验位(1位)
相比之下, 18位 比 15位 多出生年 2位 、校验位 1位 。
此中,序次号如果是偶数,则说明是女生,序次号是奇数,则说明是男生。
校验位的计算:
有17位数字,分别是:
7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2
分别用身份证的前 17 位乘以上面相应位置的数字,然后相加。
接着用相加的和对 11 取模。
用得到的值在下面 11 个字符里查找对应位置的字符,这个字符就是校验位。
'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'
15位转18位:
从上述的分析中,可以知道,只要补充上年分和校验位就可以了。
一般环境下年份补充都是加上 19 就可以了。
校验类的实现
通过分析身份证号的规则,相识到,有几点是可以做的:
      
  • 查抄身份是否正确(一般不会变化,而且省份不多)  
  • 查抄地级市和县级市(如果有这方面的资源,可以思量,不外一般不发起)  
  • 查抄年月日  
  • 查抄校验码
当然,由于可能部门人用的是 15位 的身份证号,所以必要一个转换的方法,不外,这里还是发起限定必要 18位 的身份证号。
下面开始实现:
初始化:
  1. class IDCardFilter
  2. {
  3.   /**
  4.    * 身份证号码校验
  5.    *
  6.    * @param string $idCard
  7.    * @return bool
  8.    */
  9.   public function vaild($idCard)
  10.   {
  11.     // 基础的校验,校验身份证格式是否正确
  12.     if (!$this->isCardNumber($idCard)) {
  13.       return false;
  14.     }
  15.     // 将 15 位转换成 18 位
  16.     $idCard = $this->fifteen2Eighteen($idCard);
  17.     // 检查省是否存在
  18.     if (!$this->checkProvince($idCard)) {
  19.       return false;
  20.     }
  21.     // 检查生日是否正确
  22.     if (!$this->checkBirthday($idCard)) {
  23.       return false;
  24.     }
  25.     // 检查校验码
  26.     return $this->checkCode($idCard);
  27.   }
  28. }
复制代码
上面已经实现了一个校验的方法,内里调用了类里的许多方法,下面逐一实现。
检测是否是身份证号码:
这一块的处理比力简朴,一个正则表达式搞定了。
此中, (^\d{15}$) 用于匹配 15位 身份证号的环境; (^\d{17}(\d|X)$) 用于匹配 18位 身份证号的环境。
  1. const REGX = '#(^\d{15}$)|(^\d{17}(\d|X)$)#';
复制代码
  1. /**
  2. * 检测是否是身份证号码
  3. *
  4. * @param string $idCard
  5. * @return boolean
  6. */
  7. public function isCardNumber($idCard)
  8. {
  9.   return preg_match(self::REGX, $idCard);
  10. }
复制代码
15位转18位:
逻辑不复杂,先判断是否是15位,然后判断必要添加的年份,终极天生校验码拼接返回就OK了。
  1. /**
  2. * 15位转18位
  3. *
  4. * @param string $idCard
  5. * @return void
  6. */
  7. public function fifteen2Eighteen($idCard)
  8. {
  9.   if (strlen($idCard) != 15) {
  10.     return $idCard;
  11.   }
  12.   // 如果身份证顺序码是996 997 998 999,这些是为百岁以上老人的特殊编码
  13.   // $code = array_search(substr($idCard, 12, 3), [996, 997, 998, 999]) !== false ? '18' : '19';
  14.   // 一般 19 就够了
  15.   $code = '19';
  16.   $idCardBase = substr($idCard, 0, 6) . $code . substr($idCard, 6, 9);
  17.   return $idCardBase . $this->genCode($idCardBase);
  18. }
复制代码
校验码的天生:
详细计算规则见上面,这里就不做重复的论述了。
  1. /**
  2. * 生成校验码
  3. *
  4. * @param string $idCardBase
  5. * @return void
  6. */
  7. final protected function genCode($idCardBase)
  8. {
  9.   $idCardLength = strlen($idCardBase);
  10.   if ($idCardLength != 17) {
  11.     return false;
  12.   }
  13.   $factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  14.   $verifyNumbers = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
  15.   $sum = 0;
  16.   for ($i = 0; $i < $idCardLength; $i++) {
  17.     $sum += substr($idCardBase, $i, 1) * $factor[$i];
  18.   }
  19.   $index = $sum % 11;
  20.   return $verifyNumbers[$index];
  21. }
复制代码
查抄省份是否正确:
  1. protected $provinces = [
  2.   11 => "北京", 12 => "天津", 13 => "河北",  14 => "山西", 15 => "内蒙古",
  3.   21 => "辽宁", 22 => "吉林", 23 => "黑龙江", 31 => "上海", 32 => "江苏",
  4.   33 => "浙江", 34 => "安徽", 35 => "福建",  36 => "江西", 37 => "山东", 41 => "河南",
  5.   42 => "湖北", 43 => "湖南", 44 => "广东",  45 => "广西", 46 => "海南", 50 => "重庆",
  6.   51 => "四川", 52 => "贵州", 53 => "云南",  54 => "西藏", 61 => "陕西", 62 => "甘肃",
  7.   63 => "青海", 64 => "宁夏", 65 => "新疆",  71 => "台湾", 81 => "香港", 82 => "澳门", 91 => "国外"
  8. ];
  9. /**
  10. * 检查省份是否正确
  11. *
  12. * @param string $idCard
  13. * @return void
  14. */
  15. public function checkProvince($idCard)
  16. {
  17.   $provinceNumber = substr($idCard, 0, 2);
  18.   return isset($this->provinces[$provinceNumber]);
  19. }
复制代码
检测生日是否正确:
这里也是用正则匹配,匹配出年月日的。
  1. /**
  2. * 检测生日是否正确
  3. *
  4. * @param string $idCard
  5. * @return void
  6. */
  7. public function checkBirthday($idCard)
  8. {
  9.   $regx = '#^\d{6}(\d{4})(\d{2})(\d{2})\d{3}[0-9X]$#';
  10.   if (!preg_match($regx, $idCard, $matches)) {
  11.     return false;
  12.   }
  13.   array_shift($matches);
  14.   list($year, $month, $day) = $matches;
  15.   return checkdate($month, $day, $year);
  16. }
复制代码
校验码比对:
话说, 15位 转 18位 的都完全不消思量这个方法了。
  1. /**
  2. * 校验码比对
  3. *
  4. * @param string $idCard
  5. * @return void
  6. */
  7. public function checkCode($idCard)
  8. {
  9.   $idCardBase = substr($idCard, 0, 17);
  10.   $code = $this->genCode($idCardBase);
  11.   return $idCard == ($idCardBase . $code);
  12. }
复制代码
完备代码
传送门:IDCardFilter
末了
这个功能最多算是新颖吧,毕竟之前没有打仗过。很开心代码片断里又增加了新的成员。
以上所述是小编给各人先容的PHP校验15位和18位身份证号的类封装,希望对各人有所帮助,如果各人有任何疑问请给我留言,小编会及时复兴各人的。在此也非常感谢各人对草根技能分享网站的支持!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作