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位的身份证号。
下面开始实现:
初始化:
classIDCardFilter
{
/**
*身份证号码校验
*
*@paramstring$idCard
*@returnbool
*/
publicfunctionvaild($idCard)
{
//基础的校验,校验身份证格式是否正确
if(!$this->isCardNumber($idCard)){
returnfalse;
}
//将15位转换成18位
$idCard=$this->fifteen2Eighteen($idCard);
//检查省是否存在
if(!$this->checkProvince($idCard)){
returnfalse;
}
//检查生日是否正确
if(!$this->checkBirthday($idCard)){
returnfalse;
}
//检查校验码
return$this->checkCode($idCard);
}
}
上面已经实现了一个校验的方法,里面调用了类里的很多方法,下面一一实现。
检测是否是身份证号码:
这一块的处理比较简单,一个正则表达式搞定了。
其中,(^\d{15}$)用于匹配15位身份证号的情况;(^\d{17}(\d|X)$)用于匹配18位身份证号的情况。
constREGX='#(^\d{15}$)|(^\d{17}(\d|X)$)#';
/**
*检测是否是身份证号码
*
*@paramstring$idCard
*@returnboolean
*/
publicfunctionisCardNumber($idCard)
{
returnpreg_match(self::REGX,$idCard);
}
15位转18位:
逻辑不复杂,先判断是否是15位,然后判断需要添加的年份,最终生成校验码拼接返回就OK了。
/**
*15位转18位
*
*@paramstring$idCard
*@returnvoid
*/
publicfunctionfifteen2Eighteen($idCard)
{
if(strlen($idCard)!=15){
return$idCard;
}
//如果身份证顺序码是996997998999,这些是为百岁以上老人的特殊编码
//$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);
}
校验码的生成:
详细计算规则见上面,这里就不做重复的阐述了。
/**
*生成校验码
*
*@paramstring$idCardBase
*@returnvoid
*/
finalprotectedfunctiongenCode($idCardBase)
{
$idCardLength=strlen($idCardBase);
if($idCardLength!=17){
returnfalse;
}
$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=>"国外"
];
/**
*检查省份是否正确
*
*@paramstring$idCard
*@returnvoid
*/
publicfunctioncheckProvince($idCard)
{
$provinceNumber=substr($idCard,0,2);
returnisset($this->provinces[$provinceNumber]);
}
检测生日是否正确:
这里也是用正则匹配,匹配出年月日的。
/**
*检测生日是否正确
*
*@paramstring$idCard
*@returnvoid
*/
publicfunctioncheckBirthday($idCard)
{
$regx='#^\d{6}(\d{4})(\d{2})(\d{2})\d{3}[0-9X]$#';
if(!preg_match($regx,$idCard,$matches)){
returnfalse;
}
array_shift($matches);
list($year,$month,$day)=$matches;
returncheckdate($month,$day,$year);
}
校验码比对:
话说,15位转18位的都完全不用考虑这个方法了。
/**
*校验码比对
*
*@paramstring$idCard
*@returnvoid
*/
publicfunctioncheckCode($idCard)
{
$idCardBase=substr($idCard,0,17);
$code=$this->genCode($idCardBase);
return$idCard==($idCardBase.$code);
}
完整代码
传送门:IDCardFilter
最后
这个功能最多算是新颖吧,毕竟之前没有接触过。很开心代码片段里又增加了新的成员。
以上所述是小编给大家介绍的PHP校验15位和18位身份证号的类封装,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!