您如何根据号码检测信用卡类型?

And*_*son 504 language-agnostic algorithm e-commerce

我试图弄清楚如何根据其数量来检测信用卡的类型.有谁知道一个明确,可靠的方法来找到这个?

sen*_*nfo 743

信用卡/借记卡号码称为PAN主帐号.PAN的前六位是取自IIN,或发行方识别号,属于开证行(不结盟研究所以前称为BIN -银行标识号-所以你可能会看到一些文件,这一术语引用).这六个数字符合国际标准ISO/IEC 7812,可用于从数字中确定卡的类型.

遗憾的是,实际的ISO/IEC 7812数据库不公开,但是有非商业和免费的非官方列表,包括维基百科.

无论如何,要从数字中检测类型,您可以使用如下所示的正则表达式:表示原始表达式

签证: ^4[0-9]{6,}$ Visa卡号码以4开头.

万事达卡: ^5[1-5][0-9]{5,}|222[1-9][0-9]{3,}|22[3-9][0-9]{4,}|2[3-6][0-9]{5,}|27[01][0-9]{4,}|2720[0-9]{3,}$在2016年之前,万事达卡的号码从51到55开头,但这只会检测万事达信用卡 ; 使用万事达卡系统发行的其他卡不属于此IIN范围.2016年,他们将增加该范围内的数字(222100-272099).

^3[47][0-9]{5,}$美国运通卡:美国运通卡号码以34或37开头.

大莱卡: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$大莱卡的卡号从300到305,36或38开始.大莱卡的卡片以5开头,有16位数字.这些是大莱卡和万事达卡之间的合资企业,应该像万事达卡一样处理.

发现: ^6(?:011|5[0-9]{2})[0-9]{3,}$发现卡号以6011或65开头.

JCB: ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ JCB卡以2131,1800或35开头.

不幸的是,使用万事达卡系统处理的卡类型很多,并不存在于万事达卡的IIN范围内(数字从51 ... 55开始); 最重要的情况是Maestro卡,其中许多是从其他银行的IIN范围发行的,所以它们遍布数字空间.因此,最好假设您接受的任何其他类型的卡都必须是万事达卡.

重要提示:卡号的长度各不相同; 例如,Visa过去发行了13位数的PAN卡和16位数的PAN卡.Visa的文件目前表明它可能会发行或者可能发出12到19位数字. 因此,您不应检查卡号的长度,除了验证它至少有7位数(对于完整的IIN加一个校验位,它应该与Luhn算法预测的值相匹配).

进一步提示:在处理持卡人PAN之前,从输入中删除任何空格和标点字符.为什么?因为在组中输入数字通常容易得多,类似于它们在实际信用卡的正面显示的方式,即

4444 4444 4444 4444
Run Code Online (Sandbox Code Playgroud)

比正确输入要容易得多

4444444444444444
Run Code Online (Sandbox Code Playgroud)

惩罚用户真的没有任何好处,因为他们输入了你没想到的字符.

这也意味着确保您的输入字段至少有 24个字符的空间,否则输入空格的用户将用完房间. 我建议你让字段宽到足以显示32个字符,最多允许64个字符; 这为扩展提供了充足的空间.

这是一个提供更多洞察力的图像:

更新(2014):校验和方法似乎不再是验证卡片真实性的有效方法,如本答案的评论中所述.

更新(2016年):万事达卡将实施新的BIN范围,从Ach付款开始.

