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 相关文章推荐
模仿OSO的论坛(五)
Oct 09 PHP
PHP远程连接MYSQL数据库非常慢的解决方法
Jul 05 PHP
php下安装配置fckeditor编辑器的方法
Mar 02 PHP
PHP 伪静态技术原理以及突破原理实现介绍
Jul 12 PHP
如何使用PHP批量去除文件UTF8 BOM信息
Aug 05 PHP
php自动获取关键字的方法
Jan 06 PHP
PC端微信扫码支付成功之后自动跳转php版代码
Jul 07 PHP
在Yii2特定页面如何禁用调试工具栏Debug Toolbar详解
Aug 07 PHP
php 删除一维数组中某一个值元素的操作方法
Feb 01 PHP
PHP实现的一致性Hash算法详解【分布式算法】
Mar 31 PHP
php实现姓名根据首字母排序的类与方法(实例代码)
May 16 PHP
对laravel的csrf 防御机制详解,及form中csrf_token()的存在介绍
Oct 24 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
非常好用的两个PHP函数 serialize()和unserialize()
2012/02/04 PHP
php session_start()出错原因分析及解决方法
2013/10/28 PHP
php导出生成word的方法
2015/12/25 PHP
javascript:history.go()和History.back()的区别及应用
2012/11/25 Javascript
js操作CheckBoxList实现全选/反选(在客服端完成)
2013/02/02 Javascript
分享一则JavaScript滚动条插件源码
2015/03/03 Javascript
Angularjs制作简单的路由功能demo
2015/04/14 Javascript
jQuery与getJson结合的用法实例
2015/08/07 Javascript
JS判断当前页面是否在微信浏览器打开的方法
2015/12/08 Javascript
Jquery使用小技巧汇总
2015/12/29 Javascript
JS采用绝对定位实现回到顶部效果完整实例
2016/06/20 Javascript
对javascript继承的理解
2016/10/11 Javascript
js实现随机抽选效果、随机抽选红色球效果
2017/01/13 Javascript
NodeJS基础API搭建服务器详细过程记录
2017/04/01 NodeJs
利用nginx + node在阿里云部署https的步骤详解
2017/12/19 Javascript
Vue Extends 扩展选项用法完整实例
2019/09/17 Javascript
vue轮播组件实现$children和$parent 附带好用的gif录制工具
2019/09/26 Javascript
JQuery事件冒泡和默认行为代码实例
2020/05/13 jQuery
基于Vue中的父子传值问题解决
2020/07/27 Javascript
实例讲解Python中函数的调用与定义
2016/03/14 Python
python爬虫之线程池和进程池功能与用法详解
2018/08/02 Python
python 使用值来排序一个字典的方法
2018/11/16 Python
python找出因数与质因数的方法
2019/07/25 Python
Python实现在Windows平台修改文件属性
2020/03/05 Python
Matplotlib中rcParams使用方法
2021/01/05 Python
css3绘制百度的小度熊
2018/10/29 HTML / CSS
微信html5页面调用第三方位置导航的示例
2018/03/14 HTML / CSS
美国社交购物市场:MassGenie
2019/02/18 全球购物
iKRIX意大利网上商店:男女豪华服装和配件
2019/10/09 全球购物
继承权公证书
2014/04/09 职场文书
班主任工作经验交流材料
2014/05/13 职场文书
党支部综合考察材料
2014/05/19 职场文书
趣味运动会广播稿
2014/09/13 职场文书
六年级学生评语大全
2014/12/26 职场文书
党员个人总结范文
2015/02/14 职场文书
2016优秀班主任个人先进事迹材料
2016/02/26 职场文书