PHP实现中国公民身份证号码有效性验证示例代码


Posted in PHP onMay 03, 2017

本文将使用Java实现中国公民(15位或者18位)身份证号码的相关验证,功能如下:

  1. 身份证号有效性验证
  2. 分析详细身份证信息
  3. 生成一个虚拟的省份证号码。

身份证号码验证

1、号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

2、地址码(前六位数)

表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。

3、出生日期码(第七位至十四位)

表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。

4、顺序码(第十五位至十七位)

表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号, 顺序码的奇数分配给男性,偶数分配给女性。

5、校验码(第十八位数)

(1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, … , 16 ,先对前17位数字的权求和

Ai:表示第i位置上的身份证号码数字值

Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

(2)计算模 Y = mod(S, 11)

(3)通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2

IDValidator.php

<?php
namespace com\jdk5\blog\IDValidator;
 
class IDValidator {
 private static $GB2260;
 private static $instance;
 private static $cache = array();
 private static $util;
 function __construct() {
 if (!class_exists("com\jdk5\blog\IDValidator\GB2260")){
 include 'GB2260.php';
 }
 if (!class_exists("com\jdk5\blog\IDValidator\util")){
 include 'util.php';
 }
 self::$GB2260 = GB2260::getGB2260 ();
 self::$util = util::getInstance();
 }
 public static function getInstance() {
 if (is_null ( self::$instance )) {
 self::$instance = new IDValidator ();
 }
 return self::$instance;
 }
 function isValid($id) {
 $code = self::$util->checkArg ( $id );
 if ($code === false) {
 return false;
 }
 // 查询cache
 if (isset ( self::$cache [ $id ] ) && self::$cache [$id] ['valid'] !== false) {
 return self::$cache [$id] ['valid'];
 } else {
 if (! isset ( self::$cache [ $id ] )) {
 self::$cache [$id] = array ();
 }
 }
 
 $addr = substr ( $code ['body'], 0, 6 );
 $birth = $code ['type'] === 18 ? substr ( $code ['body'], 6, 8 ) :
 substr ( $code ['body'], 6, 6 );
 $order = substr ( $code ['body'], - 3 );
 
 if (! (self::$util->checkAddr ( $addr ) && self::$util->checkBirth ( $birth ) &&
 self::$util->checkOrder ( $order ))) {
 self::$cache [$id] ['valid'] = false;
 return false;
 }
 
 // 15位不含校验码,到此已结束
 if ($code ['type'] === 15) {
 self::$cache [$id] ['valid'] = true;
 return true;
 }
 
 /* 校验位部分 */
 
 // 位置加权
 $posWeight = array ();
 for($i = 18; $i > 1; $i --) {
 $wei = self::$util->weight ( $i );
 $posWeight [$i] = $wei;
 }
 
 // 累加body部分与位置加权的积
 $bodySum = 0;
 $bodyArr = str_split( $code ['body'] );
 for($j = 0; $j < count ( $bodyArr ); $j ++) {
 $bodySum += (intval ( $bodyArr [$j], 10 ) * $posWeight [18 - $j]);
 }
 
 // 得出校验码
 $checkBit = 12 - ($bodySum % 11);
 if ($checkBit == 10) {
 $checkBit = 'X';
 } else if ($checkBit > 10) {
 $checkBit = $checkBit % 11;
 }
 // 检查校验码
 if ($checkBit != $code ['checkBit']) {
 self::$cache [$id] ['valid'] = false;
 return false;
 } else {
 self::$cache [$id] ['valid'] = true;
 return true;
 }
 }
 // 分析详细信息
 function getInfo ($id) {
 // 号码必须有效
 if ($this->isValid($id) === false) {
 return false;
 }
 // TODO 复用此部分
 $code = self::$util->checkArg($id);
 
 // 查询cache
 // 到此时通过isValid已经有了cache记录
 if (isset(self::$cache[$id]) && isset(self::$cache[$id]['info'])) {
 return self::$cache[$id]['info'];
 }
 
 $addr = substr($code['body'], 0, 6);
 $birth = ($code['type'] === 18 ? substr($code['body'], 6, 8) :
 substr($code['body'], 6, 6));
 $order = substr($code['body'], -3);
 
 $info = array();
 $info['addrCode'] = $addr;
 if (self::$GB2260 !== null) {
 $info['addr'] = self::$util->getAddrInfo($addr);
 }
 $info ['birth'] = ($code ['type'] === 18 ? (substr ( $birth, 0, 4 ) . '-' . substr ( $birth, 4, 2 ) . '-' . substr ( $birth, - 2 )) : ('19' . substr ( $birth, 0, 2 ) . '-' . substr ( $birth, 2, 2 ) . '-' . substr ( $birth, - 2 )));
 $info['sex'] = ($order % 2 === 0 ? 0 : 1);
 $info['length'] = $code['type'];
 if ($code['type'] === 18) {
 $info['checkBit'] = $code['checkBit'];
 }
 
 // 记录cache
 self::$cache[$id]['info'] = $info;
 
 return $info;
 }
 
 // 仿造一个号
 function makeID ($isFifteen=false) {
 // 地址码
 $addr = null;
 if (self::$GB2260 !== null) {
 $loopCnt = 0;
 while ($addr === null) {
 // 防止死循环
 if ($loopCnt > 50) {
  $addr = 110101;
  break;
 }
 $prov = self::$util->str_pad(self::$util->rand(66), 2, '0');
 $city = self::$util->str_pad(self::$util->rand(20), 2, '0');
 $area = self::$util->str_pad(self::$util->rand(20), 2, '0');
 $addrTest = $prov . $city . $area;
 if (isset(self::$GB2260[$addrTest])) {
  $addr = $addrTest;
  break;
 }
 $loopCnt ++;
 }
 } else {
 $addr = 110101;
 }
 
 // 出生年
 $yr = self::$util->str_pad(self::$util->rand(99, 50), 2, '0');
 $mo = self::$util->str_pad(self::$util->rand(12, 1), 2, '0');
 $da = self::$util->str_pad(self::$util->rand(28, 1), 2, '0');
 if ($isFifteen) {
 return $addr . $yr . $mo . $da
 . self::$util->str_pad(self::$util->rand(999, 1), 3, '1');
 }
 
 $yr = '19' . $yr;
 $body = $addr . $yr . $mo . $da . self::$util->str_pad(self::$util->rand(999, 1), 3, '1');
 
 // 位置加权
 $posWeight = array();
 for ($i = 18; $i > 1; $i--) {
 $wei = self::$util->weight($i);
 $posWeight[$i] = $wei;
 }
 
 // 累加body部分与位置加权的积
 $bodySum = 0;
 $bodyArr = str_split($body);
 for ($j = 0; $j < count($bodyArr); $j++) {
 $bodySum += (intval($bodyArr[$j], 10) * $posWeight[18 - $j]);
 }
 
 // 得出校验码
 $checkBit = 12 - ($bodySum % 11);
 if ($checkBit == 10) {
 $checkBit = 'X';
 } else if ($checkBit > 10) {
 $checkBit = $checkBit % 11;
 }
 return ($body . $checkBit);
 }
}

调用

<?php
header("Content-type: text/html; charset=utf-8");

include 'IDValidator.php';
$v = com\jdk5\blog\IDValidator\IDValidator::getInstance();

//生成一个18位身份证号
$id = $v->makeID();
//获取身份证信息
$info = $v->getInfo($id);
var_dump($info);
//生成一个15位身份证号
$id = $v->makeID(true);
$info = $v->getInfo($id);
var_dump($info);

//验证身份证号是否正确
var_dump($v->isValid("123456789012345678"));

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php笔记之:php函数range() round()和list()的使用说明
Apr 26 PHP
hadoop常见错误以及处理方法详解
Jun 19 PHP
php初始化对象和析构函数的简单实例
Mar 11 PHP
PHP实现将视频转成MP4并获取视频预览图的方法
Mar 12 PHP
php中smarty变量修饰用法实例分析
Jun 11 PHP
PHP程序员不应该忽略的3点
Oct 09 PHP
利用PHPExcel实现Excel文件的写入和读取
Apr 26 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
Jul 21 PHP
PHP编程实现计算抽奖概率算法完整实例
Aug 09 PHP
PHP调用API接口实现天气查询功能的示例
Sep 21 PHP
PHP设计模式之装饰器模式实例详解
Feb 07 PHP
thinkphp5实现无限级分类
Feb 18 PHP
PHP基于Redis消息队列实现发布微博的方法
May 03 #PHP
Laravel5中Cookie的使用详解
May 03 #PHP
[原创]php实现数组按拼音顺序排序的方法
May 03 #PHP
PHP基于ICU扩展intl快速实现汉字转拼音及按拼音首字母分组排序的方法
May 03 #PHP
php中的异常和错误浅析
May 03 #PHP
利用php-cli和任务计划实现刷新token功能的方法
May 03 #PHP
利用php-cli和任务计划实现订单同步功能的方法
May 03 #PHP
You might like
咖啡与水的关系
2021/03/03 冲泡冲煮
5.PHP的其他功能
2006/10/09 PHP
php循环table实现一行两列显示的方法
2015/06/04 PHP
PHP实现广度优先搜索算法(BFS,Broad First Search)详解
2017/09/16 PHP
PHP设计模式之装饰器模式定义与用法详解
2018/04/02 PHP
laravel5.6中的外键约束示例
2019/10/23 PHP
关于document.cookie的使用javascript
2008/04/11 Javascript
用javascript做拖动布局的思路
2008/05/31 Javascript
jQuery中关于ScrollableGridPlugin.js(固定表头)插件的使用逐步解析
2014/07/17 Javascript
jQuery图片特效插件Revealing实现拉伸放大
2015/04/22 Javascript
使用jspdf生成pdf报表
2015/07/03 Javascript
JavaScript中对DOM节点的访问、创建、修改、删除
2015/11/16 Javascript
理解javascript中try...catch...finally
2015/12/25 Javascript
原生js的数组除重复简单实例
2016/05/24 Javascript
基于BootStrap环境写jQuery tabs插件
2016/07/12 Javascript
AngularJS基础 ng-switch 指令简单示例
2016/08/03 Javascript
基于slideout.js实现移动端侧边栏滑动特效
2016/11/28 Javascript
Angular 4.x+Ionic3踩坑之Ionic 3.x界面传值详解
2018/03/13 Javascript
jQuery实现基本动画效果的方法详解
2018/09/06 jQuery
浅析Proxy可以优化vue的数据监听机制问题及实现思路
2018/11/29 Javascript
微信小程序实现上传图片裁剪图片过程解析
2019/08/22 Javascript
浅谈layui 绑定form submit提交表单的注意事项
2019/10/25 Javascript
vue 实现单选框设置默认选中值
2019/11/07 Javascript
django-利用session机制实现唯一登录的例子
2020/03/16 Python
selenium学习教程之定位以及切换frame(iframe)
2021/01/04 Python
BRASTY捷克:购买香水、化妆品、手袋和手表
2017/07/12 全球购物
美国眼镜网:GlassesUSA
2017/09/07 全球购物
实习生个人找工作的自我评价
2013/10/30 职场文书
网页设计个人找工作求职信
2013/11/28 职场文书
党课知识竞赛主持词
2014/04/01 职场文书
青年志愿者活动总结
2014/04/26 职场文书
医学专业大学生职业生涯规划书
2014/10/25 职场文书
2015年全民国防教育日活动总结
2015/03/23 职场文书
2019通用版新员工入职培训方案!
2019/07/11 职场文书
Spring Boot 实现敏感词及特殊字符过滤处理
2021/06/29 Java/Android
MySql数据库触发器使用教程
2022/06/01 MySQL