Làm thế nào để bạn phát hiện loại thẻ tín dụng dựa trên số?


516

Tôi đang cố gắng tìm ra cách phát hiện loại thẻ tín dụng hoàn toàn dựa trên số của nó. Có ai biết một cách dứt khoát, đáng tin cậy để tìm thấy điều này?


3
Sử dụng một biểu thức thông thường. Kiểm tra liên kết này để biết thêm thông tin.
senfo

3
Các chi tiết đều có trên Wikipedia: en.wikipedia.org/wiki/Credit_card_numbers
Sten Vesterli

1
Có một bảng tóm tắt tốt trong Wikipedia, tại en.wikipedia.org/wiki/Credit_card_numbers . Đây là một đến sáu chữ số đầu tiên cho biết loại và tổ chức phát hành thẻ.
Alex

3
Tôi sẽ không sử dụng regex ngoài việc rút ra nhóm số đầu tiên, bạn thường có thể nói chỉ từ 4 số đầu tiên (ở Hoa Kỳ). Ngoài ra trước khi bận tâm thanh toán để xóa một khoản phí, hãy kiểm tra Mod 10 trên số thẻ để đảm bảo rằng nó có thể hợp pháp. Thuật toán Luhn
Dan Blair

3
bất cứ ai cũng có thể nhận xét nếu các thuật toán này tốt 'mọi lúc' - hoặc chúng có thay đổi theo định kỳ hay không, ví dụ như thuật toán 'tính toán nếu số điện thoại ở california'
Simon_Weaver

Câu trả lời:


772

Số thẻ tín dụng / thẻ ghi nợ được gọi là PAN hoặc Số tài khoản chính . Sáu chữ số đầu tiên của PAN được lấy từ IIN , hoặc Số nhận dạng nhà phát hành , thuộc ngân hàng phát hành (IIN trước đây được gọi là BIN - Số nhận dạng ngân hàng - vì vậy bạn có thể thấy các tham chiếu đến thuật ngữ đó trong một số tài liệu). Sáu chữ số này tuân theo tiêu chuẩn quốc tế, ISO / IEC 7812 và có thể được sử dụng để xác định loại thẻ từ số.

Thật không may, cơ sở dữ liệu ISO / IEC 7812 thực tế không có sẵn công khai, tuy nhiên, có những danh sách không chính thức, cả thương mại và miễn phí, kể cả trên Wikipedia .

Dù sao, để phát hiện loại từ số, bạn có thể sử dụng biểu thức chính quy như các biểu thức bên dưới: Tín dụng cho các biểu thức gốc

Visa: Số ^4[0-9]{6,}$ thẻ Visa bắt đầu bằng số 4.

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,}$ Trước năm 2016, số MasterCard bắt đầu bằng các số từ 51 đến 55, nhưng điều này sẽ chỉ phát hiện thẻ tín dụng MasterCard ; có những thẻ khác được phát hành bằng hệ thống MasterCard không thuộc phạm vi IIN này. Trong năm 2016, họ sẽ thêm số trong phạm vi (222100-272099).

American Express: ^3[47][0-9]{5,}$ Số thẻ American Express bắt đầu bằng 34 hoặc 37.

Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ Số thẻ Diners Club bắt đầu bằng 300 đến 305, 36 hoặc 38. Có thẻ Diners Club bắt đầu bằng 5 và có 16 chữ số. Đây là một liên doanh giữa Diners Club và MasterCard và nên được xử lý như MasterCard.

Khám phá: ^6(?:011|5[0-9]{2})[0-9]{3,}$ Khám phá số thẻ bắt đầu bằng 6011 hoặc 65.

JCB: ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ Thẻ JCB bắt đầu bằng 2131, 1800 hoặc 35.

Thật không may, có một số loại thẻ được xử lý với hệ thống MasterCard không nằm trong phạm vi IIN của MasterCard (số bắt đầu từ 51 ... 55); trường hợp quan trọng nhất là thẻ Maestro, nhiều thẻ được phát hành từ các phạm vi IIN của các ngân hàng khác và do đó được đặt trên khắp không gian số. Do đó, tốt nhất có thể giả định rằng bất kỳ thẻ nào không thuộc loại nào khác mà bạn chấp nhận phải là MasterCard .

Quan trọng : số thẻ có chiều dài khác nhau; chẳng hạn, Visa trước đây đã phát hành thẻ với PAN có 13 chữ số và thẻ có PAN 16 chữ số. Tài liệu của Visa hiện chỉ ra rằng nó có thể phát hành hoặc có thể đã ban hành các số có từ 12 đến 19 chữ số. Do đó, bạn không nên kiểm tra độ dài của số thẻ, ngoài việc xác minh rằng nó có ít nhất 7 chữ số (đối với IIN hoàn chỉnh cộng với một chữ số kiểm tra, phải khớp với giá trị được dự đoán bởi thuật toán Luhn ).

Một gợi ý nữa: trước khi xử lý PAN của chủ thẻ, hãy loại bỏ mọi ký tự khoảng trắng và dấu chấm câu khỏi đầu vào . Tại sao? Bởi vì việc nhập các chữ số theo nhóm thường dễ dàng hơn nhiều , tương tự như cách chúng được hiển thị ở mặt trước của thẻ tín dụng thực tế, nghĩa là

4444 4444 4444 4444

nhập chính xác dễ hơn nhiều

4444444444444444

Thực sự không có lợi ích gì trong việc trừng phạt người dùng vì họ đã nhập các ký tự mà bạn không mong đợi ở đây.

