Completed
Push — master ( fa88f9...55da4e )
by Yang
06:29
created

IDCard::age()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6.0106

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 14
cts 15
cp 0.9333
rs 8.5125
c 0
b 0
f 0
cc 6
eloc 15
nc 5
nop 0
crap 6.0106
1
<?php
2
3
namespace Leonis\IDCard;
4
5
class IDCard
6
{
7
    /**
8
     * 身份证号.
9
     *
10
     * @var string
11
     */
12
    private $id;
13
14
    /**
15
     * 行政区划代码
16
     *
17
     * @var array
18
     */
19
    private $areaCodes;
20
21 16
    public function __construct(string $id)
22
    {
23 16
        $this->id = strtoupper($id);
24 16
        $this->areaCodes = (array) require __DIR__.'/../data/codes.php';
25 16
    }
26
27
    /**
28
     * 验证身份号.
29
     *
30
     * @return bool
31
     */
32 9
    public function check()
33
    {
34 9
        return ($this->checkAreaCode() && $this->checkBirthday() && $this->checkCode()) ? true : false;
35
    }
36
37
    /**
38
     * 验证行政区划代码
39
     *
40
     * @return bool
41
     */
42 10
    public function checkAreaCode()
43
    {
44 10
        $areaCode = substr($this->id, 0, 6);
45
46 10
        return array_key_exists($areaCode, $this->areaCodes);
47
    }
48
49
    /**
50
     * 验证生日.
51
     *
52
     * @return bool
53
     */
54 10
    public function checkBirthday()
55
    {
56 10
        $year = substr($this->id, 6, 4);
57 10
        $month = substr($this->id, 10, 2);
58 10
        $day = substr($this->id, 12, 2);
59
60 10
        return checkdate($month, $day, $year);
61
    }
62
63
    /**
64
     * 验证校验码
65
     *
66
     * @return bool
67
     */
68 10
    public function checkCode()
69
    {
70 10
        $weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
71 10
        $codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
72 10
        $code = substr($this->id, 17, 1);
73 10
        $sum = 0;
74 10
        for ($i = 0; $i < 17; $i++) {
75 10
            $sum += substr(substr($this->id, 0, 17), $i, 1) * $weight[$i];
76
        }
77
78 10
        return $code == $codes[$sum % 11];
79
    }
80
81
    /**
82
     * 获取地址
83
     *
84
     * @param string $separator
85
     *
86
     * @return bool|string
87
     */
88 1
    public function address(string $separator = '')
89
    {
90 1
        return $this->check() ? $this->province().$separator.$this->city().$separator.$this->zone() : false;
91
    }
92
93
    /**
94
     * 获取省
95
     *
96
     * @return bool|mixed
97
     */
98 2
    public function province()
99
    {
100 2
        $provinceCode = substr($this->id, 0, 2).'0000';
101
102 2
        return $this->check() ? $this->areaCodes[$provinceCode] : false;
103
    }
104
105
    /**
106
     * 获取市
107
     *
108
     * @return bool|mixed
109
     */
110 2
    public function city()
111
    {
112 2
        $cityCode = substr($this->id, 0, 4).'00';
113
114 2
        return $this->check() ? $this->areaCodes[$cityCode] : false;
115
    }
116
117
    /**
118
     * 获取区.
119
     *
120
     * @return bool|mixed
121
     */
122 2
    public function zone()
123
    {
124 2
        $areaCode = substr($this->id, 0, 6);
125
126 2
        return $this->check() ? $this->areaCodes[$areaCode] : false;
127
    }
128
129
    /**
130
     * 获取生日.
131
     *
132
     * @param string $format
133
     *
134
     * @return bool|string
135
     */
136 1
    public function birthday(string $format)
137
    {
138 1
        return date($format, strtotime($this->year().'-'.$this->month().'-'.$this->day()));
139
    }
140
141
    /**
142
     * 获取年.
143
     *
144
     * @return int
145
     */
146 4
    public function year()
147
    {
148 4
        return (int) substr($this->id, 6, 4);
149
    }
150
151
    /**
152
     * 获取月.
153
     *
154
     * @return int
155
     */
156 4
    public function month()
157
    {
158 4
        return (int) substr($this->id, 10, 2);
159
    }
160
161
    /**
162
     * 获取日.
163
     *
164
     * @return int
165
     */
166 4
    public function day()
167
    {
168 4
        return (int) substr($this->id, 12, 2);
169
    }
170
171
    /**
172
     * 获取年龄.
173
     *
174
     * @return false|int|string
175
     */
176 1
    public function age()
177
    {
178 1
        if (!$this->check()) {
179
            return false;
180
        }
181
182 1
        $year = $this->year();
183 1
        $month = $this->month();
184 1
        $day = $this->day();
185
186 1
        $nowYear = (int) date('Y');
187 1
        $nowMonth = (int) date('n');
188 1
        $nowDay = (int) date('j');
189
190 1
        $age = 0;
191 1
        if ($nowYear > $year) {
192 1
            $age = $nowYear - $year - 1;
193
        }
194 1
        if ($nowMonth > $month || ($nowMonth === $month && $nowDay >= $day)) {
195 1
            $age++;
196
        }
197
198 1
        return $age;
199
    }
200
201
    /**
202
     * 获取性别.
203
     *
204
     * @return bool|string 身份证号未通过验证返回 false
205
     */
206 1
    public function sex()
207
    {
208 1
        return $this->check() ? (substr($this->id, 16, 1) % 2 === 0 ? '女' : '男') : false;
209
    }
210
211
    /**
212
     * 获取星座.
213
     *
214
     * @return bool|mixed
215
     */
216 1
    public function constellation()
217
    {
218 1
        if (!$this->check()) {
219
            return false;
220
        }
221
222 1
        $constellation = ['水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座', '魔羯座'];
223 1
        $constellationDays = [21, 20, 21, 20, 21, 22, 23, 23, 23, 24, 22, 21];
224
225 1
        $month = $this->month() - 1;
226 1
        $day = $this->day();
227
228 1
        if ($day < $constellationDays[$month]) {
229 1
            $month--;
230
        }
231
232 1
        return $month >= 0 ? $constellation[$month] : $constellation[11];
233
    }
234
235
    /**
236
     * 获取属相.
237
     *
238
     * @return bool|string
239
     */
240 1
    public function zodiac()
241
    {
242 1
        if (!$this->check()) {
243
            return false;
244
        }
245
246 1
        $year = $this->year();
247 1
        $index = $year > 1901 ? ($year - 1901) % 12 : (1901 - $year) % 12;
248 1
        $zodiac = ['牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪', '鼠'];
249
250 1
        return $zodiac[$index];
251
    }
252
}
253