1. 程式人生 > >Javascript驗證表單身份證號碼的合法性

Javascript驗證表單身份證號碼的合法性

文章出處:

不少大的遊戲註冊時都要輸入身份證號碼,來限制未成年人,配合所謂的反沉迷系統,賬號註冊環節注重的是快捷,所以身份證驗證都不是真實的驗證,只是根據身份證格式簡單判斷是否合法而已,騙騙小學生,當然也不是那麼簡單。昨天研究了下身份證表單驗證,用javascript寫一個身份證號碼的驗證程式,和盛大賬號註冊的身份證驗證基本差不多。如果有興趣可以瞭解下~

首先要知道我國身份證號碼的規則,我國的身份證為18位,老的身份證是15位。GB11643-1999《公民身份號碼》中做了明確的規定:公民身份號碼是特徵組合碼,由十七位數字本體碼和一位數字校驗碼組成。排列順序從左至右依次為:六位數字地址碼,八位數字出生日期碼,三位數字順序碼和一位數字校驗碼。

地址碼:身份證前6位,表示編碼物件常住戶口所在縣(市、旗、區)的行政區劃程式碼。1-2位為省編號,3-4位為市編號,5-6位為縣區編號。

各省編號為:11:”北京”,12:”天津”,13:”河北”,14:”山西”,15:”內蒙古”,21:”遼寧”,22:”吉林”,23:”黑龍江”,31:”上海”,32:”江蘇”,33:”浙江”,34:”安徽”,35:”福建”,36:”江西”,37:”山東”,41:”河南”,42:”湖北”,43:”湖南”,44:”廣東”,45:”廣西”,46:”海南”,50:”重慶”,51:”四川”,52:”貴州”,53:”雲南”,54:”西藏”,61:”陝西”,62:”甘肅”,63:”青海”,64:”寧夏”,65:”新疆”,71:”臺灣”,81:”香港”,82:”澳門”,91:”國外”,目前共有34個省級行政區,即4個直轄市、23個省、5個自治區、2個特別行政區。

出生日期碼:身份證7-12位,表示物件出生年月日,15位的身份證號碼年份為2位數。

順序碼:同一地址碼所標識的區域範圍內,對同年、月、日出生的人編定的順序號。其中13-15位為各派出所分配的號碼段,其中第17位奇數分給男性,偶數分給女性。對於同一地區同年、月、日出生的人,先到派出所上戶口的先分配編碼,以此類推。

校驗碼:身份證最後一位,根據前面十七位數字碼,按照ISO 7064:1983.MOD 11-2校驗碼計算出來的檢驗碼。計算規則如下:

1、將前面的身份證號碼17位數分別乘以不同的係數。從第1位到第17位的係數分別為:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

2、將身份證前17位數字分別和對應位置的係數相乘的結果相加。

3、用加出來和除以11,看餘數是多少?

4、餘數只可能有0 1 2 3 4 5 6 7 8 9 10這11個數字。其分別對應的最後一位身份證的號碼為1 0 X 9 8 7 6 5 4 3 2。

5、通過上面得知如果餘數是2,就會在身份證的第18位數字上出現羅馬數字的Ⅹ。如果餘數是10,身份證的最後一位號碼就是2。

由上文可知,要檢驗一個身份證號碼是否合法,可以檢驗省份程式碼、出生日期和校驗碼這三個部分結構是否正確即可。為什麼只檢驗省份程式碼?我國目前有7000多個縣區,要一一檢查6位地址碼沒必要,所以前端只要簡單檢驗下省份程式碼就行了。出生日期要檢查是否有效,比如使用者輸入一個20135475這樣一個根本不存在的年月日,可以用javascript的Date()來檢驗日期是否為有效日期。校驗碼為身份證前17位數字通過一套公式算出來的,這個並不難。最後還需要檢驗如果是15位的身份證號碼,雖然我國1999年開始升18位身份證號碼,不過還是有少部分人沒有去辦理二代身份證,由於15位身份證號碼沒有校驗碼,所以只能簡單判斷省編號和出生日期了。

下面可以開始寫javascript身份證表單檢驗程式了,以下是我寫的一段簡單的javascript程式碼。

