1
|
|
|
<?php |
2
|
|
|
|
|
|
|
|
3
|
|
|
namespace Jxlwqq\IdValidator; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Trait Helper. |
7
|
|
|
*/ |
|
|
|
|
8
|
|
|
trait Helper |
9
|
|
|
{ |
10
|
|
|
/** |
11
|
|
|
* 获取地址码信息. |
12
|
|
|
* |
13
|
|
|
* @param string $addressCode 地址码 |
14
|
|
|
* @param string $birthdayCode 出生日期码 |
15
|
|
|
* @param bool $strictMode 是否启动严格模式检查 |
16
|
|
|
* |
17
|
|
|
* @return bool|mixed|string |
18
|
|
|
*/ |
19
|
|
|
private function _getAddressInfo($addressCode, $birthdayCode, $strictMode = false) |
20
|
|
|
{ |
21
|
|
|
$addressInfo = [ |
22
|
|
|
'province' => '', |
23
|
|
|
'city' => '', |
24
|
|
|
'district' => '', |
25
|
|
|
]; |
26
|
|
|
|
27
|
|
|
// 省级信息 |
28
|
|
|
$provinceAddressCode = substr($addressCode, 0, 2).'0000'; |
29
|
|
|
$addressInfo['province'] = $this->_getAddress($provinceAddressCode, $birthdayCode, $strictMode); |
30
|
|
|
|
31
|
|
|
$firstCharacter = $addressCode[0]; // 用于判断是否是港澳台居民居住证(8字开头) |
32
|
|
|
|
33
|
|
|
// 港澳台居民居住证无市级、县级信息 |
34
|
|
|
if ($firstCharacter == '8') { |
35
|
|
|
return $addressInfo; |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
// 市级信息 |
39
|
|
|
$cityAddressCode = substr($addressCode, 0, 4).'00'; |
40
|
|
|
$addressInfo['city'] = $this->_getAddress($cityAddressCode, $birthdayCode, $strictMode); |
41
|
|
|
|
42
|
|
|
// 县级信息 |
43
|
|
|
$addressInfo['district'] = $this->_getAddress($addressCode, $birthdayCode, $strictMode); |
44
|
|
|
|
45
|
|
|
// 这里不判断市级信息的原因: |
46
|
|
|
// 1)直辖市,无市级信息 |
47
|
|
|
// 2)省直辖县或县级市,无市级信息 |
48
|
|
|
return (empty($addressInfo['district']) or empty($addressInfo['province'])) ? false : $addressInfo; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* 获取省市区地址码. |
53
|
|
|
* |
54
|
|
|
* @param string $addressCode 地址码 |
55
|
|
|
* @param string $birthdayCode 出生日期码 |
56
|
|
|
* @param bool $strictMode 是否启动严格模式检查 |
57
|
|
|
* |
58
|
|
|
* @return string |
59
|
|
|
*/ |
60
|
|
|
private function _getAddress($addressCode, $birthdayCode, $strictMode = false) |
61
|
|
|
{ |
62
|
|
|
$address = ''; |
63
|
|
|
if (isset($this->_addressCodeTimeline[$addressCode])) { |
64
|
|
|
$timeline = $this->_addressCodeTimeline[$addressCode]; |
65
|
|
|
$year = substr($birthdayCode, 0, 4); |
66
|
|
|
// 严格模式下,会检查【地址码正式启用的年份】与【身份证上的出生年份】 |
67
|
|
|
foreach ($timeline as $val) { |
68
|
|
|
$start_year = $val['start_year'] != '' ? $val['start_year'] : '0001'; |
69
|
|
|
$end_year = $val['end_year'] != '' ? $val['end_year'] : '9999'; |
70
|
|
|
if ($year >= $start_year and $year <= $end_year) { |
71
|
|
|
$address = $val['address']; |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
// 非严格模式下,则不会检查【地址码正式启用的年份】与【身份证上的出生年份】的关系 |
76
|
|
|
if (empty($address) and !$strictMode) { |
77
|
|
|
// 由于较晚申请户口或身份证等原因,导致会出现地址码正式启用于2000年,但实际1999年出生的新生儿,由于晚了一年报户口,导致身份证上的出生年份早于地址码正式启用的年份 |
78
|
|
|
// 由于某些地区的地址码已经废弃,但是实际上在之后的几年依然在使用 |
79
|
|
|
// 这里就不做时间判断了 |
80
|
|
|
return array_pop($timeline)['address']; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
return $address; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
// 修复 \d\d\d\d01、\d\d\d\d02、\d\d\d\d11 和 \d\d\d\d20 的历史遗留问题 |
87
|
|
|
// 以上四种地址码,现实身份证真实存在,但民政部历年公布的官方地址码中可能没有查询到 |
88
|
|
|
// 如:440401 450111 等 |
89
|
|
|
// 所以这里需要特殊处理 |
90
|
|
|
// 1980年、1982年版本中,未有制定省辖市市辖区的代码,所有带县的省辖市给予“××××20”的“市区”代码。 |
91
|
|
|
// 1984年版本开始对地级市(前称省辖市)市辖区制定代码,其中“××××01”表示市辖区的汇总码,同时撤销“××××20”的“市区”代码(追溯至1983年)。 |
92
|
|
|
// 1984年版本的市辖区代码分为城区和郊区两类,城区由“××××02”开始排起,郊区由“××××11”开始排起,后来版本已不再采用此方式,已制定的代码继续沿用。 |
93
|
|
|
$suffixes = substr($addressCode, 4, 2); |
94
|
|
|
switch ($suffixes) { |
95
|
|
|
case '20': |
|
|
|
|
96
|
|
|
$address = '市区'; |
97
|
|
|
break; |
98
|
|
|
case '01': |
|
|
|
|
99
|
|
|
$address = '市辖区'; |
100
|
|
|
break; |
101
|
|
|
case '02': |
|
|
|
|
102
|
|
|
$address = '城区'; |
103
|
|
|
break; |
104
|
|
|
case '11': |
|
|
|
|
105
|
|
|
$address = '郊区'; |
106
|
|
|
break; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
return $address; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* 获取星座信息. |
114
|
|
|
* |
115
|
|
|
* @param string $birthdayCode 出生日期码 |
116
|
|
|
* |
117
|
|
|
* @return string |
118
|
|
|
*/ |
119
|
|
|
private function _getConstellation($birthdayCode) |
120
|
|
|
{ |
121
|
|
|
$constellationList = include __DIR__.'/../data/constellation.php'; |
122
|
|
|
$month = (int) substr($birthdayCode, 4, 2); |
123
|
|
|
$day = (int) substr($birthdayCode, 6, 2); |
124
|
|
|
|
125
|
|
|
$start_date = $constellationList[$month]['start_date']; |
126
|
|
|
$start_day = (int) explode('-', $start_date)[1]; |
127
|
|
|
|
128
|
|
|
if ($day < $start_day) { |
129
|
|
|
$tmp_month = $month == 1 ? 12 : $month - 1; |
130
|
|
|
|
131
|
|
|
return $constellationList[$tmp_month]['name']; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
return $constellationList[$month]['name']; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* 获取生肖信息. |
139
|
|
|
* |
140
|
|
|
* @param string $birthdayCode 出生日期码 |
141
|
|
|
* |
142
|
|
|
* @return mixed |
143
|
|
|
*/ |
144
|
|
|
private function _getChineseZodiac($birthdayCode) |
145
|
|
|
{ |
146
|
|
|
$chineseZodiacList = include __DIR__.'/../data/chineseZodiac.php'; |
147
|
|
|
$start = 1900; // 子鼠 |
148
|
|
|
$end = substr($birthdayCode, 0, 4); |
149
|
|
|
$key = ($end - $start) % 12; |
150
|
|
|
|
151
|
|
|
return $chineseZodiacList[$key]; |
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
|