Điều này cũng ngụ ý đảm bảo rằng các trường nhập cảnh của bạn có chỗ cho ít nhất 24 ký tự, nếu không, người dùng vào không gian sẽ hết phòng. Tôi khuyên bạn nên làm cho trường đủ rộng để hiển thị 32 ký tự và cho phép tối đa 64; cung cấp nhiều khoảng trống để mở rộng.

Đây là một hình ảnh cung cấp một cái nhìn sâu sắc hơn một chút:

CẬP NHẬT (2014): Phương thức tổng kiểm tra dường như không còn là một cách hợp lệ để xác minh tính xác thực của thẻ như đã lưu ý trong các nhận xét về câu trả lời này.

CẬP NHẬT (2016): Mastercard là để triển khai các phạm vi BIN mới bắt đầu Ach Payment .

Xác minh thẻ tín dụng


7
ví dụ tuyệt vời Bạn có biểu thức thường xuyên cho thẻ maestro?
Manikandan

4
Không không không. Bạn không thể dựa vào độ dài của số thẻ; họ có thể thay đổi bất cứ lúc nào. Phần duy nhất của số thẻ bạn có thể dựa vào là IIN (thường được gọi là BIN) và là tiền tố của số. Ngoài ra, bạn không thể phát hiện thẻ Mastercard theo cách bạn đề xuất; sẽ chỉ nhận một tập hợp con các thẻ được xử lý thông qua hệ thống Mastercard (vấn đề chính là thẻ Maestro, có nhiều tiền tố IIN).
alastair

2
@alastair bạn đã đọc các biểu thức trước khi bình luận? Chúng được viết riêng để sử dụng IIN, vì vậy tôi không hiểu bạn đang cố nói gì. Hơn nữa, IIN có thể được sử dụng để xác định nhà phát hành thẻ, nhưng không xác thực. Ví dụ, 5412 không đại diện cho một MasterCard hoàn chỉnh, nhưng đề xuất của bạn sẽ ngụ ý rằng nó có. Tôi không tìm thấy bằng chứng nào cho thấy MasterCards là bất cứ thứ gì ngoài 16 chữ số. Xin vui lòng cung cấp một nguồn cho yêu cầu của bạn. Tuy nhiên, bạn đã đúng khi đề cập đến một bản cập nhật cần được thực hiện cho thẻ Maestro.
senfo

3
@senfo Bạn nói đúng, 5412 sẽ không phải là số Mastercard hoàn chỉnh. Các IIN dài sáu chữ số, vì vậy một số thẻ hoàn chỉnh phải có 7 chữ số (tối thiểu) và phải vượt qua kiểm tra Luhn. Không cần chứng minh trên mạng mà các số Mastercard có bất cứ thứ gì ngoài 16 chữ số; vấn đề là, bất kể tình huống hiện nay, trong tương lai, họ có thể phát hành thẻ có 17 hoặc 18 chữ số, hoặc đối với vấn đề đó với một số 15. Dựa vào chúng dài 16 chữ số là không cần thiết và tạo ra rủi ro bảo trì dài hạn.
alastair

3
Tôi thấy rất khó tin rằng một số thẻ hợp lệ sẽ không có chữ số kiểm tra chính xác theo thuật toán Luhn. Nó được sử dụng hoàn toàn ở mọi nơi để kiểm tra số thẻ chống lại lỗi chính tả đơn giản và các nỗ lực lừa đảo ngu ngốc. Thay vào đó, tôi đã quan sát thấy một số người khá thông minh chỉ đơn giản là không nắm bắt được thuật toán và họ chỉ tính toán sai.
Rennex

74

Trong 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
        }
    }
}

Bài kiểm tra đơn vị:

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]);
            });
        });
    });
});

1
@ jolly.exe - Fiddle của bạn trả về không xác định cho tất cả các bài kiểm tra. Không hoạt động :(
ShadowTreeDeveloper

@ShadeTreeDeveloper chỉ cần nhập bất kỳ giá trị nào, vd. 372176090165471 cho AMAX trong trường văn bản
Code Spy

@ jolly.exe Tôi thấy ... Tôi đã hy vọng một cái gì đó sẽ định dạng khi tôi gõ (tắt sự kiện keyup). Fiddle không hoạt động khi tôi nhập một số đầy đủ.
ShadowTreeDeveloper

Tôi đã kết thúc việc viết đoạn mã này để thực hiện định dạng và xác nhận đầu vào mà tôi muốn. quercusv.github.io/smartForm
ShadeTreeDeveloper

Bạn có biết cách phát hiện số thẻ v-pay và bancontact không? Cảm ơn
Oleksandr IY

38

Cập nhật: ngày 15 tháng 6 năm 2016 (như một giải pháp tối ưu hiện tại)

Xin lưu ý rằng tôi thậm chí bỏ phiếu cho người được bình chọn hàng đầu, nhưng để làm rõ đây là các biểu thức chính thực sự hoạt động tôi đã thử nghiệm nó với hàng ngàn mã BIN thực. Điều quan trọng nhất là sử dụng chuỗi bắt đầu (^) nếu không nó sẽ cho kết quả sai trong thế giới thực!

JCB ^(?:2131|1800|35)[0-9]{0,}$ Bắt đầu với: 2131, 1800, 35 (3528-3589)

American Express ^3[47][0-9]{0,}$ Bắt đầu với: 34, 37

Câu lạc bộ thực khách ^3(?:0[0-59]{1}|[689])[0-9]{0,}$ Bắt đầu với: 300-305, 309, 36, 38-39

Visa ^4[0-9]{0,}$ Bắt đầu với: 4

Thẻ MasterCard ^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$ Bắt đầu với: 2221-2720, 51-55

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro luôn phát triển trong phạm vi: 60-69 , bắt đầu bằng / không phải thứ gì khác, nhưng bắt đầu 5 phải được mã hóa dưới dạng thẻ mastercard. Thẻ Maestro phải được phát hiện ở cuối mã vì một số thẻ khác có trong khoảng 60-69. Hãy nhìn vào mã.

Khám phá Khám ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$ phá khá khó để viết mã, bắt đầu với: 6011, 622126-622925, 644-649, 65

Trong javascript tôi sử dụng chức năng này. Điều này là tốt khi bạn gán nó cho một sự kiện onkeyup và nó cho kết quả càng sớm càng tốt.

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;
}

