idCard.js
7.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
export function IDValidator() {
var param = {
error : {
longNumber : '长数字存在精度问题,请使用字符串传值! Long number is not allowed, because the precision of the Number In JavaScript.'
}
};
var util = {
checkArg : function(id) {
var argType = (typeof id);
switch (argType) {
case 'number':
// long number not allowed
id = id.toString();
if (id.length > 15) {
this.error(param.error.longNumber);
return false;
}
break;
case 'string':
break;
default:
return false;
}
id = id.toUpperCase();
var code = null;
if (id.length === 18) {
// 18位
code = {
body : id.slice(0, 17),
checkBit : id.slice(-1),
type : 18
};
} else if (id.length === 15) {
// 15位
code = {
body : id,
type : 15
};
} else {
return false;
}
return code;
}
// 地址码检查
,
checkAddr : function(addr, GB2260) {
var addrInfo = this.getAddrInfo(addr, GB2260);
return (addrInfo === false ? false : true);
}
// 取得地址码信息
,
getAddrInfo : function(addr, GB2260) {
GB2260 = GB2260 || null;
// 查询GB/T2260,没有引入GB2260时略过
if (GB2260 === null) {
return addr;
}
if (!GB2260.hasOwnProperty(addr)) {
// 考虑标准不全的情况,搜索不到时向上搜索
var tmpAddr;
tmpAddr = addr.slice(0, 4) + '00';
if (!GB2260.hasOwnProperty(tmpAddr)) {
tmpAddr = addr.slice(0, 2) + '0000';
if (!GB2260.hasOwnProperty(tmpAddr)) {
return false;
} else {
return GB2260[tmpAddr] + '未知地区';
}
} else {
return GB2260[tmpAddr] + '未知地区';
}
} else {
return GB2260[addr];
}
}
// 生日码检查
,
checkBirth : function(birth) {
var year, month, day;
if (birth.length == 8) {
year = parseInt(birth.slice(0, 4), 10);
month = parseInt(birth.slice(4, 6), 10);
day = parseInt(birth.slice(-2), 10);
} else if (birth.length == 6) {
year = parseInt('19' + birth.slice(0, 2), 10);
month = parseInt(birth.slice(2, 4), 10);
day = parseInt(birth.slice(-2), 10);
} else {
return false;
}
// TODO 是否需要判断年份
/*
* if( year<1800 ){ return false; }
*/
// TODO 按月份检测
if (month > 12 || month === 0 || day > 31 || day === 0) {
return false;
}
return true;
}
// 顺序码检查
,
checkOrder : function(order) {
// 暂无需检测
return true;
}
// 加权
,
weight : function(t) {
return Math.pow(2, t - 1) % 11;
}
// 随机整数
,
rand : function(max, min) {
min = min || 1;
return Math.round(Math.random() * (max - min)) + min;
}
// 数字补位
,
str_pad : function(str, len, chr, right) {
str = str.toString();
len = len || 2;
chr = chr || '0';
right = right || false;
if (str.length >= len) {
return str;
} else {
for (var i = 0, j = len - str.length; i < j; i++) {
if (right) {
str = str + chr;
} else {
str = chr + str;
}
}
return str;
}
}
// 抛错
,
error : function(msg) {
var e = new Error();
e.message = 'IDValidator: ' + msg;
throw e;
}
};
var _IDValidator = function(GB2260) {
if (typeof GB2260 !== "undefined") {
this.GB2260 = GB2260;
}
// 建立cache
this.cache = {};
};
_IDValidator.prototype = {
isValid : function(id) {
var GB2260 = this.GB2260 || null;
var code = util.checkArg(id);
if (code === false) {
return false;
}
// 查询cache
if (this.cache.hasOwnProperty(id)
&& typeof this.cache[id].valid !== 'undefined') {
return this.cache[id].valid;
} else {
if (!this.cache.hasOwnProperty(id)) {
this.cache[id] = {};
}
}
var addr = code.body.slice(0, 6);
var birth = (code.type === 18 ? code.body.slice(6, 14) : code.body
.slice(6, 12));
var order = code.body.slice(-3);
if (!(util.checkAddr(addr, GB2260) && util.checkBirth(birth) && util
.checkOrder(order))) {
this.cache[id].valid = false;
return false;
}
// 15位不含校验码,到此已结束
if (code.type === 15) {
this.cache[id].valid = true;
return true;
}
/* 校验位部分 */
// 位置加权
var posWeight = [];
for (var i = 18; i > 1; i--) {
var wei = util.weight(i);
posWeight[i] = wei;
}
// 累加body部分与位置加权的积
var bodySum = 0;
var bodyArr = code.body.split('');
for (var j = 0; j < bodyArr.length; j++) {
bodySum += (parseInt(bodyArr[j], 10) * posWeight[18 - j]);
}
// 得出校验码
var checkBit = 12 - (bodySum % 11);
if (checkBit == 10) {
checkBit = 'X';
} else if (checkBit > 10) {
checkBit = checkBit % 11;
}
checkBit = (typeof checkBit === 'number' ? checkBit.toString()
: checkBit);
// 检查校验码
if (checkBit !== code.checkBit) {
this.cache[id].valid = false;
return false;
} else {
this.cache[id].valid = true;
return true;
}
}
// 分析详细信息
,
getInfo : function(id) {
var GB2260 = this.GB2260 || null;
// 号码必须有效
if (this.isValid(id) === false) {
return false;
}
// TODO 复用此部分
var code = util.checkArg(id);
// 查询cache
// 到此时通过isValid已经有了cache记录
if (typeof this.cache[id].info !== 'undefined') {
return this.cache[id].info;
}
var addr = code.body.slice(0, 6);
var birth = (code.type === 18 ? code.body.slice(6, 14) : code.body
.slice(6, 12));
var order = code.body.slice(-3);
var info = {};
info.addrCode = addr;
if (GB2260 !== null) {
info.addr = util.getAddrInfo(addr, GB2260);
}
info.birth = (code.type === 18 ? (([ birth.slice(0, 4),
birth.slice(4, 6), birth.slice(-2) ]).join('-')) : ([
'19' + birth.slice(0, 2), birth.slice(2, 4),
birth.slice(-2) ]).join('-'));
info.sex = (order % 2 === 0 ? 0 : 1);
info.length = code.type;
if (code.type === 18) {
info.checkBit = code.checkBit;
}
// 记录cache
this.cache[id].info = info;
return info;
}
// 仿造一个号
,
makeID : function(isFifteen) {
var GB2260 = this.GB2260 || null;
// 地址码
var addr = null;
if (GB2260 !== null) {
var loopCnt = 0;
while (addr === null) {
// 防止死循环
if (loopCnt > 10) {
addr = 110101;
break;
}
var prov = util.str_pad(util.rand(50), 2, '0');
var city = util.str_pad(util.rand(20), 2, '0');
var area = util.str_pad(util.rand(20), 2, '0');
var addrTest = [ prov, city, area ].join('');
if (GB2260[addrTest]) {
addr = addrTest;
break;
}
}
} else {
addr = 110101;
}
// 出生年
var yr = util.str_pad(util.rand(99, 50), 2, '0');
var mo = util.str_pad(util.rand(12, 1), 2, '0');
var da = util.str_pad(util.rand(28, 1), 2, '0');
if (isFifteen) {
return addr + yr + mo + da
+ util.str_pad(util.rand(999, 1), 3, '1');
}
yr = '19' + yr;
var body = addr + yr + mo + da
+ util.str_pad(util.rand(999, 1), 3, '1');
// 位置加权
var posWeight = [];
for (var i = 18; i > 1; i--) {
var wei = util.weight(i);
posWeight[i] = wei;
}
// 累加body部分与位置加权的积
var bodySum = 0;
var bodyArr = body.split('');
for (var j = 0; j < bodyArr.length; j++) {
bodySum += (parseInt(bodyArr[j], 10) * posWeight[18 - j]);
}
// 得出校验码
var checkBit = 12 - (bodySum % 11);
if (checkBit == 10) {
checkBit = 'X';
} else if (checkBit > 10) {
checkBit = checkBit % 11;
}
checkBit = (typeof checkBit === 'number' ? checkBit.toString()
: checkBit);
return (body + checkBit);
}
};// _IDValidator
var GB2260 = GB2260 == null ? "" : GB2260;
return new _IDValidator(GB2260);
}