首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 從身份證號提取出生日期與成年判斷(支援 15/18 位)

     編輯:PHP 綜合知識

身份證號碼編碼規則國家標準(GB 11643-1999)規定:第 7-14 位為出生日期(YYYYMMDD),15 位舊版身份證年份僅保留後兩位(19XX)。本文提供健壯的解析函數,含格式校驗、日期合法性檢查、成年判定。

身份證號結構速查

版本長度出生日期位置年份格式
舊版15 位第 7-12 位YYMMDD (19XX)
新版18 位第 7-14 位YYYYMMDD

核心解析函數

/**
 * 解析身份證號,返回生日、是否成年、錯誤碼
 * @param string $idCard 身份證號碼
 * @param int $format 1=YYYY-MM-DD, 0=MM-DD
 * @return array ['error'=>0/1/2, 'isAdult'=>0/1, 'birthday'=>'', 'gender'=>'male/female']
 */
function parseIdCard(string $idCard, int $format = 1): array {
    $result = [
        'error' => 0,      // 0=未知錯誤, 1=格式錯誤, 2=成功
        'isAdult' => 0,    // 0=成年, 1=未成年
        'birthday' => '',
        'gender' => '',
    ];

    // 1. 格式正則校驗(支援大小寫 X)
    if (!preg_match('/^(\d{15}|\d{17}[\dXx])$/', $idCard)) {
        $result['error'] = 1;
        return $result;
    }

    // 2. 提取出生日期
    if (strlen($idCard) === 18) {
        $year  = (int)substr($idCard, 6, 4);
        $month = (int)substr($idCard, 10, 2);
        $day   = (int)substr($idCard, 12, 2);
        // 性別:倒數第 2 位奇男偶女
        $result['gender'] = ((int)substr($idCard, 16, 1) % 2) ? 'male' : 'female';
    } else { // 15 位
        $year  = 1900 + (int)substr($idCard, 6, 2);
        $month = (int)substr($idCard, 8, 2);
        $day   = (int)substr($idCard, 10, 2);
        $result['gender'] = ((int)substr($idCard, 14, 1) % 2) ? 'male' : 'female';
    }

    // 3. 日期合法性檢查
    if (!checkdate($month, $day, $year)) {
        $result['error'] = 1;
        return $result;
    }

    // 合理性範圍:100 歲內、非未來
    $nowYear = (int)date('Y');
    if ($year < $nowYear - 100 || $year > $nowYear) {
        $result['error'] = 1;
        return $result;
    }

    // 4. 格式化輸出
    $result['birthday'] = $format 
        ? sprintf('%04d-%02d-%02d', $year, $month, $day)
        : sprintf('%02d-%02d', $month, $day);

    // 5. 成年判定(18 歲整)
    $birthTimestamp = mktime(0, 0, 0, $month, $day, $year);
    $ageSeconds = time() - $birthTimestamp;
    $result['isAdult'] = ($ageSeconds >= 18 * 365 * 24 * 3600) ? 0 : 1;

    $result['error'] = 2;
    return $result;
}

使用範例

$tests = [
    '110101199003071234',  // 18 位
    '110101900307123',     // 15 位
    '11010120101231123X',  // 含 X
    'invalid',             // 錯誤格式
];

foreach ($tests as $id) {
    $info = parseIdCard($id);
    echo "ID: {$id}\n";
    echo "  錯誤碼: {$info['error']} (2=成功)\n";
    echo "  生日: {$info['birthday']}\n";
    echo "  性別: {$info['gender']}\n";
    echo "  成年: " . ($info['isAdult'] ? '否' : '是') . "\n\n";
}

進階擴展建議

  1. 校驗碼驗證:18 位身份證第 18 位為 ISO 7064:1983.MOD 11-2 校驗碼,可進一步驗證真偽
  2. 地址碼解析:前 6 位行政區劃代碼可關聯 GB/T 2260 標準查詢戶籍地
  3. 年齡精確計算:考慮閏年、具體出生時間,使用 DateTime::diff()
  4. 隱私保護:日誌、異常上報務必脫敏(如 110101******1234)

校驗碼算法補充(可選集成)

function validateChecksum(string $id18): bool {
    if (strlen($id18) !== 18) return false;
    $weights = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2];
    $checkMap = ['1','0','X','9','8','7','6','5','4','3','2'];
    $sum = 0;
    for ($i = 0; $i < 17; $i++) {
        $sum += (int)$id18[$i] * $weights[$i];
    }
    return strtoupper($id18[17]) === $checkMap[$sum % 11];
}

身份證解析看似簡單,實則涉及正則校驗、日期邊界、編碼規則演進等多維考量。生產環境建議封裝為獨立 Composer 包,配合單元測試覆蓋各種邊界案例,確保業務穩健。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved