本文目录导读:

<?php
/**
* 中国大陆身份证号码信息提取类
* 支持18位和15位身份证号码
*/
class IdCardInfo {
// 身份证号码
private $idCard;
// 是否有效
private $isValid = false;
// 解析后的信息
private $info = [];
// 省市县代码对照表(简化版,实际开发中可扩展)
private $areaCode = [
'110000' => '北京市', '120000' => '天津市', '130000' => '河北省',
'140000' => '山西省', '150000' => '内蒙古自治区', '210000' => '辽宁省',
'220000' => '吉林省', '230000' => '黑龙江省', '310000' => '上海市',
'320000' => '江苏省', '330000' => '浙江省', '340000' => '安徽省',
'350000' => '福建省', '360000' => '江西省', '370000' => '山东省',
'410000' => '河南省', '420000' => '湖北省', '430000' => '湖南省',
'440000' => '广东省', '450000' => '广西壮族自治区', '460000' => '海南省',
'500000' => '重庆市', '510000' => '四川省', '520000' => '贵州省',
'530000' => '云南省', '540000' => '西藏自治区', '610000' => '陕西省',
'620000' => '甘肃省', '630000' => '青海省', '640000' => '宁夏回族自治区',
'650000' => '新疆维吾尔自治区', '710000' => '台湾省', '810000' => '香港特别行政区',
'820000' => '澳门特别行政区'
];
/**
* 构造函数
* @param string $idCard 身份证号码
*/
public function __construct($idCard) {
$this->idCard = trim($idCard);
$this->parse();
}
/**
* 解析身份证信息
*/
private function parse() {
// 去除空格并转大写
$this->idCard = strtoupper($this->idCard);
// 验证身份证格式
if (!$this->validateFormat()) {
$this->isValid = false;
$this->info = ['error' => '身份证号码格式不正确'];
return;
}
// 处理15位身份证(转换为18位分析)
$idCard = $this->idCard;
if (strlen($idCard) == 15) {
$idCard = $this->convert15To18($idCard);
if ($idCard === false) {
$this->isValid = false;
$this->info = ['error' => '身份证号码无效'];
return;
}
}
// 验证校验位
if (!$this->validateChecksum($idCard)) {
$this->isValid = false;
$this->info = ['error' => '身份证号码校验失败'];
return;
}
// 提取基本信息
$this->isValid = true;
$this->info = [
'id_card' => $idCard, // 18位身份证号
'original' => $this->idCard, // 原始输入
'area_code' => substr($idCard, 0, 6), // 地区代码
'birth_date' => $this->formatBirthDate(substr($idCard, 6, 8)), // 出生日期
'gender' => $this->getGender($idCard), // 性别
'age' => $this->calculateAge(substr($idCard, 6, 8)), // 年龄
'zodiac' => $this->getZodiac(substr($idCard, 6, 8)), // 属相
'constellation' => $this->getConstellation(substr($idCard, 6, 8)), // 星座
'region' => $this->getRegion(substr($idCard, 0, 6)), // 地区名称
'checksum' => substr($idCard, 17, 1), // 校验位
];
}
/**
* 验证身份证格式
* @return bool
*/
private function validateFormat() {
// 18位:6位地区 + 8位生日 + 3位顺序码 + 1位校验码
if (preg_match('/^\d{17}[\dX]$/', $this->idCard)) {
return $this->validateBirthDate(substr($this->idCard, 6, 8));
}
// 15位:6位地区 + 6位生日 + 3位顺序码
if (preg_match('/^\d{15}$/', $this->idCard)) {
return $this->validateBirthDate('19' . substr($this->idCard, 6, 6));
}
return false;
}
/**
* 验证出生日期
* @param string $date 日期字符串 YYYYMMDD
* @return bool
*/
private function validateBirthDate($date) {
if (strlen($date) != 8) return false;
$year = (int)substr($date, 0, 4);
$month = (int)substr($date, 4, 2);
$day = (int)substr($date, 6, 2);
if ($year < 1900 || $year > date('Y')) return false;
if ($month < 1 || $month > 12) return false;
if ($day < 1 || $day > 31) return false;
// 检查特定月份天数
$daysInMonth = [31, ($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0 ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
return $day <= $daysInMonth[$month - 1];
}
/**
* 将15位身份证转换为18位
* @param string $idCard15 15位身份证
* @return string|false
*/
private function convert15To18($idCard15) {
// 15位身份证出生日期加19前缀
$idCard17 = substr($idCard15, 0, 6) . '19' . substr($idCard15, 6);
// 计算校验码
$checksum = $this->calculateChecksum($idCard17);
if ($checksum === false) return false;
return $idCard17 . $checksum;
}
/**
* 计算校验码
* @param string $idCard17 前17位
* @return string|false
*/
private function calculateChecksum($idCard17) {
if (strlen($idCard17) != 17) return false;
// 加权因子
$factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
// 校验码对应值
$checksumMap = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
$sum = 0;
for ($i = 0; $i < 17; $i++) {
$sum += (int)$idCard17[$i] * $factors[$i];
}
return $checksumMap[$sum % 11];
}
/**
* 验证校验码
* @param string $idCard 18位身份证
* @return bool
*/
private function validateChecksum($idCard) {
if (strlen($idCard) != 18) return false;
$calculate = $this->calculateChecksum(substr($idCard, 0, 17));
return $calculate !== false && $calculate === $idCard[17];
}
/**
* 格式化出生日期
* @param string $date YYYYMMDD
* @return string
*/
private function formatBirthDate($date) {
return substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2);
}
/**
* 获取性别
* @param string $idCard 身份证号
* @return string
*/
private function getGender($idCard) {
// 第17位(倒数第二位)奇数为男,偶数为女
$genderDigit = (int)$idCard[16];
return ($genderDigit % 2 == 1) ? '男' : '女';
}
/**
* 计算年龄
* @param string $birthDate 出生日期 YYYYMMDD
* @return int
*/
private function calculateAge($birthDate) {
$birthYear = (int)substr($birthDate, 0, 4);
$birthMonth = (int)substr($birthDate, 4, 2);
$birthDay = (int)substr($birthDate, 6, 2);
$now = new DateTime();
$currentYear = (int)$now->format('Y');
$currentMonth = (int)$now->format('m');
$currentDay = (int)$now->format('d');
$age = $currentYear - $birthYear;
// 如果还没到生日,年龄减一
if ($currentMonth < $birthMonth || ($currentMonth == $birthMonth && $currentDay < $birthDay)) {
$age--;
}
return max($age, 0);
}
/**
* 获取属相
* @param string $birthDate 出生日期 YYYYMMDD
* @return string
*/
private function getZodiac($birthDate) {
$year = (int)substr($birthDate, 0, 4);
$zodiacs = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'];
return $zodiacs[($year - 4) % 12];
}
/**
* 获取星座
* @param string $birthDate 出生日期 YYYYMMDD
* @return string
*/
private function getConstellation($birthDate) {
$month = (int)substr($birthDate, 4, 2);
$day = (int)substr($birthDate, 6, 2);
$constellations = [
'摩羯座' => [1, 19], '水瓶座' => [2, 18], '双鱼座' => [3, 20],
'白羊座' => [4, 19], '金牛座' => [5, 20], '双子座' => [6, 21],
'巨蟹座' => [7, 22], '狮子座' => [8, 22], '处女座' => [9, 22],
'天秤座' => [10, 23], '天蝎座' => [11, 23], '射手座' => [12, 21],
'摩羯座' => [12, 22]
];
foreach ($constellations as $name => $date) {
if ($month == $date[0] && $day >= $date[1]) {
return $name;
}
}
// 处理特殊日期
if ($month == 1 && $day <= 19) return '摩羯座';
if ($month == 2 && $day <= 18) return '水瓶座';
if ($month == 3 && $day <= 20) return '双鱼座';
if ($month == 4 && $day <= 19) return '白羊座';
if ($month == 5 && $day <= 20) return '金牛座';
if ($month == 6 && $day <= 21) return '双子座';
if ($month == 7 && $day <= 22) return '巨蟹座';
if ($month == 8 && $day <= 22) return '狮子座';
if ($month == 9 && $day <= 22) return '处女座';
if ($month == 10 && $day <= 23) return '天秤座';
if ($month == 11 && $day <= 23) return '天蝎座';
if ($month == 12 && $day <= 21) return '射手座';
return '未知';
}
/**
* 获取地区名称
* @param string $areaCode 6位地区代码
* @return string
*/
private function getRegion($areaCode) {
// 省级代码(前2位 + 4个0)
$provinceCode = substr($areaCode, 0, 2) . '0000';
$province = isset($this->areaCode[$provinceCode]) ? $this->areaCode[$provinceCode] : '未知地区';
// 城市级(前4位 + 2个0)- 简化处理
$cityCode = substr($areaCode, 0, 4) . '00';
$city = isset($this->areaCode[$cityCode]) ? $this->areaCode[$cityCode] : '';
$cityAreaCodes = [
'1101' => '市辖区', '1102' => '县', '1201' => '市辖区', '1202' => '县',
'1301' => '石家庄市', '1302' => '唐山市', '1303' => '秦皇岛市',
'1304' => '邯郸市', '1305' => '邢台市', '1306' => '保定市',
'1307' => '张家口市', '1308' => '承德市', '1309' => '沧州市',
'1310' => '廊坊市', '1311' => '衡水市', '1401' => '太原市',
'2101' => '沈阳市', '2102' => '大连市', '2103' => '鞍山市',
'3101' => '市辖区', '3201' => '南京市', '3202' => '无锡市',
'3301' => '杭州市', '3302' => '宁波市', '3501' => '福州市',
'3502' => '厦门市', '3701' => '济南市', '3702' => '青岛市',
'4101' => '郑州市', '4201' => '武汉市', '4301' => '长沙市',
'4401' => '广州市', '4403' => '深圳市', '5101' => '成都市',
'6101' => '西安市', '6201' => '兰州市', '6501' => '乌鲁木齐市'
];
$cityKey = substr($areaCode, 0, 4);
if (isset($cityAreaCodes[$cityKey])) {
$city = $cityAreaCodes[$cityKey];
} elseif ($province != '未知地区') {
$city = '';
}
return $province . ($city ? ' ' . $city : '');
}
/**
* 获取解析结果
* @return array|false 成功返回信息数组,失败返回false
*/
public function getInfo() {
return $this->isValid ? $this->info : false;
}
/**
* 获取具体字段
* @param string $key 字段名
* @return mixed|null
*/
public function get($key) {
return $this->isValid && isset($this->info[$key]) ? $this->info[$key] : null;
}
/**
* 检查是否有效
* @return bool
*/
public function isValid() {
return $this->isValid;
}
}
/**
* 使用示例
*/
// 测试18位身份证
echo "=== 测试18位身份证 ===\n";
$idCard18 = new IdCardInfo('11010519491231002X');
if ($idCard18->isValid()) {
$info = $idCard18->getInfo();
echo "身份证号:{$info['id_card']}\n";
echo "出生日期:{$info['birth_date']}\n";
echo "性别:{$info['gender']}\n";
echo "年龄:{$info['age']}\n";
echo "属相:{$info['zodiac']}\n";
echo "星座:{$info['constellation']}\n";
echo "地区:{$info['region']}\n";
echo "校验位:{$info['checksum']}\n";
} else {
echo "无效的身份证号\n";
}
echo "\n=== 测试15位身份证 ===\n";
$idCard15 = new IdCardInfo('110105491231002');
if ($idCard15->isValid()) {
$info = $idCard15->getInfo();
echo "原始号码:{$info['original']}\n";
echo "转换后:{$info['id_card']}\n";
echo "出生日期:{$info['birth_date']}\n";
echo "性别:{$info['gender']}\n";
} else {
echo "无效的身份证号\n";
}
echo "\n=== 测试无效身份证 ===\n";
$invalidIdCard = new IdCardInfo('123456789012345678');
if (!$invalidIdCard->isValid()) {
echo "身份证号无效:" . $invalidIdCard->get('error') . "\n";
}
echo "\n=== 演示常用方法 ===\n";
$demo = new IdCardInfo('440305199003078819');
echo "性别:{$demo->get('gender')}\n";
echo "年龄:{$demo->get('age')}\n";
echo "出生日期:{$demo->get('birth_date')}\n";
echo "属相:{$demo->get('zodiac')}\n";
echo "星座:{$demo->get('constellation')}\n";
echo "地区:{$demo->get('region')}\n";
功能说明
该工具类可以从身份证号中提取以下信息:
- 基础信息:出生日期、性别、年龄
- 文化信息:属相(生肖)、星座
- 地理信息:省份、城市(简版地区对照表)
- 验证功能:自动验证格式、校验位
- 兼容性:支持18位和15位身份证号
主要方法
| 方法 | 说明 |
|---|---|
isValid() |
检查身份证是否有效 |
getInfo() |
获取完整信息数组 |
get($key) |
获取指定字段信息 |
注意事项
- 地区代码表为简化版,生产环境建议使用完整数据库
- 15位身份证会自动转换为18位进行分析
- 年龄基于当前日期实时计算
- 属相和星座计算基于公历生日
您可以直接运行此代码查看效果,也可以根据需求扩展地区数据库或添加其他功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播