Tại đây bạn có thể chơi với nó:

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

Đối với PHP sử dụng chức năng này, điều này cũng phát hiện một số thẻ VISA / MC phụ:

/**
  * Obtain a brand constant from a PAN
  *
  * @param string $pan               Credit card number
  * @param bool   $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
}

1
Và xin lưu ý rằng đây chỉ là phát hiện số CC và không xác thực. Đó là tách ra, nên là một kiểm tra Luhn ...
Janos Szabo

Visa Electron ở đâu và tại sao Maestro kiểm tra trả lại MasterCard trong một số trường hợp? MasterCard có nên tự kiểm tra không?
BadHorsie

Không thể nhận ra số kiểm tra JCB này là bất kỳ loại nào (3088514174175777) và xác định số kiểm tra này của JCB là dinftime club (3096278649822922). Giả sử danh sách số thẻ thử nghiệm này vẫn hợp lệ ( freeformatter.com/credit-card-number-generator-validator.html )
Drew

không có tài liệu nào bắt đầu từ 308 hoặc 309 có thể là thẻ JCB
Janos Szabo

+1 để cung cấp mã phát hiện loại cc, đó là những gì bạn thường muốn làm cho ux - regex cho phạm vi mới trên MC cần một tweek nhỏ: / ^ (5 [1-5] | 222 [1-9] | 22 [3-9] [0-9] | 2 [3-6] [0-9] {2} | 27 [01] [0-9] | 2720) [0-9] {0,} $ /
kinakuta

21
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";
}

Đây là chức năng kiểm tra loại thẻ tín dụng bằng Regex, c #


19

Kiểm tra này:

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;
}

15

Gần đây tôi cần chức năng như vậy, tôi đã chuyển Trình xác thực thẻ tín dụng Zend Framework sang ruby. đá quý ruby: https://github.com/Fivell/credit_card_validations zend framework: https://github.com/zendframework/zf2/blob/master/l Library / Zend / Valator / HolyitCard.php

Cả hai đều sử dụng phạm vi INN để phát hiện loại. Ở đây bạn có thể đọc về INN

Theo đó, bạn có thể phát hiện thẻ tín dụng thay thế (không có biểu thức chính quy, nhưng khai báo một số quy tắc về tiền tố và độ dài có thể)

Vì vậy, chúng tôi có các quy tắc tiếp theo cho hầu hết các thẻ được sử dụng

########  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}
    ]

}

Sau đó, bằng cách tìm kiếm tiền tố và so sánh độ dài, bạn có thể phát hiện thương hiệu thẻ tín dụng. Cũng đừng quên luhn algoritm (nó được giải thích ở đây http://en.wikipedia.org/wiki/Luhn ).

CẬP NHẬT

danh sách các quy tắc cập nhật có thể được tìm thấy ở đây https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml


2
Rất minh họa. Thẻ VISA có thể dài 13 chữ số.
Herman Kan

@HermanKan, không có trang web VISA nào nói nó phải dài 16, tôi nghĩ cách đây rất lâu có thể là 13, nhưng không phải bây giờ
Fivell

1
Tôi nghĩ đó là hỗ trợ di sản
Fivell

1
@HermanKan, có một điều nữa, VISA có thẻ VPay và tích hợp vào thương hiệu VPay của Visa có thể chỉ định độ dài PAN từ 13 đến 19 chữ số, do đó, số thẻ hơn 16 chữ số hiện đang được nhìn thấy.
Fivell

1
@Ethan, kiểm tra liên kết cuối cùng trong câu trả lời được cập nhật của tôi raw.githubusercontent.com/Fivell/credit_card_validations/master/ trộm
Fivell

13

Đây là mã C # hoặc VB hoàn chỉnh cho tất cả các loại điều liên quan đến CC trên bảng mã.

  • Số điện thoại
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassLuhnTest

Bài viết này đã được một vài năm không có bình luận tiêu cực.


1
@barett - Đã sửa nó. có vẻ như họ đã chuyển nó từ danh mục 'aspnet' sang danh mục 'xác thực' đã thay đổi liên kết
Simon_Weaver

2
Liên kết bị hỏng. Có lẽ đây là tiện ích tương tự? codeproject.com/Articles/20271/ Mạnh
Josh Noe

Mã codeproject đó là từ năm 2007 Cảnh báo, Nó có thể bị lỗi thời.
aron

8

Phiên bản javascript nhỏ gọn

    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;
            }
        }
    };

8

Câu trả lời của Anatoliy trong 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;
    }
 }

7

Đây là một hàm lớp php trả về CCtype bởi CCnumber.
Mã này không xác thực thẻ hoặc không chạy thuật toán Luhn chỉ cố gắng tìm loại thẻ tín dụng dựa trên bảng trong trang này . về cơ bản sử dụng chiều dài CCnumber và tiền tố CCcard để xác định loại CCcard.

<?php
class CreditcardType
{
    public static $creditcardTypes = [
        [
            'Name' => 'American Express',
            'cardLength' => [15],
            'cardPrefix' => ['34', '37'],
        ], [
            'Name' => 'Maestro',
            'cardLength' => [12, 13, 14, 15, 16, 17, 18, 19],
            'cardPrefix' => ['5018', '5020', '5038', '6304', '6759', '6761', '6763'],
        ], [
            'Name' => 'Mastercard',
            'cardLength' => [16],
            'cardPrefix' => ['51', '52', '53', '54', '55'],
        ], [
            'Name' => 'Visa',
            'cardLength' => [13, 16],
            'cardPrefix' => ['4'],
        ], [
            'Name' => 'JCB',
            'cardLength' => [16],
            'cardPrefix' => ['3528', '3529', '353', '354', '355', '356', '357', '358'],
        ], [
            'Name' => 'Discover',
            'cardLength' => [16],
            'cardPrefix' => ['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'],
        ], [
            'Name' => 'Solo',
            'cardLength' => [16, 18, 19],
            'cardPrefix' => ['6334', '6767'],
        ], [
            'Name' => 'Unionpay',
            'cardLength' => [16, 17, 18, 19],
            'cardPrefix' => ['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'],
        ], [
            'Name' => 'Diners Club',
            'cardLength' => [14],
            'cardPrefix' => ['300', '301', '302', '303', '304', '305', '36'],
        ], [
            'Name' => 'Diners Club US',
            'cardLength' => [16],
            'cardPrefix' => ['54', '55'],
        ], [
            'Name' => 'Diners Club Carte Blanche',
            'cardLength' => [14],
            'cardPrefix' => ['300', '305'],
        ], [
            'Name' => 'Laser',
            'cardLength' => [16, 17, 18, 19],
            'cardPrefix' => ['6304', '6706', '6771', '6709'],
        ],
    ];

    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;
    }
}

6

Đừng cố gắng phát hiện loại thẻ tín dụng như là một phần của việc xử lý thanh toán. Bạn đang có nguy cơ từ chối các giao dịch hợp lệ.

Nếu bạn cần cung cấp thông tin cho bộ xử lý thanh toán của mình (ví dụ: đối tượng thẻ tín dụng PayPal yêu cầu đặt tên loại thẻ ), thì hãy đoán nó từ thông tin ít nhất có sẵn, ví dụ:

$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.');
}

Việc triển khai này (chỉ sử dụng hai chữ số đầu tiên) là đủ để xác định tất cả các lược đồ thẻ chính (và trong trường hợp của PayPal là tất cả các lược đồ thẻ được hỗ trợ). Trong thực tế, bạn có thể muốn bỏ qua ngoại lệ hoàn toàn và mặc định cho loại thẻ phổ biến nhất. Hãy để cổng thanh toán / bộ xử lý cho bạn biết nếu có lỗi xác thực đáp ứng yêu cầu của bạn.

Thực tế là cổng thanh toán của bạn không quan tâm đến giá trị bạn cung cấp .


1
Điều này chỉ đơn giản là không đúng sự thật. Tôi biết 3 nhà cung cấp khác nhau yêu cầu các loại thẻ được chuyển qua và nếu bạn không chuyển nó vào, giao dịch sẽ thất bại.
Ed DeGagne

3
@EdDeGagne - "không quan tâm giá trị nào" không giống như "không quan tâm nếu được thông qua".
Quentin Skousen

Tôi đã chỉ định ở đâu? Tôi chỉ đơn giản đề cập rằng có những nhà cung cấp đang sử dụng yêu cầu BẠN phải vượt qua trong loại CC, không có gì hơn.
Ed DeGagne

bạn không thể đơn giản hóa vấn đề phức tạp này, nhưng thông thường các nhà cung cấp thanh toán không yêu cầu bạn đề xuất loại thẻ, họ có phương pháp riêng để phát hiện
Janos Szabo

6

Các số đầu tiên của thẻ tín dụng có thể được sử dụng để ước tính nhà cung cấp:

  • Visa: 49,44 hoặc 47
  • Visa điện tử: 42, 45, 48, 49
  • Thẻ tín dụng: 51
  • Amex: 34
  • Thực khách: 30, 36, 38
  • JCB: 35

Các phạm vi này đã được cập nhật chủ yếu, các công ty bán thẻ đã thêm cách nhiều phạm vi hơn được đề cập trong bài.
NJInamdar

6

Trong Nhận dạng phạm vi thẻ (CRR), một nhược điểm với các thuật toán sử dụng một loạt biểu thức chính quy hoặc các phạm vi được mã hóa cứng khác, đó là các BIN / IIN thay đổi theo thời gian theo kinh nghiệm của tôi. Việc hợp tác xây dựng thương hiệu thẻ là một sự phức tạp đang diễn ra. Những người mua / người bán thẻ khác nhau có thể cần bạn đối xử với cùng một loại thẻ khác nhau, tùy thuộc vào vị trí địa lý.

Ngoài ra, trong vài năm gần đây, ví dụ như thẻ UnionPay được lưu hành rộng hơn, các mô hình hiện tại không đối phó với các phạm vi mới đôi khi xen kẽ với các phạm vi rộng hơn mà chúng thay thế.
Biết địa lý mà hệ thống của bạn cần bao quát có thể giúp ích, vì một số phạm vi bị hạn chế sử dụng ở các quốc gia cụ thể. Ví dụ: phạm vi 62 bao gồm một số phạm vi phụ AAA ở Hoa Kỳ, nhưng nếu cơ sở thương mại của bạn ở bên ngoài Hoa Kỳ, bạn có thể coi tất cả 62 là UnionPay.
Bạn cũng có thể được yêu cầu đối xử với một thẻ khác nhau dựa trên vị trí thương gia. Ví dụ: coi một số thẻ của Vương quốc Anh là ghi nợ trong nước, nhưng là tín dụng quốc tế.

Có một bộ quy tắc rất hữu ích được duy trì bởi một Ngân hàng Mua lại lớn. Ví dụ: https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdfhttps://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf . (Liên kết hợp lệ kể từ tháng 6 năm 2017, nhờ người dùng đã cung cấp liên kết đến tài liệu tham khảo được cập nhật.) nó không bao gồm các phạm vi được xác định là CUP / UPI.

Những nhận xét này áp dụng cho các tình huống sọc từ (MagStripe) hoặc PKE (Pan Key Entry). Tình hình lại khác trong thế giới ICC / EMV.

Cập nhật: Các câu trả lời khác trên trang này (và cả trang WikiPedia được liên kết) có JCB luôn luôn dài 16. Tuy nhiên, trong công ty của tôi, chúng tôi có một đội ngũ kỹ sư chuyên dụng chứng nhận các thiết bị và phần mềm POS của chúng tôi trên nhiều ngân hàng và khu vực địa lý. Gói chứng nhận gần đây nhất của nhóm này có từ JCB, đã có một trường hợp vượt qua cho một PAN dài 19.


Xin chào @CaiqueOliveira, xem các liên kết được cập nhật. Cảm ơn mac9416, người đã cung cấp liên kết đến tài liệu tham khảo Quy tắc BIN được cập nhật.
MikeRoger

1
Cảm ơn @ mac9416, vì đã tham khảo quy tắc BIN-Rules được cập nhật.
MikeRoger

5

Phiên bản Swift 2.1 của câu trả lời của Usman Y. Sử dụng một câu lệnh in để xác minh để gọi theo một số giá trị chuỗi

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 ""

}

4

Stripe đã cung cấp thư viện javascript tuyệt vời này để phát hiện sơ đồ thẻ. Hãy để tôi thêm một vài đoạn mã và chỉ cho bạn cách sử dụng nó.

Trước hết, hãy đưa nó vào trang web của bạn dưới dạng

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.payment/1.2.3/jquery.payment.js " ></script>

Thứ hai sử dụng chức năng cardType để phát hiện sơ đồ thẻ.

$(document).ready(function() {              
            var type = $.payment.cardType("4242 4242 4242 4242"); //test card number
            console.log(type);                                   
}); 

Dưới đây là các liên kết tham khảo cho nhiều ví dụ và bản demo.

  1. Blog sọc cho jquery.payment.js
  2. Kho lưu trữ Github

4

Trong swift, bạn có thể tạo một enum để phát hiện loại thẻ tín dụng.

enum CreditCardType: Int { // Enum which encapsulates different card types and method to find the type of card.

case Visa
case Master
case Amex
case Discover

func validationRegex() -> String {
    var regex = ""
    switch self {
    case .Visa:
        regex = "^4[0-9]{6,}$"

    case .Master:
        regex = "^5[1-5][0-9]{5,}$"

    case .Amex:
        regex = "^3[47][0-9]{13}$"

    case .Discover:
        regex = "^6(?:011|5[0-9]{2})[0-9]{12}$"
    }

    return regex
}

func validate(cardNumber: String) -> Bool {
    let predicate = NSPredicate(format: "SELF MATCHES %@", validationRegex())
    return predicate.evaluateWithObject(cardNumber)
}

// Method returns the credit card type for given card number
static func cardTypeForCreditCardNumber(cardNumber: String) -> CreditCardType?  {
    var creditCardType: CreditCardType?

    var index = 0
    while let cardType = CreditCardType(rawValue: index) {
        if cardType.validate(cardNumber) {
            creditCardType = cardType
            break
        } else {
            index++
        }
    }
    return creditCardType
  }
}

Gọi phương thức CreditCardType.cardTypeForCreditCardNumber ("# số thẻ") để trả về giá trị enum của CreditCardType.


3

Giải pháp của tôi với jQuery:

function detectCreditCardType() {
    var type = new Array;
    type[1] = '^4[0-9]{12}(?:[0-9]{3})?$';      // visa
    type[2] = '^5[1-5][0-9]{14}$';              // mastercard
    type[3] = '^6(?:011|5[0-9]{2})[0-9]{12}$';  // discover
    type[4] = '^3[47][0-9]{13}$';               // amex

    var ccnum = $('.creditcard').val().replace(/[^\d.]/g, '');
    var returntype = 0;

    $.each(type, function(idx, re) {
        var regex = new RegExp(re);
        if(regex.test(ccnum) && idx>0) {
            returntype = idx;
        }
    });

    return returntype;
}

Trong trường hợp 0 ​​được trả về, loại thẻ tín dụng không bị phát hiện.

Lớp "thẻ tín dụng" nên được thêm vào trường nhập thẻ tín dụng.


1
Sự thay đổi của các câu trả lời hiện có.
Gajus

1
Có, tôi đã sử dụng mã từ các câu trả lời ở trên, CẢI THIỆN nó và đăng nó ở đây. Cảm ơn vì đã tải xuống ...
ZurabWeb

3
Bạn nên (a) đề nghị đây là một cải tiến cho mã hiện có, (b) viết các đóng góp thích hợp hoặc (c) tham chiếu các nguồn mà bạn đã sử dụng để viết các biểu thức chính quy.
Gajus

1
Gajus, tôi tin rằng tôi đã giúp cộng đồng theo cách mà tôi có thể tại thời điểm đó, làm ơn đừng nói với tôi rằng tôi nên làm gì đó cho ai đó. Tôi đã làm những gì tôi có thể hữu ích.
ZurabWeb

3

Tôi đã tìm kiếm xung quanh khá nhiều để định dạng thẻ tín dụng và định dạng số điện thoại. Tìm thấy rất nhiều lời khuyên hay nhưng không có gì thực sự phù hợp với mong muốn chính xác của tôi nên tôi đã tạo ra đoạn mã này . Bạn sử dụng nó như thế này:

var sf = smartForm.formatCC(myInputString);
var cardType = sf.cardType;

2
// abobjects.com, parvez ahmad ab bulk mailer
use below script

function isValidCreditCard2(type, ccnum) {
       if (type == "Visa") {
          // Visa: length 16, prefix 4, dashes optional.
          var re = /^4\d{3}?\d{4}?\d{4}?\d{4}$/;
       } else if (type == "MasterCard") {
          // Mastercard: length 16, prefix 51-55, dashes optional.
          var re = /^5[1-5]\d{2}?\d{4}?\d{4}?\d{4}$/;
       } else if (type == "Discover") {
          // Discover: length 16, prefix 6011, dashes optional.
          var re = /^6011?\d{4}?\d{4}?\d{4}$/;
       } else if (type == "AmEx") {
          // American Express: length 15, prefix 34 or 37.
          var re = /^3[4,7]\d{13}$/;
       } else if (type == "Diners") {
          // Diners: length 14, prefix 30, 36, or 38.
          var re = /^3[0,6,8]\d{12}$/;
       }
       if (!re.test(ccnum)) return false;
       return true;
       /*
       // 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;
       */

    }
