IDCardNumber.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <?php
  2. namespace UCore\Random;
  3. class IDCardNumber
  4. {
  5. function generateIdNumber() {
  6. // 随机生成地址码(前6位)
  7. $addressCode = str_pad(mt_rand(1, 10000), 6, '0', STR_PAD_LEFT);
  8. // 随机生成生日码(中间8位)
  9. $birthday = mt_rand(strtotime('1970-01-01'), time());
  10. $birthdayCode = date('Ymd', $birthday);
  11. // 随机生成顺序码(最后4位)
  12. $sequenceCode = str_pad(mt_rand(1, 9999), 4, '0', STR_PAD_LEFT);
  13. // 计算校验码
  14. $id17 = $addressCode . $birthdayCode . $sequenceCode;
  15. $checksum = 0;
  16. for ($i = 0; $i < 17; $i++) {
  17. $checksum += ($id17[$i] * (18 - $i));
  18. }
  19. $mod = $checksum % 11;
  20. $checkCode = $mod == 0 ? '1' : ($mod == 1 ? '0' : (12 - $mod) % 11);
  21. return $id17 . $checkCode;
  22. }
  23. /**
  24. * 随机生成有效的 18 长度的身份证号
  25. * 中华人民共和国国家标准 GB/T 2260 行政区划代码 https://github.com/cn/GB2260.php/blob/master/README.md
  26. * @return string
  27. * @throws \Exception
  28. */
  29. public static function genID()
  30. {
  31. // vendor/lybc/php-gb2260/data/cn-gb2260.php
  32. $addressCodes = require __DIR__ . '/../../../vendor/lybc/php-gb2260/data/cn-gb2260.php';//地区编码
  33. $codes = array_keys($addressCodes);
  34. $code = $codes[array_rand($codes)];
  35. //出生年月日
  36. $year = 1900 + mt_rand(50, 102);//最大是 2002 年
  37. $month = str_pad(mt_rand(1, 12), 2, '0', STR_PAD_LEFT);
  38. switch ($month) {
  39. case '02'://2 月按照 28 天算,简化一下,不算闰年
  40. $day = str_pad(mt_rand(1, 28), 2, '0', STR_PAD_LEFT);
  41. break;
  42. case '04':
  43. case '06':
  44. case '09':
  45. case '11':
  46. $day = str_pad(mt_rand(1, 30), 2, '0', STR_PAD_LEFT);
  47. break;
  48. default:
  49. $day = str_pad(mt_rand(1, 31), 2, '0', STR_PAD_LEFT);
  50. break;
  51. }
  52. $body = $code . $year . $month . $day . str_pad(mt_rand(1, 999), 3, '1');//身份证前 17 位
  53. //十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, … , 16 ,先对前17位数字的权求和
  54. //Ai:表示第i位置上的身份证号码数字值
  55. //Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
  56. $weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];//身份证的加权因子
  57. $bodySum = 0;
  58. //累加body部分与位置加权的积
  59. for ($i = 0; $i < count($weight); $i++) {
  60. $bodySum = $bodySum + intval($body[$i]) * $weight[$i];
  61. }
  62. $checkNumber = null;
  63. $mod = $bodySum % 11;//余数为 2 时即表示身份证最后一位为 X(表示 10)
  64. switch ($mod) {
  65. case 0:
  66. $checkNumber = '1';
  67. break;
  68. case 1:
  69. $checkNumber = '0';
  70. break;
  71. case 2:
  72. $checkNumber = 'X';
  73. break;
  74. case 3:
  75. $checkNumber = '9';
  76. break;
  77. case 4:
  78. $checkNumber = '8';
  79. break;
  80. case 5:
  81. $checkNumber = '7';
  82. break;
  83. case 6:
  84. $checkNumber = '6';
  85. break;
  86. case 7:
  87. $checkNumber = '5';
  88. break;
  89. case 8:
  90. $checkNumber = '4';
  91. break;
  92. case 9:
  93. $checkNumber = '3';
  94. break;
  95. case 10:
  96. $checkNumber = '2';
  97. break;
  98. }
  99. // $sex = $body[16] % 2 == 1 ? '男' : '女';//第 17 为数字为奇数表示 男,否则为 女
  100. // $address = (new \GB2260\GB2260())->get($code);//根据地区编码获取地址
  101. return $body . $checkNumber;
  102. }
  103. }