├── .gitignore
├── tests
├── TestCase.php
├── IdentityTest.php
└── Region
│ └── RegionTest.php
├── .travis.yml
├── phpunit.xml
├── src
├── IdentityInterface.php
├── Region
│ ├── RegionInterface.php
│ └── Region.php
└── Identity.php
├── composer.json
├── LICENSE
├── scripts
└── id-card
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | composer.lock
3 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | ./tests
16 |
17 |
18 |
19 |
20 | ./src
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/IdentityInterface.php:
--------------------------------------------------------------------------------
1 |
14 | */
15 | public function legal(): bool;
16 |
17 | /**
18 | * Get Region of The ID Card People.
19 | */
20 | public function region(): RegionInterface;
21 |
22 | /**
23 | * Get The ID Card People Birthday.
24 | *
25 | * @return string
26 | * @author Seven Du
27 | */
28 | public function birthday(): string;
29 |
30 | /**
31 | * Get the ID Card People Gender.
32 | *
33 | * @return string
34 | * @author Seven Du
35 | */
36 | public function gender(): string;
37 | }
38 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phalapi/id-card-of-china",
3 | "keywords": ["id", "card", "identity", "china"],
4 | "description": "中华人民共和国身份证(The identity card of the people's Republic of China). Fork From medz/id-card-of-china",
5 | "type": "library",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Seven Du",
10 | "email": "shiweidu@outlook.com"
11 | }
12 | ],
13 | "require": {
14 | "php": ">=7.0",
15 | "medz/gb-t-2260": "^1.0"
16 | },
17 | "require-dev": {
18 | "phpunit/phpunit": "^6.5"
19 | },
20 | "autoload": {
21 | "psr-4": {
22 | "PhalApi\\IdentityCard\\China\\": "src/"
23 | }
24 | },
25 | "autoload-dev": {
26 | "psr-4": {
27 | "PhalApi\\IdentityCard\\China\\Tests\\": "tests/"
28 | }
29 | },
30 | "config": {
31 | "platform": {
32 | "php": "7.0"
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Seven Du
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Region/RegionInterface.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | public function code();
14 |
15 | /**
16 | * Get Province Of The Region.
17 | *
18 | * @return string
19 | * @author Seven Du
20 | */
21 | public function province();
22 |
23 | /**
24 | * Get City Of The Region.
25 | *
26 | * @return string
27 | * @author Seven Du
28 | */
29 | public function city();
30 |
31 | /**
32 | * Get County Of The Region.
33 | *
34 | * @return string
35 | * @author Seven Du
36 | */
37 | public function county();
38 |
39 | /**
40 | * Get The Region Tree.
41 | *
42 | * @return array
43 | * @author Seven Du
44 | */
45 | public function tree();
46 |
47 | /**
48 | * Get The Region Tree String.
49 | *
50 | * @param string $glue Join Array Elements With A Glue String
51 | * @return string
52 | * @author Seven Du
53 | */
54 | public function treeString(string $glue = '');
55 | }
56 |
--------------------------------------------------------------------------------
/scripts/id-card:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | ";
41 | }
42 |
43 | $handle = fopen('php://stdin', 'r');
44 | $identityCardNumber = trim(fgets($handle));
45 | fclose($handle);
46 |
47 | if (!$identityCardNumber) {
48 | echo "> ";
49 | return call_user_func(__FUNCTION__, false);
50 | }
51 |
52 | return $identityCardNumber;
53 | }
54 |
55 | $identityCardNumber = getIdentityCardNumberInStdin(true);
56 | }
57 |
58 | var_dump(class_exists('Identity'));
59 | exit;
60 |
61 | // $identity = new Identity((string) $identityCardNumber);
62 |
63 | var_dump($identity);
64 |
--------------------------------------------------------------------------------
/tests/IdentityTest.php:
--------------------------------------------------------------------------------
1 | createMock(Identity::class);
19 |
20 | $this->assertTrue($identityMock instanceof IdentityInterface);
21 | }
22 |
23 | /**
24 | * Test Identity legal method.
25 | */
26 | public function testLegal()
27 | {
28 | // Create the Mooc.
29 | $identityMock = $this->getMockBuilder(Identity::class)
30 | ->setConstructorArgs(['350301198906180060'])
31 | ->setMethods(['validateCheckCode'])
32 | ->getMock();
33 |
34 | // Set validateCheckCode method.
35 | $identityMock->expects($this->exactly(2))
36 | ->method('validateCheckCode')
37 | ->will($this->onConsecutiveCalls(true, false));
38 |
39 | $this->assertTrue($identityMock->legal());
40 | $this->assertFalse($identityMock->legal());
41 | }
42 |
43 | /**
44 | * Test Identity birthday method.
45 | */
46 | public function testBirthday()
47 | {
48 | $identityMock = $this->getMockBuilder(Identity::class)
49 | ->setConstructorArgs(['51100019921108'])
50 | ->setMethods(null)
51 | ->getMock();
52 | $this->assertEquals('1992-11-08', $identityMock->birthday());
53 | }
54 |
55 | /**
56 | * Test gender method.
57 | */
58 | public function testGender()
59 | {
60 | $identityMock = $this->getMockBuilder(Identity::class)
61 | ->setConstructorArgs(['0000000000000000100'])
62 | ->setMethods(null)
63 | ->getMock();
64 | $this->assertEquals('男', $identityMock->gender());
65 |
66 | $identityMock = $this->getMockBuilder(Identity::class)
67 | ->setConstructorArgs(['0000000000000000200'])
68 | ->setMethods(null)
69 | ->getMock();
70 | $this->assertEquals('女', $identityMock->gender());
71 | }
72 |
73 | /**
74 | * Test region method.
75 | */
76 | public function testRegion()
77 | {
78 | $identityMock = $this->getMockBuilder(Identity::class)
79 | ->setConstructorArgs(['1100000000000000200'])
80 | ->setMethods(null)
81 | ->getMock();
82 | $this->assertTrue($identityMock->region() instanceof RegionInterface);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Identity Card Of China (PHP)
2 |
3 | 中华人民共和国身份证(The identity card of the people's Republic of China)
4 |
5 | [](https://travis-ci.com/medz/id-card-of-china)
6 |
7 | > JavaScript 版本:https://github.com/medz/id-card-of-china-js
8 |
9 | `id-card-of-china` 是一个基于「公民身份号码」规则获取公民身份号码中包含的基础信息组件。
10 |
11 | ## 更新说明
12 | 去除PHP严格模式,以免报错。
13 |
14 | ## 安装
15 |
16 | - 你的 PHP 版本应该 `>= 7.0`
17 |
18 | 我们使用 Composer 安装:
19 |
20 | ```bash
21 | composer require phalapi/id-card-of-china
22 | ```
23 |
24 | ## 使用
25 |
26 | 遵循 PHP-MD 原则,这个工具不提供静态调用,所以使用需要进行对象实例化:
27 |
28 | ```php
29 | use PhalApi\IdentityCard\China\Identity;
30 |
31 | $peopleIDNumber = '350301198906180060';
32 | $peopleIdentity = new Identity($peopleIDNumber);
33 | ```
34 |
35 | ## APIs
36 |
37 | > 基于 `PhalApi\IdentityCard\China\IdentityInterface` 实例
38 |
39 | - `legal`:检查公民身份号码是否合法
40 | - `birthday`:获取公民身份号码中包含的生日信息
41 | - `gender`:获取身份证包含的性别信息
42 | - `region`: 获取身份证包含的地区信息,返回 `PhalApi\IdentityCard\China\Region\RegionInterface` 实例
43 |
44 | ### `region` 对象 APIs
45 |
46 | - `code`: 获取 GB/T 2260 的地区行政代码
47 | - `province`:获取省份名称或者直辖市名称
48 | - `city`:获取城市名称,如果是直辖市则返回 `''`
49 | - `county`:获取区县名称
50 | - `tree`:获取地区层级数组
51 | - `treeString`:获取地区完整字符串,支持传递一个参数作为省市区的分隔符
52 |
53 | ### 演示
54 |
55 | ```php
56 | use PhalApi\IdentityCard\China\Identity;
57 |
58 | $peopleIDNumber = '350302198906180060';
59 | $peopleIdentity = new Identity($peopleIDNumber);
60 | $peopleRegion = $peopleIdentity->region();
61 |
62 | var_dump(
63 | $peopleIdentity->legal(), // true | false
64 | $peopleIdentity->birthday(), // 1989-06-18
65 | $peopleIdentity->gender(), // 女 | 男
66 | $peopleRegion->code(), // 350302
67 | $peopleRegion->province(), // 福建省
68 | $peopleRegion->city(), // 莆田市
69 | $peopleRegion->county(), // 城厢区
70 | $peopleRegion->tree(), // ["福建省", "莆田市", "城厢区"]
71 | $peopleRegion->treeString(' ') // 福建省 莆田市 城厢区
72 | );
73 | ```
74 |
75 | ## 疑问解答
76 |
77 | 1. 问:为什么不添加年龄、星座还有属相等信息?
78 |
79 | 答:因为年龄需要专门的时间组件去计算,星座如果是「粗略」计算可以获得,但是没有意义,属相更加复杂,负责任的转换这些属性都比简单转换复杂,简单转换出来的不够准确。同样也失去了包本身该有的功能,例如年龄可以交给「时间组件」等。
80 |
81 | 2. 问:这个包到底干啥的?
82 |
83 | 答:这个包就是提取公民身份号码所包含的基础信息
84 |
85 | 3. 问:可以用来验证人或者其他的吗?
86 |
87 | 答:不基于公安部的 API 验证的身份证组件都不能叫验证组件,现在所有的 ID Card 组件都只能提取公民身份号码所包含的信息,如果说验证,那唯一能验证的就是公民身份号码是否是一个合法的公民身份号码。
88 |
89 | 4. 问:如何获取年龄?
90 | 答:例如在 PHP 中,获取年龄是一个很简单的时区,我用最快的例子,你依赖 `nesbot/carbon` 这个「时间工具」包,依赖代码:
91 | ```bash
92 | composer require nesbot/carbon
93 | ```
94 | 然后看我下面的 PHP 代码:
95 | ```php
96 | use Carbon\Carbon;
97 | $birthday = new Carbon($identity->birthday());
98 | $age = $birthday->diffInYears();
99 | ```
100 | 好了,你打印下 `$age` 试试看!
101 |
102 | ## LICENSE
103 |
104 | This component follows the MIT open source agreement.
105 |
--------------------------------------------------------------------------------
/src/Identity.php:
--------------------------------------------------------------------------------
1 | identityCardNumber = strtoupper($identityCardNumber);
18 | }
19 |
20 | /**
21 | * Check The ID Card is legal.
22 | *
23 | * @return bool
24 | * @author Seven Du
25 | */
26 | public function legal(): bool
27 | {
28 | $regionCode = (int) substr($this->identityCardNumber, 0, 6);
29 |
30 | return ($regionCode >= 110000
31 | && $regionCode <= 820000
32 | && checkdate(
33 | intval(substr($this->identityCardNumber, 10, 2)),
34 | intval(substr($this->identityCardNumber, 12, 2)),
35 | intval(substr($this->identityCardNumber, 6, 4))
36 | )
37 | && $this->validateCheckCode()
38 | );
39 | }
40 |
41 | /**
42 | * Get The ID Card People Birthday.
43 | *
44 | * @return string
45 | * @author Seven Du
46 | */
47 | public function birthday(): string
48 | {
49 | $year = substr($this->identityCardNumber, 6, 4);
50 | $month = substr($this->identityCardNumber, 10, 2);
51 | $day = substr($this->identityCardNumber, 12, 2);
52 |
53 | return sprintf('%s-%s-%s', $year, $month, $day);
54 | }
55 |
56 | /**
57 | * Get the ID Card People Gender.
58 | *
59 | * @return string
60 | * @author Seven Du
61 | */
62 | public function gender(): string
63 | {
64 | return ((intval(substr($this->identityCardNumber, 16, 1)) % 2) === 0) ? '女' : '男';
65 | }
66 |
67 | /**
68 | * Get Region of The ID Card People.
69 | */
70 | public function region(): RegionInterface
71 | {
72 | $regionCode = (int) substr($this->identityCardNumber, 0, 6);
73 |
74 | return new Region($regionCode);
75 | }
76 |
77 | public function validateCheckCode(): bool
78 | {
79 | // Init
80 | $identityCardNumber = $this->identityCardNumber;
81 | $index = $sum = 0;
82 |
83 | // Calculation $sum
84 | for ($index; $index < 17; $index++) {
85 | $sum += ((1 << (17 - $index)) % 11) * intval(substr($identityCardNumber, $index, 1));
86 | }
87 |
88 | // Calculation $quotiety
89 | $quotiety = (12 - ($sum % 11)) % 11;
90 |
91 | if ($quotiety < 10) {
92 | return intval(substr($identityCardNumber, 17, 1)) === $quotiety;
93 | }
94 |
95 | return $quotiety === 10;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/Region/Region.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | public function __construct(int $regionCode)
28 | {
29 | if (empty(static::$regions)) {
30 | // Seting regions to [static::$regions],
31 | // Using `json_decode` function decode json RAW string.
32 | static::$regions = json_decode(
33 | // Using `file_get_contents` function read
34 | // `medz/gb-t-2600` package data provided.
35 | file_get_contents(MEDZ_GBT2260_RAW_PATH), true
36 | );
37 | }
38 |
39 | // Setting init region code.
40 | $this->code = (string) $regionCode;
41 | }
42 |
43 | /**
44 | * Get the Region Code.
45 | *
46 | * @return int
47 | * @author Seven Du
48 | */
49 | public function code()
50 | {
51 | return (int) $this->code;
52 | }
53 |
54 | /**
55 | * Get Province Of The Region.
56 | *
57 | * @return string
58 | * @author Seven Du
59 | */
60 | public function province()
61 | {
62 | $provinceCode = substr($this->code, 0, 2).'0000';
63 |
64 | if(isset(static::$regions[$provinceCode])){
65 | return static::$regions[$provinceCode];
66 | }
67 | return '';
68 |
69 | }
70 |
71 | /**
72 | * Get City Of The Region.
73 | *
74 | * @return string
75 | * @author Seven Du
76 | */
77 | public function city()
78 | {
79 | // Get city code of the region.
80 | $cityCode = substr($this->code, 0, 4).'00';
81 |
82 | if (isset(static::$regions[$cityCode])) {
83 | return static::$regions[$cityCode];
84 | }
85 |
86 | return '';
87 | }
88 |
89 | /**
90 | * Get County Of The Region.
91 | *
92 | * @return string
93 | * @author Seven Du
94 | */
95 | public function county()
96 | {
97 | if(isset(static::$regions[$this->code])){
98 | return static::$regions[$this->code];
99 | }
100 | return '';
101 | }
102 |
103 | /**
104 | * Get The Region Tree.
105 | *
106 | * @return array
107 | * @author Seven Du
108 | */
109 | public function tree()
110 | {
111 | return array_values(array_filter([
112 | $this->province(),
113 | $this->city(),
114 | $this->county(),
115 | ]));
116 | }
117 |
118 | /**
119 | * Get The Region Tree String.
120 | *
121 | * @param string $glue Join Array Elements With A Glue String
122 | * @return string
123 | * @author Seven Du
124 | */
125 | public function treeString(string $glue = '')
126 | {
127 | return implode($glue, $this->tree());
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/tests/Region/RegionTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(Region::class)
19 | ->disableOriginalConstructor()
20 | // ->setMethods(['setCode'])
21 | ->getMock();
22 |
23 | $this->assertTrue($regionMock instanceof RegionInterface);
24 | }
25 |
26 | /**
27 | * Test __constrcut method.
28 | */
29 | public function testConstructor()
30 | {
31 | $regionMock = new class (110000) extends Region {
32 | public function getConstructorSetCode() {
33 | return $this->code;
34 | }
35 | };
36 |
37 | $this->assertEquals('110000', $regionMock->getConstructorSetCode());
38 | }
39 |
40 | /**
41 | * Test code method.
42 | */
43 | public function testCode()
44 | {
45 | $regionMock = $this->getMockBuilder(Region::class)
46 | ->setConstructorArgs(['110000'])
47 | ->setMethods(null)
48 | ->getMock();
49 | $this->assertEquals(110000, $regionMock->code());
50 | }
51 |
52 | /**
53 | * Test province method
54 | */
55 | public function testProvince()
56 | {
57 | $regionMock = $this->getMockBuilder(Region::class)
58 | ->setConstructorArgs(['110105'])
59 | ->setMethods(null)
60 | ->getMock();
61 | $this->assertEquals('北京市', $regionMock->province());
62 | }
63 |
64 | /**
65 | * Test city method.
66 | */
67 | public function testCity()
68 | {
69 | $regionMock = $this->getMockBuilder(Region::class)
70 | ->setConstructorArgs(['511304'])
71 | ->setMethods(null)
72 | ->getMock();
73 | $this->assertEquals('南充市', $regionMock->city());
74 |
75 | $regionMock = $this->getMockBuilder(Region::class)
76 | ->setConstructorArgs(['110105'])
77 | ->setMethods(null)
78 | ->getMock();
79 | $this->assertEmpty($regionMock->city());
80 | }
81 |
82 | /**
83 | * Test county method.
84 | */
85 | public function testCounty()
86 | {
87 | $regionMock = $this->getMockBuilder(Region::class)
88 | ->setConstructorArgs(['510116'])
89 | ->setMethods(null)
90 | ->getMock();
91 | $this->assertEquals('双流区', $regionMock->county());
92 | }
93 |
94 | /**
95 | * Test tree method.
96 | */
97 | public function testTree()
98 | {
99 | $regionMock = $this->getMockBuilder(Region::class)
100 | ->setConstructorArgs([510116])
101 | ->setMethods(null)
102 | ->getMock();
103 | $this->assertEquals(['四川省', '成都市', '双流区'], $regionMock->tree());
104 |
105 | $regionMock = $this->getMockBuilder(Region::class)
106 | ->setConstructorArgs([110105])
107 | ->setMethods(null)
108 | ->getMock();
109 | $this->assertEquals(['北京市', '朝阳区'], $regionMock->tree());
110 | }
111 |
112 | public function testTreeString()
113 | {
114 | $regionMock = $this->getMockBuilder(Region::class)
115 | ->setConstructorArgs([510116])
116 | ->setMethods(null)
117 | ->getMock();
118 | $this->assertEquals('四川省成都市双流区', $regionMock->treeString());
119 |
120 | $regionMock = $this->getMockBuilder(Region::class)
121 | ->setConstructorArgs([110105])
122 | ->setMethods(null)
123 | ->getMock();
124 | $this->assertEquals('北京市#朝阳区', $regionMock->treeString('#'));
125 | }
126 | }
127 |
--------------------------------------------------------------------------------