jQuery.validator.addMethod("isValidCreditCard", function(postalcode, element) { 
    return isValidCreditCard2($("#cardType").val(), $("#cardNum").val()); 

}, "<br>credit card is invalid");


     Type</td>
                                          <td class="text">&nbsp; <form:select path="cardType" cssclass="fields" style="border: 1px solid #D5D5D5;padding: 0px 0px 0px 0px;width: 130px;height: 22px;">
                                              <option value="SELECT">SELECT</option>
                                              <option value="MasterCard">Mastercard</option>
                                              <option value="Visa">Visa</option>
                                               <option value="AmEx">American Express</option>
                                              <option value="Discover">Discover</option>
                                            </form:select> <font color="#FF0000">*</font> 

$("#signupForm").validate({

    rules:{
       companyName:{required: true},
       address1:{required: true},
       city:{required: true},
       state:{required: true},
       zip:{required: true},
       country:{required: true},
       chkAgree:{required: true},
       confPassword:{required: true},
       lastName:{required: true},
       firstName:{required: true},
       ccAddress1:{required: true},
       ccZip:{         
           postalcode : true
       },
       phone:{required: true},
       email:{
           required: true,
           email: true
           },
       userName:{
           required: true,
           minlength: 6
           },
       password:{
           required: true,
           minlength: 6
           },          
       cardNum:{           
            isValidCreditCard : true
       },

Câu hỏi là về thuật toán để kiểm tra thẻ tín dụng, không phải là một triển khai cụ thể. Mã này làm gì?
Emil Vikström

2

Chỉ cần một thìa nhỏ cho ăn:

$("#CreditCardNumber").focusout(function () {


        var regVisa = /^4[0-9]{12}(?:[0-9]{3})?$/;
        var regMasterCard = /^5[1-5][0-9]{14}$/;
        var regAmex = /^3[47][0-9]{13}$/;
        var regDiscover = /^6(?:011|5[0-9]{2})[0-9]{12}$/;

        if (regVisa.test($(this).val())) {
            $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/visa.png")'>");          

        }

        else if (regMasterCard.test($(this).val())) {
        $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/mastercard.png")'>");

        }

        else if (regAmex.test($(this).val())) {

           $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/amex.png")'>");

        }
         else if (regDiscover.test($(this).val())) {

           $("#CCImage").html("<img height='40px' src='@Url.Content("~/images/discover.png")'>");

        }
        else {
        $("#CCImage").html("NA");

        }

    });

