IDValidator.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. namespace common\helpers\IDValidator;
  3. class IDValidator {
  4. private static $GB2260;
  5. private static $instance;
  6. private static $cache = array();
  7. private static $util;
  8. function __construct() {
  9. if (!class_exists("GB2260")){
  10. include_once 'GB2260.php';
  11. }
  12. if (!class_exists("util")){
  13. include_once 'util.php';
  14. }
  15. self::$GB2260 = GB2260::getGB2260();
  16. self::$util = util::getInstance();
  17. }
  18. public static function getInstance() {
  19. if (is_null ( self::$instance )) {
  20. self::$instance = new IDValidator ();
  21. }
  22. return self::$instance;
  23. }
  24. function isValid($id) {
  25. $code = self::$util->checkArg ( $id );
  26. if ($code === false) {
  27. return false;
  28. }
  29. // 查询cache
  30. if (isset ( self::$cache [ $id ] ) && self::$cache [$id] ['valid'] !== false) {
  31. return self::$cache [$id] ['valid'];
  32. } else {
  33. if (! isset ( self::$cache [ $id ] )) {
  34. self::$cache [$id] = array ();
  35. }
  36. }
  37. $addr = substr ( $code ['body'], 0, 6 );
  38. $birth = $code ['type'] === 18 ? substr ( $code ['body'], 6, 8 ) :
  39. substr ( $code ['body'], 6, 6 );
  40. $order = substr ( $code ['body'], - 3 );
  41. if (! (self::$util->checkAddr ( $addr ) && self::$util->checkBirth ( $birth ) &&
  42. self::$util->checkOrder ( $order ))) {
  43. self::$cache [$id] ['valid'] = false;
  44. return false;
  45. }
  46. // 15位不含校验码,到此已结束
  47. if ($code ['type'] === 15) {
  48. self::$cache [$id] ['valid'] = true;
  49. return true;
  50. }
  51. /* 校验位部分 */
  52. // 位置加权
  53. $posWeight = array ();
  54. for($i = 18; $i > 1; $i --) {
  55. $wei = self::$util->weight ( $i );
  56. $posWeight [$i] = $wei;
  57. }
  58. // 累加body部分与位置加权的积
  59. $bodySum = 0;
  60. $bodyArr = str_split( $code ['body'] );
  61. for($j = 0; $j < count ( $bodyArr ); $j ++) {
  62. $bodySum += (intval ( $bodyArr [$j], 10 ) * $posWeight [18 - $j]);
  63. }
  64. // 得出校验码
  65. $checkBit = 12 - ($bodySum % 11);
  66. if ($checkBit == 10) {
  67. $checkBit = 'X';
  68. } else if ($checkBit > 10) {
  69. $checkBit = $checkBit % 11;
  70. }
  71. // 检查校验码
  72. if ($checkBit != $code ['checkBit']) {
  73. self::$cache [$id] ['valid'] = false;
  74. return false;
  75. } else {
  76. self::$cache [$id] ['valid'] = true;
  77. return true;
  78. }
  79. }
  80. // 分析详细信息
  81. function getInfo ($id) {
  82. // 号码必须有效
  83. if ($this->isValid($id) === false) {
  84. return false;
  85. }
  86. // TODO 复用此部分
  87. $code = self::$util->checkArg($id);
  88. // 查询cache
  89. // 到此时通过isValid已经有了cache记录
  90. if (isset(self::$cache[$id]) && isset(self::$cache[$id]['info'])) {
  91. return self::$cache[$id]['info'];
  92. }
  93. $addr = substr($code['body'], 0, 6);
  94. $birth = ($code['type'] === 18 ? substr($code['body'], 6, 8) :
  95. substr($code['body'], 6, 6));
  96. $order = substr($code['body'], -3);
  97. $info = array();
  98. $info['addrCode'] = $addr;
  99. if (self::$GB2260 !== null) {
  100. $info['addr'] = self::$util->getAddrInfo($addr);
  101. }
  102. $info ['birth'] = ($code ['type'] === 18 ? (substr ( $birth, 0, 4 ) . '-' . substr ( $birth, 4, 2 ) . '-' . substr ( $birth, - 2 )) : ('19' . substr ( $birth, 0, 2 ) . '-' . substr ( $birth, 2, 2 ) . '-' . substr ( $birth, - 2 )));
  103. $info['sex'] = ($order % 2 === 0 ? 0 : 1);
  104. $info['length'] = $code['type'];
  105. if ($code['type'] === 18) {
  106. $info['checkBit'] = $code['checkBit'];
  107. }
  108. // 记录cache
  109. self::$cache[$id]['info'] = $info;
  110. return $info;
  111. }
  112. // 仿造一个号
  113. function makeID ($isFifteen=false) {
  114. // 地址码
  115. $addr = null;
  116. if (self::$GB2260 !== null) {
  117. $loopCnt = 0;
  118. while ($addr === null) {
  119. // 防止死循环
  120. if ($loopCnt > 50) {
  121. $addr = 110101;
  122. break;
  123. }
  124. $prov = self::$util->str_pad(self::$util->rand(66), 2, '0');
  125. $city = self::$util->str_pad(self::$util->rand(20), 2, '0');
  126. $area = self::$util->str_pad(self::$util->rand(20), 2, '0');
  127. $addrTest = $prov . $city . $area;
  128. if (isset(self::$GB2260[$addrTest])) {
  129. $addr = $addrTest;
  130. break;
  131. }
  132. $loopCnt ++;
  133. }
  134. } else {
  135. $addr = 110101;
  136. }
  137. // 出生年
  138. $yr = self::$util->str_pad(self::$util->rand(99, 50), 2, '0');
  139. $mo = self::$util->str_pad(self::$util->rand(12, 1), 2, '0');
  140. $da = self::$util->str_pad(self::$util->rand(28, 1), 2, '0');
  141. if ($isFifteen) {
  142. return $addr . $yr . $mo . $da
  143. . self::$util->str_pad(self::$util->rand(999, 1), 3, '1');
  144. }
  145. $yr = '19' . $yr;
  146. $body = $addr . $yr . $mo . $da . self::$util->str_pad(self::$util->rand(999, 1), 3, '1');
  147. // 位置加权
  148. $posWeight = array();
  149. for ($i = 18; $i > 1; $i--) {
  150. $wei = self::$util->weight($i);
  151. $posWeight[$i] = $wei;
  152. }
  153. // 累加body部分与位置加权的积
  154. $bodySum = 0;
  155. $bodyArr = str_split($body);
  156. for ($j = 0; $j < count($bodyArr); $j++) {
  157. $bodySum += (intval($bodyArr[$j], 10) * $posWeight[18 - $j]);
  158. }
  159. // 得出校验码
  160. $checkBit = 12 - ($bodySum % 11);
  161. if ($checkBit == 10) {
  162. $checkBit = 'X';
  163. } else if ($checkBit > 10) {
  164. $checkBit = $checkBit % 11;
  165. }
  166. return ($body . $checkBit);
  167. }
  168. }