php中验证18位身份证号格式应先用正则/^[1-9]\d{16}[\dxx]$/快速过滤,再通过gb 11643-1999标准校验码算法(加权求和模11查表)确保第18位正确,同时需trim、strlen预判、全角转半角、类型检查等防御性处理。

PHP中用正则验证18位身份证号是否符合格式
直接用正则判断格式是否合法,不校验行政区划码、出生日期真实性或校验码逻辑,适合前端提交后的第一道轻量过滤。
中国大陆身份证号是18位:前17位为数字,最后1位可能是数字或字母X(大小写均可,但标准为大写)。正则需兼顾这几种情况。
-
/^[1-9]\d{16}[\dXx]$/—— 最简匹配,能拦住明显错误(如位数不对、开头为0、含非法字符) - 更严谨一点可加出生年份范围限制:
/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))((0[1-9])|([12]\d)|(3[01]))\d{3}[\dXx]$/,但注意:闰年、每月天数未完全校验,仅防明显乱填(如2月31日) - 实际使用中建议先用简版正则快速过滤,再用完整校验函数处理关键业务(如注册、实名认证)
PHP完整校验身份证号(含校验码、日期逻辑)
只靠正则无法验证第18位校验码是否正确,必须按国标GB 11643-1999实现加权求和+模11运算。PHP里没有内置函数,得自己写。
校验码对应关系为:array('10'=>'X', '11'=>'X', '0'=>'1', '1'=>'0', '2'=>'X', '3'=>'9', '4'=>'8', '5'=>'7', '6'=>'6', '7'=>'5', '8'=>'4', '9'=>'3', '10'=>'2'),但实际只需算余数再查表。
立即学习“PHP免费学习笔记(深入)”;
- 先用正则确保长度和字符合法:
if (!preg_match('/^[1-9]\d{16}[\dXx]$/', $id)) return false; - 把前17位转为整数数组,与权重数组
[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]对应相乘求和 - 对和取模11,查校验码表:
$checkCode = ['1','0','X','9','8','7','6','5','4','3','2'][$sum % 11]; - 最后比较:
strtoupper(substr($id, -1)) === $checkCode
$_POST提交后如何安全调用身份证校验
别直接对 $_POST['id_card'] 做正则或计算,先 trim + 类型过滤,防止空格、\0截断、超长字符串引发异常。
- 获取并清理:
$id = trim($_POST['id_card'] ?? '') ?: ''; - 长度预判:
if (strlen($id) !== 18) { /* 格式错误 */ },比正则更快失败 - 避免全角数字混入:可用
str_replace(['0','1','2','3','4','5','6','7','8','9'], range(0,9), $id)简单兼容,但更推荐前端限制输入法 - 如果校验失败,返回明确提示(如“身份证格式不正确”),不要暴露校验细节(如“第18位应为X”),防探测
常见报错和绕过陷阱
看似简单的身份证验证,线上常因边界情况翻车:
- 用户粘贴带空格或换行的身份证号 →
trim()必须做,且建议用preg_replace('/\s+/', '', $id)清除所有空白符 - X被输成小写x → 校验码比对前统一转大写:
strtoupper()不可少 - 传入null或数组触发Warning → 先用
is_string($id) && $id !== ''守住入口 - 超长字符串(如1000字符)导致内存溢出或正则回溯爆炸 → 在
strlen($id) > 18时直接拒绝,不进正则 - 部分老系统用15位身份证(已淘汰),若需兼容,得单独分支处理,但新项目不建议支持
校验码算法本身不难,难的是各种脏数据怎么挡在门外——真正上线前,一定要用真实用户可能输入的混乱样本(如复制粘贴、语音识别结果、OCR误识)跑一遍测试。