2

Dưới đây là một ví dụ về một số hàm boolean được viết bằng Python trả về Truenếu thẻ được phát hiện theo tên hàm.

def is_american_express(cc_number):
    """Checks if the card is an american express. If us billing address country code, & is_amex, use vpos
    https://en.wikipedia.org/wiki/Bank_card_number#cite_note-GenCardFeatures-3
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^3[47][0-9]{13}$', cc_number))


def is_visa(cc_number):
    """Checks if the card is a visa, begins with 4 and 12 or 15 additional digits.
    :param cc_number: unicode card number
    """

    # Standard Visa is 13 or 16, debit can be 19
    if bool(re.match(r'^4', cc_number)) and len(cc_number) in [13, 16, 19]:
        return True

    return False


def is_mastercard(cc_number):
    """Checks if the card is a mastercard. Begins with 51-55 or 2221-2720 and 16 in length.
    :param cc_number: unicode card number
    """
    if len(cc_number) == 16 and cc_number.isdigit():  # Check digit, before cast to int
        return bool(re.match(r'^5[1-5]', cc_number)) or int(cc_number[:4]) in range(2221, 2721)
    return False


def is_discover(cc_number):
    """Checks if the card is discover, re would be too hard to maintain. Not a supported card.
    :param cc_number: unicode card number
    """
    if len(cc_number) == 16:
        try:
            # return bool(cc_number[:4] == '6011' or cc_number[:2] == '65' or cc_number[:6] in range(622126, 622926))
            return bool(cc_number[:4] == '6011' or cc_number[:2] == '65' or 622126 <= int(cc_number[:6]) <= 622925)
        except ValueError:
            return False
    return False


def is_jcb(cc_number):
    """Checks if the card is a jcb. Not a supported card.
    :param cc_number: unicode card number
    """
    # return bool(re.match(r'^(?:2131|1800|35\d{3})\d{11}$', cc_number))  # wikipedia
    return bool(re.match(r'^35(2[89]|[3-8][0-9])[0-9]{12}$', cc_number))  # PawelDecowski


def is_diners_club(cc_number):
    """Checks if the card is a diners club. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^3(?:0[0-6]|[68][0-9])[0-9]{11}$', cc_number))  # 0-5 = carte blance, 6 = international


