IdCardRule.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. namespace app\common\Rule;
  3. /**
  4. * 身份证验证工具类
  5. */
  6. class IdCardRule
  7. {
  8. /**
  9. * 验证身份证号格式
  10. * @param string $idCard 身份证号
  11. * @return array 返回验证结果 ['valid' => true/false, 'message' => '错误信息']
  12. */
  13. public static function validate($idCard)
  14. {
  15. // 去除空格
  16. $idCard = trim($idCard);
  17. // 检查长度(18位)
  18. if (strlen($idCard) !== 18) {
  19. return ['valid' => false, 'message' => '身份证号必须为18位'];
  20. }
  21. // 检查前17位是否为数字
  22. if (!ctype_digit(substr($idCard, 0, 17))) {
  23. return ['valid' => false, 'message' => '身份证号前17位必须为数字'];
  24. }
  25. // 检查最后一位(数字或X)
  26. $lastChar = strtoupper(substr($idCard, 17, 1));
  27. if (!ctype_digit($lastChar) && $lastChar !== 'X') {
  28. return ['valid' => false, 'message' => '身份证号最后一位必须为数字或字母X'];
  29. }
  30. // 验证日期部分(第7-14位)
  31. $year = substr($idCard, 6, 4);
  32. $month = substr($idCard, 10, 2);
  33. $day = substr($idCard, 12, 2);
  34. // 检查年份范围(1900-当前年份)
  35. $currentYear = date('Y');
  36. if ($year < 1900 || $year > $currentYear) {
  37. return ['valid' => false, 'message' => '身份证号中的出生年份不正确'];
  38. }
  39. // 检查月份
  40. if ($month < 1 || $month > 12) {
  41. return ['valid' => false, 'message' => '身份证号中的出生月份不正确'];
  42. }
  43. // 检查日期
  44. if (!checkdate($month, $day, $year)) {
  45. return ['valid' => false, 'message' => '身份证号中的出生日期不正确'];
  46. }
  47. // 验证校验码
  48. $checkResult = self::validateCheckCode($idCard);
  49. if (!$checkResult['valid']) {
  50. return $checkResult;
  51. }
  52. return ['valid' => true, 'message' => '身份证号格式正确'];
  53. }
  54. /**
  55. * 验证校验码
  56. * @param string $idCard 身份证号
  57. * @return array
  58. */
  59. private static function validateCheckCode($idCard)
  60. {
  61. $weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  62. $checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
  63. $sum = 0;
  64. for ($i = 0; $i < 17; $i++) {
  65. $sum += intval(substr($idCard, $i, 1)) * $weights[$i];
  66. }
  67. $checkCode = $checkCodes[$sum % 11];
  68. $lastChar = strtoupper(substr($idCard, 17, 1));
  69. if ($lastChar !== $checkCode) {
  70. return ['valid' => false, 'message' => '身份证号校验码不正确'];
  71. }
  72. return ['valid' => true, 'message' => '校验码正确'];
  73. }
  74. /**
  75. * 从身份证号获取生日
  76. * @param string $idCard 身份证号
  77. * @return string|false 生日(Y-m-d)或false
  78. */
  79. public static function getBirthday($idCard)
  80. {
  81. $result = self::validate($idCard);
  82. if (!$result['valid']) {
  83. return false;
  84. }
  85. $year = substr($idCard, 6, 4);
  86. $month = substr($idCard, 10, 2);
  87. $day = substr($idCard, 12, 2);
  88. return $year . '-' . $month . '-' . $day;
  89. }
  90. /**
  91. * 从身份证号获取年龄
  92. * @param string $idCard 身份证号
  93. * @return int|false 年龄或false
  94. */
  95. public static function getAge($idCard)
  96. {
  97. $birthday = self::getBirthday($idCard);
  98. if (!$birthday) {
  99. return false;
  100. }
  101. $birthTime = strtotime($birthday);
  102. $age = floor((time() - $birthTime) / (365 * 24 * 3600));
  103. return $age;
  104. }
  105. /**
  106. * 从身份证号获取性别
  107. * @param string $idCard 身份证号
  108. * @return string|false 'male'(男)或'female'(女)或false
  109. */
  110. public static function getGender($idCard)
  111. {
  112. $result = self::validate($idCard);
  113. if (!$result['valid']) {
  114. return false;
  115. }
  116. $genderCode = intval(substr($idCard, 16, 1));
  117. return $genderCode % 2 === 0 ? 'female' : 'male';
  118. }
  119. }