|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace Jxlwqq\IdValidator; |
| 4 | + |
| 5 | +/** |
| 6 | + * Trait Generator |
| 7 | + */ |
| 8 | +trait Generator |
| 9 | +{ |
| 10 | + /** |
| 11 | + * 生成顺序码 |
| 12 | + * |
| 13 | + * @param int $sex 性别 |
| 14 | + * |
| 15 | + * @return int|string |
| 16 | + */ |
| 17 | + private function _generatorOrderCode($sex) |
| 18 | + { |
| 19 | + $orderCode = $this->_getStrPad($this->_getRandInt(999, 1), 3, '1'); |
| 20 | + if ($sex === 1) { |
| 21 | + $orderCode = $orderCode % 2 === 0 ? $orderCode - 1 : $orderCode; |
| 22 | + } |
| 23 | + if ($sex === 0) { |
| 24 | + $orderCode = $orderCode % 2 === 0 ? $orderCode : $orderCode - 1; |
| 25 | + } |
| 26 | + |
| 27 | + return $orderCode; |
| 28 | + } |
| 29 | + |
| 30 | + /** |
| 31 | + * 生成出生日期码 |
| 32 | + * |
| 33 | + * @param int|string $birthday 出生日期 |
| 34 | + * |
| 35 | + * @return string |
| 36 | + */ |
| 37 | + private function _generatorBirthdayCode($birthday) |
| 38 | + { |
| 39 | + if ($birthday && is_numeric($birthday)) { |
| 40 | + $year = $this->_getStrPad(substr($birthday, 0, 4), 4); |
| 41 | + $month = $this->_getStrPad(substr($birthday, 4, 2), 2); |
| 42 | + $day = $this->_getStrPad(substr($birthday, 6, 2), 2); |
| 43 | + } |
| 44 | + if (!isset($year) || empty($year) || $year < 1800 || $year > date('Y')) { |
| 45 | + $year = $this->_getStrPad($this->_getRandInt(99, 50), 2, '0'); |
| 46 | + $year = '19'.$year; |
| 47 | + } |
| 48 | + |
| 49 | + if (!isset($month) || empty($month) || $month < 1 || $month > 12) { |
| 50 | + $month = $this->_getStrPad($this->_getRandInt(12, 1), 2, '0'); |
| 51 | + } |
| 52 | + |
| 53 | + if (!isset($day) || empty($day) || $day < 1 || $day > 31) { |
| 54 | + $day = $this->_getStrPad($this->_getRandInt(28, 1), 2, '0'); |
| 55 | + } |
| 56 | + |
| 57 | + if (!checkdate($month, $day, $year)) { |
| 58 | + $year = $this->_getStrPad($this->_getRandInt(99, 50), 2, '0'); |
| 59 | + $month = $this->_getStrPad($this->_getRandInt(12, 1), 2, '0'); |
| 60 | + $day = $this->_getStrPad($this->_getRandInt(28, 1), 2, '0'); |
| 61 | + } |
| 62 | + $birthdayCode = $year.$month.$day; |
| 63 | + |
| 64 | + return $birthdayCode; |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * 生成地址码 |
| 69 | + * |
| 70 | + * @param string $address 地址(行政区全称) |
| 71 | + * @return false|int|string |
| 72 | + */ |
| 73 | + private function _generatorAddressCode($address) |
| 74 | + { |
| 75 | + $addressCode = ''; |
| 76 | + if ($address) { |
| 77 | + $addressCode = array_search($address, $this->_addressCodeList); |
| 78 | + } |
| 79 | + if ($addressCode && substr($addressCode, 0, 1) != 8) { |
| 80 | + // 台湾省、香港特别行政区和澳门特别行政区(8字开头)暂缺地市和区县信息 |
| 81 | + // 省级 |
| 82 | + if (substr($addressCode, 2, 4) == '0000') { |
| 83 | + $keys = array_keys($this->_addressCodeList); |
| 84 | + $provinceCode = substr($addressCode, 0, 2); |
| 85 | + $pattern = '/^'.$provinceCode.'\d{2}[^0]{2}$/'; |
| 86 | + $result = preg_grep($pattern, $keys); |
| 87 | + $addressCode = $result[array_rand($result)]; |
| 88 | + } |
| 89 | + // 市级 |
| 90 | + if (substr($addressCode, 4, 2) == '00') { |
| 91 | + $keys = array_keys($this->_addressCodeList); |
| 92 | + $cityCode = substr($addressCode, 0, 4); |
| 93 | + $pattern = '/^'.$cityCode.'[^0]{2}$/'; |
| 94 | + $result = preg_grep($pattern, $keys); |
| 95 | + $addressCode = $result[array_rand($result)]; |
| 96 | + } |
| 97 | + } else { |
| 98 | + $addressCode = '110100'; // Default value |
| 99 | + for ($i = 0; $i < 100; $i++) { |
| 100 | + $province = $this->_getStrPad($this->_getRandInt(66), 2, '0'); |
| 101 | + $city = $this->_getStrPad($this->_getRandInt(20), 2, '0'); |
| 102 | + $district = $this->_getStrPad($this->_getRandInt(20), 2, '0'); |
| 103 | + $fakeAddressCode = $province.$city.$district; |
| 104 | + if (isset($this->_addressCodeList[$fakeAddressCode])) { |
| 105 | + $addressCode = $fakeAddressCode; |
| 106 | + break; |
| 107 | + } |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + return $addressCode; |
| 112 | + } |
| 113 | + |
| 114 | + /** |
| 115 | + * 生成校验码 |
| 116 | + * 详细计算方法 @lint https://zh.wikipedia.org/wiki/中华人民共和国公民身份号码 |
| 117 | + * |
| 118 | + * @param string $body 身份证号 body 部分 |
| 119 | + * |
| 120 | + * @return int|string |
| 121 | + */ |
| 122 | + private function _generatorCheckBit($body) |
| 123 | + { |
| 124 | + // 位置加权 |
| 125 | + $posWeight = []; |
| 126 | + for ($i = 18; $i > 1; $i--) { |
| 127 | + $weight = pow(2, $i - 1) % 11; |
| 128 | + $posWeight[$i] = $weight; |
| 129 | + }; |
| 130 | + |
| 131 | + // 累身份证号 body 部分与位置加权的积 |
| 132 | + $bodySum = 0; |
| 133 | + $bodyArray = str_split($body); |
| 134 | + $count = count($bodyArray); |
| 135 | + for ($j = 0; $j < $count; $j++) { |
| 136 | + $bodySum += (intval($bodyArray[$j], 10) * $posWeight[18 - $j]); |
| 137 | + } |
| 138 | + |
| 139 | + // 生成校验码 |
| 140 | + $checkBit = 12 - ($bodySum % 11); |
| 141 | + if ($checkBit == 10) { |
| 142 | + $checkBit = 'X'; |
| 143 | + } elseif ($checkBit > 10) { |
| 144 | + $checkBit = $checkBit % 11; |
| 145 | + } |
| 146 | + |
| 147 | + return $checkBit; |
| 148 | + } |
| 149 | +} |
0 commit comments