def is_laser(cc_number):
    """Checks if the card is laser. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^(6304|670[69]|6771)', cc_number))


def is_maestro(cc_number):
    """Checks if the card is maestro. Not a supported card.
    :param cc_number: unicode card number
    """
    possible_lengths = [12, 13, 14, 15, 16, 17, 18, 19]
    return bool(re.match(r'^(50|5[6-9]|6[0-9])', cc_number)) and len(cc_number) in possible_lengths


# Child cards

def is_visa_electron(cc_number):
    """Child of visa. Checks if the card is a visa electron. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^(4026|417500|4508|4844|491(3|7))', cc_number)) and len(cc_number) == 16


def is_total_rewards_visa(cc_number):
    """Child of visa. Checks if the card is a Total Rewards Visa. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^41277777[0-9]{8}$', cc_number))


def is_diners_club_carte_blanche(cc_number):
    """Child card of diners. Checks if the card is a diners club carte blance. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^30[0-5][0-9]{11}$', cc_number))  # github PawelDecowski, jquery-creditcardvalidator


def is_diners_club_carte_international(cc_number):
    """Child card of diners. Checks if the card is a diners club international. Not a supported card.
    :param cc_number: unicode card number
    """
    return bool(re.match(r'^36[0-9]{12}$', cc_number))  # jquery-creditcardvalidator

