数码控科技猎奇Iphone动漫星座游戏电竞lolcosplay王者荣耀攻略allcnewsBLOGNEWSBLOGASKBLOGBLOGZSK全部技术问答问答技术问答it问答代码软件新闻开发博客电脑/网络手机/数码笔记本电脑互联网操作系统软件硬件编程开发360产品资源分享电脑知识文档中心IT全部全部分类全部分类技术牛文全部分类教程最新网页制作cms教程平面设计媒体动画操作系统网站运营网络安全服务器教程数据库工具网络安全软件教学vbscript正则表达式javascript批处理更多»编程更新教程更新游戏更新allitnewsJava新闻网络医疗信息化安全创业站长电商科技访谈域名会议专栏创业动态融资创投创业学院 / 产品经理创业公司人物访谈营销开发数据库服务器系统虚拟化云计算嵌入式移动开发作业作业1常见软件all电脑网络手机数码生活游戏体育运动明星影音休闲爱好文化艺术社会民生教育科学医疗健康金融管理情感社交地区其他电脑互联网软件硬件编程开发360相关产品手机平板其他电子产品摄影器材360硬件通讯智能设备购物时尚生活常识美容塑身服装服饰出行旅游交通汽车购房置业家居装修美食烹饪单机电脑游戏网页游戏电视游戏桌游棋牌游戏手机游戏小游戏掌机游戏客户端游戏集体游戏其他游戏体育赛事篮球足球其他运动球类运动赛车健身运动运动用品影视娱乐人物音乐动漫摄影摄像收藏宠物幽默搞笑起名花鸟鱼虫茶艺彩票星座占卜书画美术舞蹈小说图书器乐声乐小品相声戏剧戏曲手工艺品历史话题时事政治就业职场军事国防节日风俗法律法规宗教礼仪礼节自然灾害360维权社会人物升学入学人文社科外语资格考试公务员留学出国家庭教育学习方法语文物理生物工程学农业数学化学健康知识心理健康孕育早教内科外科妇产科儿科皮肤科五官科男科整形中医药品传染科其他疾病医院两性肿瘤科创业投资企业管理财务税务银行股票金融理财基金债券保险贸易商务文书国民经济爱情婚姻家庭烦恼北京上海重庆天津黑龙江吉林辽宁河北内蒙古山西陕西宁夏甘肃青海新疆西藏四川贵州云南河南湖北湖南山东江苏浙江安徽江西福建广东广西海南香港澳门台湾海外地区

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

来源:脚本之家  责任编辑:小易  

新公司框架源码的时候,发现了这个功能,于是搜索一番并封装了一下身份证号校验的类。

目前大家的身份证号大多是 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位 的身份证号。

下面开始实现:

初始化:

class IDCardFilter
{
  /**
   * 身份证号码校验
   *
   * @param string $idCard
   * @return bool
   */
  public function vaild($idCard)
  {
    // 基础的校验,校验身份证格式是否正确
    if (!$this->isCardNumber($idCard)) {
      return false;
    }

    // 将 15 位转换成 18 位
    $idCard = $this->fifteen2Eighteen($idCard);

    // 检查省是否存在
    if (!$this->checkProvince($idCard)) {
      return false;
    }

    // 检查生日是否正确
    if (!$this->checkBirthday($idCard)) {
      return false;
    }

    // 检查校验码
    return $this->checkCode($idCard);
  }
}

上面已经实现了一个校验的方法,里面调用了类里的很多方法,下面一一实现。

检测是否是身份证号码:

这一块的处理比较简单,一个正则表达式搞定了。

其中, (^\d{15}$) 用于匹配 15位 身份证号的情况; (^\d{17}(\d|X)$) 用于匹配 18位 身份证号的情况。

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

/**
 * 检测是否是身份证号码
 *
 * @param string $idCard
 * @return boolean
 */
public function isCardNumber($idCard)
{
  return preg_match(self::REGX, $idCard);
}

15位转18位:

逻辑不复杂,先判断是否是15位,然后判断需要添加的年份,最终生成校验码拼接返回就OK了。

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

  // 如果身份证顺序码是996 997 998 999,这些是为百岁以上老人的特殊编码
  // $code = array_search(substr($idCard, 12, 3), [996, 997, 998, 999]) !== false ? '18' : '19';
  // 一般 19 就够了
  $code = '19';
  $idCardBase = substr($idCard, 0, 6) . $code . substr($idCard, 6, 9);
  return $idCardBase . $this->genCode($idCardBase);
}

校验码的生成:

详细计算规则见上面,这里就不做重复的阐述了。

/**
 * 生成校验码
 *
 * @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];
}

检查省份是否正确:

protected $provinces = [
  11 => "北京", 12 => "天津", 13 => "河北",  14 => "山西", 15 => "内蒙古",
  21 => "辽宁", 22 => "吉林", 23 => "黑龙江", 31 => "上海", 32 => "江苏",
  33 => "浙江", 34 => "安徽", 35 => "福建",  36 => "江西", 37 => "山东", 41 => "河南",
  42 => "湖北", 43 => "湖南", 44 => "广东",  45 => "广西", 46 => "海南", 50 => "重庆",
  51 => "四川", 52 => "贵州", 53 => "云南",  54 => "西藏", 61 => "陕西", 62 => "甘肃",
  63 => "青海", 64 => "宁夏", 65 => "新疆",  71 => "台湾", 81 => "香港", 82 => "澳门", 91 => "国外"
];

/**
 * 检查省份是否正确
 *
 * @param string $idCard
 * @return void
 */
public function checkProvince($idCard)
{
  $provinceNumber = substr($idCard, 0, 2);
  return isset($this->provinces[$provinceNumber]);
}

检测生日是否正确:

这里也是用正则匹配,匹配出年月日的。

/**
 * 检测生日是否正确
 *
 * @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);
}

校验码比对:

话说, 15位 转 18位 的都完全不用考虑这个方法了。

/**
 * 校验码比对
 *
 * @param string $idCard
 * @return void
 */
public function checkCode($idCard)
{
  $idCardBase = substr($idCard, 0, 17);
  $code = $this->genCode($idCardBase);
  return $idCard == ($idCardBase . $code);
}

完整代码

传送门:IDCardFilter

最后

这个功能最多算是新颖吧,毕竟之前没有接触过。很开心代码片段里又增加了新的成员。

以上所述是小编给大家介绍的PHP校验15位和18位身份证号的类封装,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

您可能感兴趣的文章:


  • 本文相关:
  • php实现中国公民身份证号码有效性验证示例代码
  • php正则判断是否为合法身份证号的方法
  • php验证身份证号码正确性的函数
  • 使用php从身份证号中获取一系列线索(星座、生肖、生日等)
  • php提取身份证号码中的生日日期以及验证是否为成年人的函数
  • php身份证号码检查类实例
  • php根据身份证号码计算年龄的实例代码
  • php用身份证号获取星座和生肖的方法
  • php 身份证号验证函数
  • 一个经典的php文件上传类分享
  • php中in_array的隐式转换的解决方法
  • 用php写的一个冒泡排序法的函数简单实例
  • 在laravel中使用datatables插件的方法
  • php ucwords() 函数将字符串中每个单词的首字符转换为大写(实现代
  • laravel5.4利用163邮箱发送邮件的步骤详解
  • php中将网页导出为word文档的代码
  • zf框架的session会话周期及次数限制使用示例
  • 基于php上传图片重命名的6种解决方法的详细介绍
  • php中的插件机制原理和实例
  • 免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved