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位身份证号的类封装,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!