1

Sáu chữ số đầu tiên của một số thẻ (bao gồm cả chữ số MII ban đầu) được gọi là số nhận dạng nhà phát hành (IIN). Chúng xác định tổ chức phát hành thẻ đã cấp thẻ cho chủ thẻ. Phần còn lại của số được phân bổ bởi tổ chức phát hành thẻ. Độ dài của số thẻ là số chữ số của nó. Nhiều tổ chức phát hành thẻ in toàn bộ IIN và số tài khoản trên thẻ của họ.

Dựa trên các sự kiện trên, tôi muốn giữ một đoạn mã JAVA để xác định thương hiệu thẻ.

Các loại thẻ mẫu

public static final String AMERICAN_EXPRESS = "American Express";
public static final String DISCOVER = "Discover";
public static final String JCB = "JCB";
public static final String DINERS_CLUB = "Diners Club";
public static final String VISA = "Visa";
public static final String MASTERCARD = "MasterCard";
public static final String UNKNOWN = "Unknown";

Tiền tố thẻ

// Based on http://en.wikipedia.org/wiki/Bank_card_number#Issuer_identification_number_.28IIN.29
public static final String[] PREFIXES_AMERICAN_EXPRESS = {"34", "37"};
public static final String[] PREFIXES_DISCOVER = {"60", "62", "64", "65"};
public static final String[] PREFIXES_JCB = {"35"};
public static final String[] PREFIXES_DINERS_CLUB = {"300", "301", "302", "303", "304", "305", "309", "36", "38", "39"};
public static final String[] PREFIXES_VISA = {"4"};
public static final String[] PREFIXES_MASTERCARD = {
        "2221", "2222", "2223", "2224", "2225", "2226", "2227", "2228", "2229",
        "223", "224", "225", "226", "227", "228", "229",
        "23", "24", "25", "26",
        "270", "271", "2720",
        "50", "51", "52", "53", "54", "55"
    };

Kiểm tra xem số đầu vào có bất kỳ tiền tố nào không.

public String getBrand(String number) {

String evaluatedType;
if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_AMERICAN_EXPRESS)) {
    evaluatedType = AMERICAN_EXPRESS;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_DISCOVER)) {
    evaluatedType = DISCOVER;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_JCB)) {
    evaluatedType = JCB;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_DINERS_CLUB)) {
    evaluatedType = DINERS_CLUB;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_VISA)) {
    evaluatedType = VISA;
} else if (StripeTextUtils.hasAnyPrefix(number, PREFIXES_MASTERCARD)) {
    evaluatedType = MASTERCARD;
} else {
    evaluatedType = UNKNOWN;
}
    return evaluatedType;
}

Cuối cùng, phương thức Utility