信用卡验证

  • 很好的例子.你有大师卡的正则表达式吗? (7认同)
  • 不不不.你不能依赖卡号的长度; 他们可以随时改变.您可以信赖的卡号的唯一部分是IIN(以前称为BIN),它是号码的前缀.此外,您*不能*以您建议的方式检测万事达卡; 只能获取通过万事达卡系统处理的卡的子集(主要问题是Maestro卡,它有各种IIN前缀). (4认同)
  • @senfo你是对的,5412不是一个完整的万事达卡号码.IIN长度为六位数,因此完整的卡号必须为7位数(最小值),并且必须通过Luhn检查.没有必要"证明"Mastercard号码有16位以外的数字; 关键在于,无论今天的情况如何,将来他们可能会发行17或18位数的卡,或者就此而言,有15位卡.依靠它们长达16位是不必要的,并且会产生长期维护风险. (3认同)
  • 根据Luhn算法,我发现很难相信一些有效的卡片没有正确的校验位.它绝对用于检查卡号以防止简单的错别字和愚蠢的欺诈行为.相反,我观察到一些相当聪明的人根本没有掌握算法,他们只是计算错了. (3认同)
  • @alastair你在评论之前读过这些表达吗?它们是专门用来使用IIN的,所以我不明白你想说的是什么.此外,IIN可用于识别发卡机构,但不能验证.例如,5412并不代表完整的万事达卡,但您的建议意味着它确实存在.我没有发现万事达卡只有16位数的证据.请随时提供索赔来源.但是,你提到需要为Maestro卡进行更新是正确的. (2认同)
  • @ BaileyParker- [*LUHN算法*](https://en.wikipedia.org/wiki/Luhn_algorithm)不要求数字可被10整除(或任何特定数字),它只是应用公式来生成然后,数字中的值将查看值的最后一位(它使用%10,而不是/ 10).它被[*所有*卡使用](https://en.wikipedia.org/wiki/Bank_card_number)使用. (2认同)
  • 正则表达式不应该总是在"或"子句中"以"开头"吗?目前,当我查看"378282246310005"(这是AmericanExpress)时,该卡也会获得与MasterCard正则表达式的匹配.修复方法是将MasterCard正则表达式更改为"^ 5 [1-5] [0-9] {5,} | ^ 222 [1-9] [0-9] {3,} | ^ 22 [3-9 ] [0-9] {4,} | ^ 2 [3-6] [0-9] {5,} | ^ 27 [01] [0-9] {4,} | ^ 2720 [0-9] {3} $" (2认同)

Ana*_*liy 71

在javascript中:

function detectCardType(number) {
    var re = {
        electron: /^(4026|417500|4405|4508|4844|4913|4917)\d+$/,
        maestro: /^(5018|5020|5038|5612|5893|6304|6759|6761|6762|6763|0604|6390)\d+$/,
        dankort: /^(5019)\d+$/,
        interpayment: /^(636)\d+$/,
        unionpay: /^(62|88)\d+$/,
        visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
        mastercard: /^5[1-5][0-9]{14}$/,
        amex: /^3[47][0-9]{13}$/,
        diners: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
        discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/,
        jcb: /^(?:2131|1800|35\d{3})\d{11}$/
    }

    for(var key in re) {
        if(re[key].test(number)) {
            return key
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

单元测试:

describe('CreditCard', function() {
    describe('#detectCardType', function() {

        var cards = {
            '8800000000000000': 'UNIONPAY',

            '4026000000000000': 'ELECTRON',
            '4175000000000000': 'ELECTRON',
            '4405000000000000': 'ELECTRON',
            '4508000000000000': 'ELECTRON',
            '4844000000000000': 'ELECTRON',
            '4913000000000000': 'ELECTRON',
            '4917000000000000': 'ELECTRON',

            '5019000000000000': 'DANKORT',

            '5018000000000000': 'MAESTRO',
            '5020000000000000': 'MAESTRO',
            '5038000000000000': 'MAESTRO',
            '5612000000000000': 'MAESTRO',
            '5893000000000000': 'MAESTRO',
            '6304000000000000': 'MAESTRO',
            '6759000000000000': 'MAESTRO',
            '6761000000000000': 'MAESTRO',
            '6762000000000000': 'MAESTRO',
            '6763000000000000': 'MAESTRO',
            '0604000000000000': 'MAESTRO',
            '6390000000000000': 'MAESTRO',

            '3528000000000000': 'JCB',
            '3589000000000000': 'JCB',
            '3529000000000000': 'JCB',

            '6360000000000000': 'INTERPAYMENT',

            '4916338506082832': 'VISA',
            '4556015886206505': 'VISA',
            '4539048040151731': 'VISA',
            '4024007198964305': 'VISA',
            '4716175187624512': 'VISA',

            '5280934283171080': 'MASTERCARD',
            '5456060454627409': 'MASTERCARD',
            '5331113404316994': 'MASTERCARD',
            '5259474113320034': 'MASTERCARD',
            '5442179619690834': 'MASTERCARD',

            '6011894492395579': 'DISCOVER',
            '6011388644154687': 'DISCOVER',
            '6011880085013612': 'DISCOVER',
            '6011652795433988': 'DISCOVER',
            '6011375973328347': 'DISCOVER',

            '345936346788903': 'AMEX',
            '377669501013152': 'AMEX',
            '373083634595479': 'AMEX',
            '370710819865268': 'AMEX',
            '371095063560404': 'AMEX'
        };

        Object.keys(cards).forEach(function(number) {
            it('should detect card ' + number + ' as ' + cards[number], function() {
                Basket.detectCardType(number).should.equal(cards[number]);
            });
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

  • @jolly.exe - 您的小提琴对于所有测试都返回未定义。不起作用:( (3认同)

Jan*_*abo 34

更新时间:2016年6月15日(目前为最终解决方案)

请注意,我甚至投票支持最高投票,但为了明确这些正在实际工作的regexp我用数千个真正的BIN代码测试它.最重要的是使用开始字符串(^)否则会在现实世界中给出错误的结果!

JCB ^(?:2131|1800|35)[0-9]{0,}$开头:2131,1800,35(3528-3589)

美国运通 ^3[47][0-9]{0,}$开始于:34,37

Diners Club ^3(?:0[0-59]{1}|[689])[0-9]{0,}$开始于:300-305,309,36,38-39

签证 ^4[0-9]{0,}$开始于:4

万事达卡 ^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$开头:2221-2720,51-55

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro总是在60-69范围内成长,从/不是别的开始,但是起点5必须编码为万事达卡.必须在代码末尾检测到Maestro卡,因为其他一些卡的范围为60-69.请看代码.

发现 ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$发现很难编码,开始于:6011,622126-622925,644-649,65

javascript中我使用此功能.当你将它分配给onkeyup事件并且它尽快给出结果时这很好.

function cc_brand_id(cur_val) {
  // the regular expressions check for possible matches as you type, hence the OR operators based on the number of chars
  // regexp string length {0} provided for soonest detection of beginning of the card numbers this way it could be used for BIN CODE detection also

  //JCB
  jcb_regex = new RegExp('^(?:2131|1800|35)[0-9]{0,}$'); //2131, 1800, 35 (3528-3589)
  // American Express
  amex_regex = new RegExp('^3[47][0-9]{0,}$'); //34, 37
  // Diners Club
  diners_regex = new RegExp('^3(?:0[0-59]{1}|[689])[0-9]{0,}$'); //300-305, 309, 36, 38-39
  // Visa
  visa_regex = new RegExp('^4[0-9]{0,}$'); //4
  // MasterCard
  mastercard_regex = new RegExp('^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$'); //2221-2720, 51-55
  maestro_regex = new RegExp('^(5[06789]|6)[0-9]{0,}$'); //always growing in the range: 60-69, started with / not something else, but starting 5 must be encoded as mastercard anyway
  //Discover
  discover_regex = new RegExp('^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$');
  ////6011, 622126-622925, 644-649, 65


  // get rid of anything but numbers
  cur_val = cur_val.replace(/\D/g, '');

  // checks per each, as their could be multiple hits
  //fix: ordering matter in detection, otherwise can give false results in rare cases
  var sel_brand = "unknown";
  if (cur_val.match(jcb_regex)) {
    sel_brand = "jcb";
  } else if (cur_val.match(amex_regex)) {
    sel_brand = "amex";
  } else if (cur_val.match(diners_regex)) {
    sel_brand = "diners_club";
  } else if (cur_val.match(visa_regex)) {
    sel_brand = "visa";
  } else if (cur_val.match(mastercard_regex)) {
    sel_brand = "mastercard";
  } else if (cur_val.match(discover_regex)) {
    sel_brand = "discover";
  } else if (cur_val.match(maestro_regex)) {
    if (cur_val[0] == '5') { //started 5 must be mastercard
      sel_brand = "mastercard";
    } else {
      sel_brand = "maestro"; //maestro is all 60-69 which is not something else, thats why this condition in the end
    }
  }

  return sel_brand;
}
Run Code Online (Sandbox Code Playgroud)

在这里你可以玩它:

http://jsfiddle.net/upN3L/69/

对于PHP使用此功能,它也会检测一些子VISA/MC卡:

    /**
 * Obtain a brand constant from a PAN 
 *
 * @param type $pan               Credit card number
 * @param type $include_sub_types Include detection of sub visa brands
 * @return string
 */
public static function getCardBrand($pan, $include_sub_types = false)
{
    //maximum length is not fixed now, there are growing number of CCs has more numbers in length, limiting can give false negatives atm

    //these regexps accept not whole cc numbers too
    //visa        
    $visa_regex = "/^4[0-9]{0,}$/";
    $vpreca_regex = "/^428485[0-9]{0,}$/";
    $postepay_regex = "/^(402360|402361|403035|417631|529948){0,}$/";
    $cartasi_regex = "/^(432917|432930|453998)[0-9]{0,}$/";
    $entropay_regex = "/^(406742|410162|431380|459061|533844|522093)[0-9]{0,}$/";
    $o2money_regex = "/^(422793|475743)[0-9]{0,}$/";

    // MasterCard
    $mastercard_regex = "/^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$/";
    $maestro_regex = "/^(5[06789]|6)[0-9]{0,}$/"; 
    $kukuruza_regex = "/^525477[0-9]{0,}$/";
    $yunacard_regex = "/^541275[0-9]{0,}$/";

    // American Express
    $amex_regex = "/^3[47][0-9]{0,}$/";

    // Diners Club
    $diners_regex = "/^3(?:0[0-59]{1}|[689])[0-9]{0,}$/";

    //Discover
    $discover_regex = "/^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$/";

    //JCB
    $jcb_regex = "/^(?:2131|1800|35)[0-9]{0,}$/";

    //ordering matter in detection, otherwise can give false results in rare cases
    if (preg_match($jcb_regex, $pan)) {
        return "jcb";
    }

    if (preg_match($amex_regex, $pan)) {
        return "amex";
    }

    if (preg_match($diners_regex, $pan)) {
        return "diners_club";
    }

    //sub visa/mastercard cards
    if ($include_sub_types) {
        if (preg_match($vpreca_regex, $pan)) {
            return "v-preca";
        }
        if (preg_match($postepay_regex, $pan)) {
            return "postepay";
        }
        if (preg_match($cartasi_regex, $pan)) {
            return "cartasi";
        }
        if (preg_match($entropay_regex, $pan)) {
            return "entropay";
        }
        if (preg_match($o2money_regex, $pan)) {
            return "o2money";
        }
        if (preg_match($kukuruza_regex, $pan)) {
            return "kukuruza";
        }
        if (preg_match($yunacard_regex, $pan)) {
            return "yunacard";
        }
    }

    if (preg_match($visa_regex, $pan)) {
        return "visa";
    }

    if (preg_match($mastercard_regex, $pan)) {
        return "mastercard";
    }

    if (preg_match($discover_regex, $pan)) {
        return "discover";
    }

    if (preg_match($maestro_regex, $pan)) {
        if ($pan[0] == '5') {//started 5 must be mastercard
            return "mastercard";
        }
            return "maestro"; //maestro is all 60-69 which is not something else, thats why this condition in the end

    }

    return "unknown"; //unknown for this system
}
Run Code Online (Sandbox Code Playgroud)


Usm*_*nas 20

  public string GetCreditCardType(string CreditCardNumber)
    {
        Regex regVisa = new Regex("^4[0-9]{12}(?:[0-9]{3})?$");
        Regex regMaster = new Regex("^5[1-5][0-9]{14}$");
        Regex regExpress = new Regex("^3[47][0-9]{13}$");
        Regex regDiners = new Regex("^3(?:0[0-5]|[68][0-9])[0-9]{11}$");
        Regex regDiscover = new Regex("^6(?:011|5[0-9]{2})[0-9]{12}$");
        Regex regJCB= new Regex("^(?:2131|1800|35\\d{3})\\d{11}$");


        if(regVisa.IsMatch(CreditCardNumber))
            return "VISA";
       else if (regMaster.IsMatch(CreditCardNumber))
            return "MASTER";
      else  if (regExpress.IsMatch(CreditCardNumber))
            return "AEXPRESS";
       else if (regDiners.IsMatch(CreditCardNumber))
            return "DINERS";
       else if (regDiscover.IsMatch(CreditCardNumber))
            return "DISCOVERS";
       else   if (regJCB.IsMatch(CreditCardNumber))
            return "JCB";
       else
        return "invalid";
    }
Run Code Online (Sandbox Code Playgroud)

以下是使用Regex检查信用卡类型的功能,c#


Ras*_*shy 19

看一下这个:

http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CC70060A01B

function isValidCreditCard(type, ccnum) {
/* Visa: length 16, prefix 4, dashes optional.
Mastercard: length 16, prefix 51-55, dashes optional.
Discover: length 16, prefix 6011, dashes optional.
American Express: length 15, prefix 34 or 37.
Diners: length 14, prefix 30, 36, or 38. */

  var re = new Regex({ "visa": "/^4\d{3}-?\d{4}-?\d{4}-?\d",
                       "mc": "/^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/",
                       "disc": "/^6011-?\d{4}-?\d{4}-?\d{4}$/",
                       "amex": "/^3[47]\d{13}$/",
                       "diners": "/^3[068]\d{12}$/"}[type.toLowerCase()])

   if (!re.test(ccnum)) return false;
   // Remove all dashes for the checksum checks to eliminate negative numbers
   ccnum = ccnum.split("-").join("");
   // Checksum ("Mod 10")
   // Add even digits in even length strings or odd digits in odd length strings.
   var checksum = 0;
   for (var i=(2-(ccnum.length % 2)); i<=ccnum.length; i+=2) {
      checksum += parseInt(ccnum.charAt(i-1));
   }
   // Analyze odd digits in even length strings or even digits in odd length strings.
   for (var i=(ccnum.length % 2) + 1; i<ccnum.length; i+=2) {
      var digit = parseInt(ccnum.charAt(i-1)) * 2;
      if (digit < 10) { checksum += digit; } else { checksum += (digit-9); }
   }
   if ((checksum % 10) == 0) return true; else return false;
}
Run Code Online (Sandbox Code Playgroud)


Fiv*_*ell 14

最近我需要这样的功能,我正在将Zend Framework信用卡验证器移植到ruby.ruby gem:https://github.com/Fivell/credit_card_validations zend framework:https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

他们都使用INN范围来检测类型.在这里你可以阅读INN

根据这个你可以检测信用卡(没有正则表达式,但声明有关前缀和可能的长度的一些规则)

所以我们对大多数使用的卡都有下一个规则

########  most used brands #########

    visa: [
        {length: [13, 16], prefixes: ['4']}
    ],
    mastercard: [
        {length: [16], prefixes: ['51', '52', '53', '54', '55']}
    ],

    amex: [
        {length: [15], prefixes: ['34', '37']}
    ],
    ######## other brands ########
    diners: [
        {length: [14], prefixes: ['300', '301', '302', '303', '304', '305', '36', '38']},
    ],

    #There are Diners Club (North America) cards that begin with 5. These are a joint venture between Diners Club and MasterCard, and are processed like a MasterCard
    # will be removed in next major version

    diners_us: [
        {length: [16], prefixes: ['54', '55']}
    ],

    discover: [
        {length: [16], prefixes: ['6011', '644', '645', '646', '647', '648',
                                  '649', '65']}
    ],

    jcb: [
        {length: [16], prefixes: ['3528', '3529', '353', '354', '355', '356', '357', '358', '1800', '2131']}
    ],


    laser: [
        {length: [16, 17, 18, 19], prefixes: ['6304', '6706', '6771']}
    ],

    solo: [
        {length: [16, 18, 19], prefixes: ['6334', '6767']}
    ],

    switch: [
        {length: [16, 18, 19], prefixes: ['633110', '633312', '633304', '633303', '633301', '633300']}

    ],

    maestro: [
        {length: [12, 13, 14, 15, 16, 17, 18, 19], prefixes: ['5010', '5011', '5012', '5013', '5014', '5015', '5016', '5017', '5018',
                                                              '502', '503', '504', '505', '506', '507', '508',
                                                              '6012', '6013', '6014', '6015', '6016', '6017', '6018', '6019',
                                                              '602', '603', '604', '605', '6060',
                                                              '677', '675', '674', '673', '672', '671', '670',
                                                              '6760', '6761', '6762', '6763', '6764', '6765', '6766', '6768', '6769']}
    ],

    # Luhn validation are skipped for union pay cards because they have unknown generation algoritm
    unionpay: [
        {length: [16, 17, 18, 19], prefixes: ['622', '624', '625', '626', '628'], skip_luhn: true}
    ],

    dankrot: [
        {length: [16], prefixes: ['5019']}
    ],

    rupay: [
        {length: [16], prefixes: ['6061', '6062', '6063', '6064', '6065', '6066', '6067', '6068', '6069', '607', '608'], skip_luhn: true}
    ]

}
Run Code Online (Sandbox Code Playgroud)

然后通过搜索前缀和比较长度,您可以检测信用卡品牌.另外不要忘记luhn algoritm(这里有http://en.wikipedia.org/wiki/Luhn).

  • 很有说服力.VISA卡长度可能是13位数. (2认同)

Sim*_*ver 13

这是codeProject上各种CC相关事物完整C#或VB代码.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

这篇文章已经发表了几年没有负面评论.

  • 链接坏了.也许这是同一个实用程序?http://www.codeproject.com/Articles/20271/Ultimate-NET-Credit-Card-Utility-Class (2认同)

Nic*_*ick 8

紧凑的JavaScript版本

    var getCardType = function (number) {
        var cards = {
            visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
            mastercard: /^5[1-5][0-9]{14}$/,
            amex: /^3[47][0-9]{13}$/,
            diners: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
            discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/,
            jcb: /^(?:2131|1800|35\d{3})\d{11}$/
        };
        for (var card in cards) {
            if (cards[card].test(number)) {
                return card;
            }
        }
    };
Run Code Online (Sandbox Code Playgroud)


ang*_*net 8

Anatoliy在PHP中的答案:

 public static function detectCardType($num)
 {
    $re = array(
        "visa"       => "/^4[0-9]{12}(?:[0-9]{3})?$/",
        "mastercard" => "/^5[1-5][0-9]{14}$/",
        "amex"       => "/^3[47][0-9]{13}$/",
        "discover"   => "/^6(?:011|5[0-9]{2})[0-9]{12}$/",
    );

    if (preg_match($re['visa'],$num))
    {
        return 'visa';
    }
    else if (preg_match($re['mastercard'],$num))
    {
        return 'mastercard';
    }
    else if (preg_match($re['amex'],$num))
    {
        return 'amex';
    }
    else if (preg_match($re['discover'],$num))
    {
        return 'discover';
    }
    else
    {
        return false;
    }
 }
Run Code Online (Sandbox Code Playgroud)


ism*_*ail 7

这是一个php类函数,由CCnumber返回CCtype.
此代码不验证卡或不运行Luhn算法只尝试根据此页面中的表查找信用卡类型.基本上使用CCnumber长度和CCcard前缀来确定CCcard类型.

    <?php class CreditcardType
    {
   public static $creditcardTypes = array(
            array('Name'=>'American Express','cardLength'=>array(15),'cardPrefix'=>array('34', '37'))
            ,array('Name'=>'Maestro','cardLength'=>array(12, 13, 14, 15, 16, 17, 18, 19),'cardPrefix'=>array('5018', '5020', '5038', '6304', '6759', '6761', '6763'))
            ,array('Name'=>'Mastercard','cardLength'=>array(16),'cardPrefix'=>array('51', '52', '53', '54', '55'))
            ,array('Name'=>'Visa','cardLength'=>array(13,16),'cardPrefix'=>array('4'))
            ,array('Name'=>'JCB','cardLength'=>array(16),'cardPrefix'=>array('3528', '3529', '353', '354', '355', '356', '357', '358'))
            ,array('Name'=>'Discover','cardLength'=>array(16),'cardPrefix'=>array('6011', '622126', '622127', '622128', '622129', '62213',
                                        '62214', '62215', '62216', '62217', '62218', '62219',
                                        '6222', '6223', '6224', '6225', '6226', '6227', '6228',
                                        '62290', '62291', '622920', '622921', '622922', '622923',
                                        '622924', '622925', '644', '645', '646', '647', '648',
                                        '649', '65'))
            ,array('Name'=>'Solo','cardLength'=>array(16, 18, 19),'cardPrefix'=>array('6334', '6767'))
            ,array('Name'=>'Unionpay','cardLength'=>array(16, 17, 18, 19),'cardPrefix'=>array('622126', '622127', '622128', '622129', '62213', '62214',
                                        '62215', '62216', '62217', '62218', '62219', '6222', '6223',
                                        '6224', '6225', '6226', '6227', '6228', '62290', '62291',
                                        '622920', '622921', '622922', '622923', '622924', '622925'))
            ,array('Name'=>'Diners Club','cardLength'=>array(14),'cardPrefix'=>array('300', '301', '302', '303', '304', '305', '36'))
            ,array('Name'=>'Diners Club US','cardLength'=>array(16),'cardPrefix'=>array('54', '55'))
            ,array('Name'=>'Diners Club Carte Blanche','cardLength'=>array(14),'cardPrefix'=>array('300','305'))
            ,array('Name'=>'Laser','cardLength'=>array(16, 17, 18, 19),'cardPrefix'=>array('6304', '6706', '6771', '6709'))
    );     
        private function __construct() {}    
        public static function getType($CCNumber)
        {
            $CCNumber= trim($CCNumber);
            $type='Unknown';
            foreach (CreditcardType::$creditcardTypes as $card){
                if (! in_array(strlen($CCNumber),$card['cardLength'])) {
                    continue;
                }
                $prefixes = '/^('.implode('|',$card['cardPrefix']).')/';            
                if(preg_match($prefixes,$CCNumber) == 1 ){
                    $type= $card['Name'];
                    break;
                }
            }
            return $type;
        }
    } ?>
Run Code Online (Sandbox Code Playgroud)


Sho*_*ban 6

信用卡的第一个数字可用于估算供应商:

  • 签证:49,44或47
  • 签证电子:42,45,48,49
  • 万事达卡:51
  • 美国运通:34
  • 用餐者:30,36,38
  • JCB:35


Gaj*_*jus 6

不要尝试检测信用卡类型作为处理付款的一部分.您有可能拒绝有效的交易.

如果您需要向支付处理器提供信息(例如,PayPal信用卡对象需要命名卡类型),请从可用的最少信息中猜测,例如

$credit_card['pan'] = preg_replace('/[^0-9]/', '', $credit_card['pan']);
$inn = (int) mb_substr($credit_card['pan'], 0, 2);

// @see http://en.wikipedia.org/wiki/List_of_Bank_Identification_Numbers#Overview
if ($inn >= 40 && $inn <= 49) {
    $type = 'visa';
} else if ($inn >= 51 && $inn <= 55) {
    $type = 'mastercard';
} else if ($inn >= 60 && $inn <= 65) {
    $type = 'discover';
} else if ($inn >= 34 && $inn <= 37) {
    $type = 'amex';
} else {
    throw new \UnexpectedValueException('Unsupported card type.');
}
Run Code Online (Sandbox Code Playgroud)

这种实现(仅使用前两位数字)足以识别所有主要(在PayPal的情况下所有支持的)卡方案.实际上,您可能希望完全跳过该异常并默认为最常用的卡类型.让支付网关/处理器告诉您是否存在响应您的请求的验证错误.

实际情况是,您的支付网关并不关心您提供的价值.

  • @EdDeGagne - "不关心什么价值"与"不关心传入"不一样. (3认同)

Mik*_*ger 6

在卡片范围识别(CRR)中,使用一系列正则表达式或其他硬编码范围的算法的缺点是BIN/IIN在我的经验中确实会随着时间的推移而发生变化.卡片的联合品牌是一个持续的复杂功能.不同的卡购买者/商家可能需要您以不同方式对待同一张卡,具体取决于例如地理位置.

此外,在过去几年中,例如银联卡在更广泛的流通中,现有的模型无法应对新的范围,有时会与更广泛的范围交错.
了解您的系统需要覆盖的地理位置可能有所帮助,因为某些范围仅限于在特定国家/地区使用.例如,范围62包括美国的一些AAA子范围,但如果您的商家基地位于美国境外,您可以将所有62个视为银联.
您可能还会被要求根据商家位置对卡进行不同的处理.例如,将某些英国卡片视为国内借记卡,但作为国际信用卡.

一个主要的收购银行维护着非常有用的规则.例如https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdfhttps://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf.(截至2017年6月的有效链接,这要归功于提供更新参考链接的用户.)但请注意,虽然这些CRR规则可能代表发卡领域,因为它适用于该实体获得的商家,它不包括例如标识为CUP/UPI的范围.

这些注释适用于磁条(MagStripe)或PKE(Pan Key Entry)场景.ICC/EMV世界的情况再次不同.

更新:此页面上的其他答案(以及链接的WikiPedia页面)JCB始终为16长.然而,在我的公司,我们有一个专门的工程师团队,他们在多个收单银行和地区认证我们的POS设备和软件.这支团队从JCB获得的最新认证证书包含19个长PAN的通行证.


Dai*_* R. 5

Swift 2.1版本的Usman Y的答案。使用打印语句进行验证,以便按某个字符串值进行调用

print(self.validateCardType(self.creditCardField.text!))

func validateCardType(testCard: String) -> String {

    let regVisa = "^4[0-9]{12}(?:[0-9]{3})?$"
    let regMaster = "^5[1-5][0-9]{14}$"
    let regExpress = "^3[47][0-9]{13}$"
    let regDiners = "^3(?:0[0-5]|[68][0-9])[0-9]{11}$"
    let regDiscover = "^6(?:011|5[0-9]{2})[0-9]{12}$"
    let regJCB = "^(?:2131|1800|35\\d{3})\\d{11}$"


    let regVisaTest = NSPredicate(format: "SELF MATCHES %@", regVisa)
    let regMasterTest = NSPredicate(format: "SELF MATCHES %@", regMaster)
    let regExpressTest = NSPredicate(format: "SELF MATCHES %@", regExpress)
    let regDinersTest = NSPredicate(format: "SELF MATCHES %@", regDiners)
    let regDiscoverTest = NSPredicate(format: "SELF MATCHES %@", regDiscover)
    let regJCBTest = NSPredicate(format: "SELF MATCHES %@", regJCB)


    if regVisaTest.evaluateWithObject(testCard){
        return "Visa"
    }
    else if regMasterTest.evaluateWithObject(testCard){
        return "MasterCard"
    }

    else if regExpressTest.evaluateWithObject(testCard){
        return "American Express"
    }

    else if regDinersTest.evaluateWithObject(testCard){
        return "Diners Club"
    }

    else if regDiscoverTest.evaluateWithObject(testCard){
        return "Discover"
    }

    else if regJCBTest.evaluateWithObject(testCard){
        return "JCB"
    }

    return ""

}
Run Code Online (Sandbox Code Playgroud)