SIM卡的ICCID校验位的计算方法,应该不是什么隐私或者机密吧,最近关于这个有点小发现,故写出来与大家分享一下。
ICCID简介
ICCID (Integerate Circuit Card Identity),集成电路卡识别码,是SIM卡的唯一识别号码。ICCID长为19~20位,其中最后一位是校验位(当然也有另外,中移动的某些卡就不是校验位,而是普通的序列号)。关于其它位的含义,可自行百度。
背景
最近要处理中国联通物联网卡的相关业务,需要对接联通的Jasper平台,封装成自己的一套API给客户用,查询卡的信息是通过卡的ICCID(移动、电信用的是MSISDN)。同事给过来一张联通的卡号清单,有ICCID和MSISDN,通过API查询其中一个ICCID的相关信息,结果没查到,于是通过浏览器在联通的管理平台再次查询,还是没查到,这就纳闷了!询问同事,同事说要在ICCID后面加上*
,才能查询到。测试了一下,果然可以查到,只是查出的号码多了一位!
原来,同事给我的号码清单,其中ICCID只有19位,而通过API或者管理平台,需要20位的ICCID才能查询,其中第二十位就是前面19位的校验位。
现在问题来了:如何计算ICCID的校验位?
第一部分:问题初探
首先是百度,通过“iccid 校验位”关键字查询,很多人问与我同样的问题,大部分介绍的都是Luhn
算法,其中知乎上有位热心的网友给出了详细的关于ICCID的介绍,以及Luhn
算法的维基百科链接。进入该维基百科的页面,都是些英文,后面是各种语言的Luhn
算法实现,由于目前是用PHP开发,就把PHP版本的代码复制了下来:
function checkLuhn($number) {
$sum = 0;
$numDigits = strlen($number)-1;
$parity = $numDigits % 2;
for ($i = $numDigits; $i >= 0; $i--) {
$digit = substr($number, $i, 1);
if (!$parity == ($i % 2)) {
$digit <<= 1;}
$digit = ($digit > 9) ? ($digit - 9) : $digit;
$sum += $digit;
}
return (0 == ($sum % 10));
}
由于是求校验位,显然,return
那行代码不对,我们只需要求校验和除10的余数就行了。如下:
function checkLuhn($number) {
$sum = 0;
$numDigits = strlen($number)-1;
$parity = $numDigits % 2;
for ($i = $numDigits; $i >= 0; $i--) {
$digit = substr($number, $i, 1);
if (!$parity == ($i % 2)) {
$digit <<= 1;}
$digit = ($digit > 9) ? ($digit - 9) : $digit;
$sum += $digit;
}
return (