/**
  * Check to see if the input number has any of the given prefixes.
  *
  * @param number the number to test
  * @param prefixes the prefixes to test against
  * @return {@code true} if number begins with any of the input prefixes
*/

public static boolean hasAnyPrefix(String number, String... prefixes) {
  if (number == null) {
       return false;
  }
   for (String prefix : prefixes) {
       if (number.startsWith(prefix)) {
       return true;
    }
  }
     return false;
}

Tài liệu tham khảo


1

Hãy thử điều này cho kotlin. Thêm Regex và thêm vào câu lệnh khi.

private fun getCardType(number: String): String {

        val visa = Regex("^4[0-9]{12}(?:[0-9]{3})?$")
        val mastercard = Regex("^5[1-5][0-9]{14}$")
        val amx = Regex("^3[47][0-9]{13}$")

        return when {
            visa.matches(number) -> "Visa"
            mastercard.matches(number) -> "Mastercard"
            amx.matches(number) -> "American Express"
            else -> "Unknown"
        }
    }

0

Các quy tắc biểu thức chính quy phù hợp với các nhà cung cấp thẻ tương ứng :

  • (4\d{12}(?:\d{3})?) cho VISA.
  • (5[1-5]\d{14}) đối với thẻ MasterCard.
  • (3[47]\d{13}) cho AMEX.
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) cho Maestro.
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) cho câu lạc bộ thực khách.
  • (6(?:011|5[0-9]{2})[0-9]{12}) để khám phá
  • (35[2-8][89]\d\d\d{10}) cho JCB.

Tôi nghĩ rằng regex cho JCB là không chính xác. Tất cả bốn chữ số đầu tiên trong khoảng từ 3528 đến 3589 phải được chấp nhận, nhưng 3570 thì không.
Gabe

0

Tôi sử dụng https://github.com/bendrucker/creditcards-types/ để phát hiện loại thẻ tín dụng từ số. Một vấn đề tôi gặp phải là khám phá số kiểm tra 6011 1111 1111 1117

từ https://www.cybersource.com/developers/other_resource/quick_Vferences/test_cc_numbers/ chúng ta có thể thấy đó là một số khám phá vì nó bắt đầu từ 6011. Nhưng kết quả tôi nhận được từ các loại thẻ tín dụng là "Maestro". Tôi đã mở vấn đề cho tác giả. Anh ấy đã trả lời tôi rất sớm và cung cấp tài liệu pdf này https://www.discbadetwork.com/doads/IPP_VAR_Compliance.pdf Từ tài liệu chúng tôi có thể thấy rõ rằng 6011 1111 1111 1117 không rơi vào phạm vi khám phá thẻ tín dụng.


Tôi có cùng một vấn đề, bạn đã sửa nó chưa?
lucasvm1980

@ lucasvm1980 Tôi nghĩ rằng tệp pdf Discocateetwork.com đáng tin cậy hơn. Và số 6011 1111 1111 1117 chỉ là số thử nghiệm, không có thẻ tín dụng thực sự có số này. Vì vậy, tôi nghĩ rằng không cần phải lo lắng về điều này.
yuxiaomin

Có vẻ như có một số lỗi với một số thẻ Discover, tôi đã thử số hợp lệ và tôi cũng nhận được lỗi đó.
lucasvm1980

@ lucasvm1980 bạn có thể cung cấp số điện thoại và gửi một vấn đề trên github không?
yuxiaomin

0

Hãy thử điều này. Cho nhanh chóng.

func checkCardValidation(number : String) -> Bool
{
    let reversedInts = number.characters.reversed().map { Int(String($0)) }
        return reversedInts.enumerated().reduce(0, {(sum, val) in
            let odd = val.offset % 2 == 1
            return sum + (odd ? (val.element! == 9 ? 9 : (val.element! * 2) % 9) : val.element!)
        }) % 10 == 0
}

Sử dụng.

if (self.checkCardValidation(number: "yourNumber") == true) {
     print("Card Number valid")
}else{
     print("Card Number not valid")
}

0
follow Luhn’s algorithm

 private  boolean validateCreditCardNumber(String str) {

        int[] ints = new int[str.length()];
        for (int i = 0; i < str.length(); i++) {
            ints[i] = Integer.parseInt(str.substring(i, i + 1));
        }
        for (int i = ints.length - 2; i >= 0; i = i - 2) {
            int j = ints[i];
            j = j * 2;
            if (j > 9) {
                j = j % 10 + 1;
            }
            ints[i] = j;
        }
        int sum = 0;
        for (int i = 0; i < ints.length; i++) {
            sum += ints[i];
        }
        if (sum % 10 == 0) {
           return true;
        } else {
            return false;
        }


    }

then call this method

Edittext mCreditCardNumberEt;

 mCreditCardNumberEt.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

             int cardcount=   s.toString().length();
                 if(cardcount>=16) {
                    boolean cardnumbervalid=   validateCreditCardNumber(s.toString());
                    if(cardnumbervalid) {
                        cardvalidtesting.setText("Valid Card");
                        cardvalidtesting.setTextColor(ContextCompat.getColor(context,R.color.green));
                    }
                    else {
                        cardvalidtesting.setText("Invalid Card");
                        cardvalidtesting.setTextColor(ContextCompat.getColor(context,R.color.red));
                    }
                }
               else if(cardcount>0 &&cardcount<16) {
                     cardvalidtesting.setText("Invalid Card");
                     cardvalidtesting.setTextColor(ContextCompat.getColor(context,R.color.red));
                }

                else {
                    cardvalidtesting.setText("");

                }


                }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.