<script type="text/javascript">
window.onload=function(){
    var oTxt=document.getElementById('txt');
    var oBtn=document.getElementById('btn');
 
    var CheckIdCard={
        //Wi 加權因子 Xi 餘數0~10對應的校驗碼 Pi省份程式碼
        Wi:[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2],
        Xi:[1,0,"X",9,8,7,6,5,4,3,2],
        Pi:[11,12,13,14,15,21,22,23,31,32,33,34,35,36,37,41,42,43,44,45,46,50,51,52,53,54,61,62,63,64,65,71,81,82,91],
 
        //檢驗18位身份證號碼出生日期是否有效
        //parseFloat過濾前導零,年份必需大於等於1900且小於等於當前年份,用Date()物件判斷日期是否有效。
        brithday18:function(sIdCard){
            var year=parseFloat(sIdCard.substr(6,4));
            var month=parseFloat(sIdCard.substr(10,2));
            var day=parseFloat(sIdCard.substr(12,2));
            var checkDay=new Date(year,month-1,day);
            var nowDay=new Date();
            if (1900<=year && year<=nowDay.getFullYear() && month==(checkDay.getMonth()+1) && day==checkDay.getDate()) {
                return true;
            };
        },
 
        //檢驗15位身份證號碼出生日期是否有效
        brithday15:function(sIdCard){
            var year=parseFloat(sIdCard.substr(6,2));
            var month=parseFloat(sIdCard.substr(8,2));
            var day=parseFloat(sIdCard.substr(10,2));
            var checkDay=new Date(year,month-1,day);
            if (month==(checkDay.getMonth()+1) && day==checkDay.getDate()) {
                return true;
            };
        },
 
        //檢驗校驗碼是否有效
        validate:function(sIdCard){
            var aIdCard=sIdCard.split("");
            var sum=0;
            for (var i = 0; i < CheckIdCard.Wi.length; i++) {
                sum+=CheckIdCard.Wi[i]*aIdCard[i]; //線性加權求和
            };
            var index=sum%11;//求模,可能為0~10,可求對應的校驗碼是否於身份證的校驗碼匹配
            if (CheckIdCard.Xi[index]==aIdCard[17].toUpperCase()) {
                return true;
            };
        },
 
        //檢驗輸入的省份編碼是否有效
        province:function(sIdCard){
            var p2=sIdCard.substr(0,2);
            for (var i = 0; i < CheckIdCard.Pi.length; i++) {
                if(CheckIdCard.Pi[i]==p2){
                    return true;
                };
            };
        }
    };
 
    oBtn.onclick=function(){
        var sIdCard=oTxt.value.replace(/^\s+|\s+$/g,"");//去除字串的前後空格,允許使用者不小心輸入前後空格
        if (sIdCard.match(/^\d{14,17}(\d|X)$/gi)==null) {//判斷是否全為18或15位數字,最後一位可以是大小寫字母X
            alert("身份證號碼須為18位或15位數字");      //允許使用者輸入大小寫X代替羅馬數字的Ⅹ
        }
        else if (sIdCard.length==18) {
            if (CheckIdCard.province(sIdCard)&&CheckIdCard.brithday18(sIdCard)&&CheckIdCard.validate(sIdCard)) {
                alert("身份證號碼合法");
            }
            else{
                alert("請輸入有效的身份證號碼");
            };
        }
        else if (sIdCard.length==15) {
            if (CheckIdCard.province(sIdCard)&&CheckIdCard.brithday15(sIdCard)) {
                alert("身份證號碼合法");
            }
            else{
                alert("請輸入有效的身份證號碼");
            };
        };
    };
}
</script>


基本和盛大賬號註冊的身份證號碼驗證功能一樣。缺點只能根據身份證格式來簡單判斷是否合法,不能判斷身份證號碼和姓名的真實性,同時只要省份程式碼、出生日期和校驗碼填寫正確格式,其他亂寫也能通過,這些表單驗證只能騙騙不懂規則的小學生,

其實,完全可以虛構一個15位的身份證號碼,因為沒有複雜計算的校驗碼,只要省份程式碼和出生日期格式正確,其他的順便寫,基本能通過各種身份證的表單驗證,親測多個網站的註冊驗證屢試不爽。當然,如果真的需要確實身份證的真實性,一般像支付寶,電信,銀行等都會連線“全國公民身份資訊資料庫”,人工稽核提交的身份證姓名和資訊是否真實。個人也可以到“全國公民身份證號碼查詢服務中心”查身份證號碼,5塊錢一次。