คุณตรวจจับประเภทบัตรเครดิตตามหมายเลขได้อย่างไร


516

ฉันกำลังพยายามหาวิธีตรวจสอบประเภทของบัตรเครดิตตามหมายเลขอย่างหมดจด ไม่มีใครรู้วิธีที่ชัดเจนและเชื่อถือได้ในการค้นหาสิ่งนี้?


3
ใช้การแสดงออกปกติ ลองดูที่ลิงค์นี้สำหรับข้อมูลเพิ่มเติม
senfo

3
รายละเอียดทั้งหมดอยู่ในวิกิพีเดีย: en.wikipedia.org/wiki/Credit_card_numbers
Sten Vesterli

1
มีตารางสรุปที่ดีในวิกิพีเดียที่en.wikipedia.org/wiki/Credit_card_numbers มันเป็นตัวเลขแรกถึงหกหลักที่บอกประเภทและผู้ออกบัตร
อเล็กซ์

3
ฉันจะไม่ใช้ regex นอกเหนือจากการดึงกลุ่มตัวเลขกลุ่มแรกออกมาโดยทั่วไปคุณสามารถบอกได้จากตัวเลข 4 ตัวแรกเท่านั้น (ในสหรัฐอเมริกา) นอกจากนี้ก่อนที่จะรบกวนการชำระค่าใช้จ่ายให้ดำเนินการตรวจสอบ Mod 10 บนหมายเลขบัตรเพื่อให้แน่ใจว่าอาจถูกต้องตามกฎหมาย อัลกอริทึม Luhn
Dan Blair

3
ยังทุกคนสามารถแสดงความคิดเห็นถ้าขั้นตอนวิธีการเหล่านี้เป็นสิ่งที่ดี 'ตลอดเวลา' - หรือว่าพวกเขาเป็นระยะ ๆ การเปลี่ยนแปลงเช่นตัวอย่างเช่นอัลกอริทึมสำหรับ 'การคำนวณหากหมายเลขโทรศัพท์ที่อยู่ในรัฐแคลิฟอร์เนีย
Simon_Weaver

คำตอบ:


772

หมายเลขบัตรเครดิต / บัตรเดบิตจะเรียกว่าเป็นแพนหรือเลขที่บัญชีหลัก หกหลักแรกของ PAN ถูกนำมาจากIINหรือหมายเลขประจำตัวผู้ออกซึ่งเป็นของธนาคารผู้ออก (ก่อนหน้านี้ IIN นั้นรู้จักกันในชื่อ BIN - หมายเลขประจำตัวธนาคาร - ดังนั้นคุณอาจเห็นการอ้างอิงถึงคำศัพท์นั้นในเอกสารบางฉบับ) ตัวเลขหกหลักเหล่านี้ขึ้นอยู่กับมาตรฐานสากล ISO / IEC 7812และสามารถใช้เพื่อกำหนดประเภทของการ์ดจากหมายเลข

แต่น่าเสียดายที่เกิดขึ้นจริงมาตรฐาน ISO / IEC 7812 ฐานข้อมูลไม่สามารถใช้ได้ต่อสาธารณชน แต่มีรายชื่ออย่างไม่เป็นทางการทั้งในเชิงพาณิชย์และฟรีรวมทั้งวิกิพีเดีย

อย่างไรก็ตามในการตรวจจับประเภทจากหมายเลขคุณสามารถใช้นิพจน์ทั่วไปเช่นเดียวกับที่อยู่ด้านล่าง: เครดิตสำหรับนิพจน์ดั้งเดิม

Visa: ^4[0-9]{6,}$หมายเลขบัตรวีซ่าเริ่มต้นด้วย 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 หมายเลข MasterCard เริ่มต้นด้วยหมายเลข 51 ถึง 55 แต่จะตรวจจับเฉพาะบัตรเครดิต MasterCardเท่านั้น มีการ์ดอื่น ๆ ที่ออกโดยใช้ระบบ MasterCard ที่ไม่ตกอยู่ในช่วง IIN นี้ ในปี 2559 พวกเขาจะเพิ่มตัวเลขในช่วง (222100-272099)

American Express: ^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

น่าเสียดายที่มีบัตรหลายประเภทที่ประมวลผลด้วยระบบ MasterCard ที่ไม่ได้อยู่ในช่วง IIN ของ MasterCard (หมายเลขเริ่มต้นที่ 51 ... 55) กรณีที่สำคัญที่สุดคือบัตร Maestro ซึ่งส่วนใหญ่ออกมาจากบัตร IIN ของธนาคารอื่นและอยู่ทั่วพื้นที่หมายเลข ผลที่ตามมา,มันอาจจะดีที่สุดที่จะคิดว่าบัตรใด ๆ ที่ไม่ได้เป็นของประเภทอื่น ๆ บางอย่างที่คุณยอมรับจะต้องเป็นมาสเตอร์การ์ด

สำคัญ : หมายเลขบัตรมีความยาวต่างกัน ตัวอย่างเช่น Visa มีบัตรที่ออกในอดีตที่มี PAN 13 หลักและบัตร PAN 16 หลัก เอกสารประกอบการขอวีซ่าในปัจจุบันระบุว่าอาจออกหรืออาจมีหมายเลขที่ออกระหว่าง 12 และ 19 หลัก ดังนั้นคุณไม่ควรตรวจสอบความยาวของหมายเลขบัตรนอกเหนือจากการตรวจสอบว่ามีอย่างน้อย 7 หลัก (สำหรับ IIN ที่สมบูรณ์พร้อมกับตัวเลขเช็คหนึ่งตัวซึ่งควรตรงกับค่าที่อัลกอริทึมของ Luhnทำนายไว้)

หนึ่งคำแนะนำเพิ่มเติม: ก่อนที่จะประมวลผล PAN ผู้ถือบัตรแถบช่องว่างและเครื่องหมายวรรคตอนใด ๆ ตัวละครจากการป้อนข้อมูล ทำไม? เพราะโดยทั่วไปจะง่ายกว่ามากในการป้อนตัวเลขในกลุ่มคล้ายกับที่แสดงในหน้าบัตรเครดิตจริงเช่น

4444 4444 4444 4444

ป้อนได้ง่ายกว่ามาก

4444444444444444

ไม่มีประโยชน์ใด ๆ ในการตีสอนผู้ใช้เพราะพวกเขาป้อนตัวอักษรที่คุณไม่คาดหวังไว้ที่นี่

นอกจากนี้ยังหมายถึงการตรวจสอบให้แน่ใจว่าฟิลด์รายการของคุณมีที่ว่างอย่างน้อย 24 ตัวอักษรมิฉะนั้นผู้ใช้ที่ป้อนช่องว่างจะหมดห้อง ฉันขอแนะนำให้คุณสร้างฟิลด์ให้กว้างพอที่จะแสดงอักขระได้ 32 ตัวและอนุญาตได้สูงสุด 64 ตัว ที่ให้ความอุดมสมบูรณ์มากสำหรับการขยายตัว

นี่คือภาพที่ให้ความเข้าใจเพิ่มเติมเล็กน้อย:

อัปเดต (2014):วิธีการตรวจสอบดูเหมือนจะไม่เป็นวิธีที่ถูกต้องในการตรวจสอบความถูกต้องของบัตรตามที่ระบุไว้ในความคิดเห็นเกี่ยวกับคำตอบนี้

UPDATE (2016):มาสเตอร์การ์ดคือการดำเนินการช่วงถังใหม่ที่เริ่มต้นการชำระเงิน Ach

การยืนยันบัตรเครดิต


7
ตัวอย่างที่ดี คุณมีการแสดงออกปกติสำหรับการ์ดมาสโทร?
Manikandan

4
ไม่ไม่ไม่. คุณไม่สามารถพึ่งพาความยาวของหมายเลขบัตรได้ พวกเขาสามารถเปลี่ยนแปลงได้ตลอดเวลา ส่วนหนึ่งของหมายเลขบัตรที่คุณวางใจได้คือ IIN (ซึ่งเคยเรียกว่า BIN) และหมายเลขนำหน้าของหมายเลขนั้น นอกจากนี้คุณไม่สามารถตรวจจับการ์ดมาสเตอร์การ์ดในลักษณะที่คุณแนะนำ ที่จะรับเซ็ตย่อยของการ์ดที่ประมวลผลผ่านระบบ Mastercard (ปัญหาหลักคือการ์ด Maestro ซึ่งมีคำนำหน้า IIN หลากหลาย)
alastair

2
@alastair คุณอ่านนิพจน์ก่อนที่จะแสดงความคิดเห็น? พวกเขาเขียนขึ้นโดยเฉพาะเพื่อใช้ IIN ดังนั้นฉันไม่เข้าใจสิ่งที่คุณพยายามจะพูด นอกจากนี้ IIN สามารถใช้เพื่อระบุผู้ออกบัตร แต่ไม่สามารถตรวจสอบได้ ตัวอย่างเช่น 5412 ไม่ได้เป็นตัวแทนของ MasterCard ที่สมบูรณ์ แต่ข้อเสนอแนะของคุณจะบ่งบอกว่าเป็นเช่นนั้น ฉันไม่พบหลักฐานว่า MasterCards เป็นอะไรนอกจากตัวเลข 16 หลัก โปรดระบุแหล่งที่มาสำหรับการอ้างสิทธิ์ของคุณ อย่างไรก็ตามคุณถูกต้องในการกล่าวถึงการอัปเดตสำหรับการ์ด Maestro อย่างไรก็ตาม
senfo

3
@senfo คุณพูดถูก 5412 จะไม่ใช่หมายเลขบัตรมาสเตอร์การ์ดที่สมบูรณ์ IIN นั้นยาวหกหลักดังนั้นหมายเลขบัตรทั้งหมดจะต้องเป็น 7 หลัก (ขั้นต่ำ) และต้องผ่านการตรวจสอบ Luhn ไม่จำเป็นต้องมี "การพิสูจน์" ว่าหมายเลข Mastercard มีอะไรนอกเหนือจาก 16 หลัก; ประเด็นก็คือไม่ว่าสถานการณ์ในวันนี้จะเป็นอย่างไรในอนาคตพวกเขาอาจออกบัตรที่มี 17 หรือ 18 หลักหรือสำหรับบางอย่างที่มี 15 การใช้งานโดยที่พวกเขามีความยาว 16 หลักนั้นไม่จำเป็นและสร้างความเสี่ยงในการบำรุงรักษาระยะยาว
alastair

3
ฉันพบว่ามันยากมากที่จะเชื่อว่าบัตรที่ถูกต้องบางใบจะไม่มีตัวเลขการตรวจสอบที่ถูกต้องตามอัลกอริทึม Luhn มันใช้ทุกที่อย่างแน่นอนเพื่อตรวจสอบหมายเลขบัตรกับความผิดพลาดที่เรียบง่ายและความพยายามฉ้อโกงโง่ แต่ฉันสังเกตเห็นคนฉลาดบางคนไม่เข้าใจอัลกอริธึมและพวกเขาแค่คำนวณผิด
Rennex

74

ในจาวาสคริปต์:

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

ทดสอบหน่วย:

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 - ซอของคุณส่งคืนไม่ได้กำหนดสำหรับการทดสอบทั้งหมด ไม่ทำงาน :(
ShadeTreeDeveloper

@ShadeTreeDeveloper เพียงแค่ป้อนค่าใด ๆ เช่น 372176090165471 สำหรับ AMAX ในฟิลด์ข้อความ
รหัส Spy

@ jolly.exe ฉันเห็น ... ฉันหวังว่าจะมีบางสิ่งที่จะจัดรูปแบบขณะที่ฉันพิมพ์ (ปิดการเหตุการณ์คีย์อัป) ซอทำงานได้เมื่อฉันป้อนตัวเลขเต็ม
ShadeTreeDeveloper

ฉันสิ้นสุดการเขียนรหัสบิตนี้เพื่อทำการจัดรูปแบบอินพุตและการตรวจสอบที่ฉันต้องการ quercusv.github.io/smartForm
ShadeTreeDeveloper

คุณรู้วิธีตรวจจับหมายเลขบัตร v-pay และ bancontact ได้อย่างไร? ขอบคุณ
Oleksandr IY

38

อัปเดต: 15 มิถุนายน 2559 (เป็นทางออกที่ดีที่สุดในปัจจุบัน)

โปรดทราบว่าฉันได้ให้คะแนนสำหรับผู้ที่ได้รับการโหวตสูงสุด แต่เพื่อให้ชัดเจนว่านี่คือ regexps ใช้งานได้จริงฉันทดสอบด้วยรหัส BIN จริงนับพัน ที่สำคัญที่สุดคือการใช้สตริงเริ่มต้น (^) มิฉะนั้นจะให้ผลลัพธ์ที่ผิดพลาดในโลกแห่งความจริง!

JCB ^(?:2131|1800|35)[0-9]{0,}$เริ่มต้นด้วย: 2131, 1800, 35 (3528-3589)

American Express ^3[47][0-9]{0,}$เริ่มต้นด้วย: 34, 37

ไดเนอร์สคลับ ^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

ศาสตราจารย์ในทางดนตรี ^(5[06789]|6)[0-9]{0,}$โทรเติบโตในช่วง: 60-69เริ่มต้นด้วย / ไม่ใช่อย่างอื่น แต่เริ่มต้นที่ 5 จะต้องเข้ารหัสเป็นมาสเตอร์การ์ดอยู่ดี จะต้องตรวจพบการ์ดมาสโทรในตอนท้ายของรหัสเพราะการ์ดบางอันมีค่าอยู่ในช่วง 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

ใน จาวาสคริปต์ฉันใช้ฟังก์ชั่นนี้ นี่เป็นสิ่งที่ดีเมื่อคุณกำหนดให้กับเหตุการณ์ 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;
}

ที่นี่คุณสามารถเล่นกับมัน:

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

สำหรับ PHP ใช้ฟังก์ชั่นนี้จะตรวจจับการ์ด VISA / MC ย่อยด้วยเช่นกัน:

/**
  * 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
และโปรดทราบว่านี่เป็นเพียงการตรวจจับหมายเลข CC และไม่ผ่านการตรวจสอบ นั่นคือการแยกออกจากกันควรจะมีการตรวจสอบ Luhn ...
Janos ปั

Visa Electron อยู่ที่ไหนและเพราะเหตุใดเช็คมาสโทรจึงส่งคืนมาสเตอร์การ์ดในบางกรณี มาสเตอร์การ์ดไม่ควรตรวจสอบตัวเองเหรอ?
BadHorsie

ไม่สามารถจดจำหมายเลขทดสอบ JCB นี้เป็นประเภทใดก็ได้ (3088514174175777) และระบุหมายเลขทดสอบ JCB เป็น diners_club (3096278649822922) สมมติว่ารายการหมายเลขบัตรทดสอบนี้ใช้งานได้แล้ว ( freeformatter.com/credit-card-number-generator-validator.html )
Drew

ไม่มีเอกสารที่เริ่มต้น 308 หรือ 309 อาจเป็นบัตร JCB
Janos Szabo

+1 สำหรับการระบุรหัสการตรวจจับประเภท cc ซึ่งเป็นสิ่งที่คุณต้องการทำเพื่อ ux - regex สำหรับช่วงใหม่ของ MC ต้องการ tweek ขนาดเล็ก: / ^ (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";
}

นี่คือฟังก์ชั่นเพื่อตรวจสอบประเภทบัตรเครดิตโดยใช้ Regex, c #


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

15

เมื่อเร็ว ๆ นี้ฉันต้องการฟังก์ชั่นดังกล่าวฉันกำลังย้ายเครื่องมือตรวจสอบบัตรเครดิต Zend Framework เพื่อทับทิม พลอยทับทิม: https://github.com/Fivell/credit_card_validations กรอบ zend: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

พวกเขาทั้งสองใช้ช่วง INN สำหรับการตรวจจับประเภท ที่นี่คุณสามารถอ่านเกี่ยวกับ INN

ตามนี้คุณสามารถตรวจจับบัตรเครดิตหรือ (โดยไม่ต้อง regexps แต่ประกาศกฎบางอย่างเกี่ยวกับคำนำหน้าและความยาวที่เป็นไปได้)

ดังนั้นเราจึงมีกฎต่อไปสำหรับการ์ดที่ใช้มากที่สุด

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

}

จากนั้นค้นหาคำนำหน้าและเปรียบเทียบความยาวคุณสามารถตรวจสอบแบรนด์บัตรเครดิตได้ อย่าลืมเกี่ยวกับ luhn algoritm (มันสืบเชื้อสายมาจากที่นี่http://en.wikipedia.org/wiki/Luhn )

UPDATE

รายการกฎที่อัปเดตสามารถพบได้ที่นี่https://raw.githubusercontent.com/Fivell/credit_card_validations/master/lib/data/brands.yaml


2
ตัวอย่างมาก บัตรวีซ่าอาจมีความยาว 13 หลัก
เฮอร์แมนกาญจน์

@HermanKan ไม่มีเว็บไซต์ VISA บอกว่าควรมีความยาว 16 ฉันคิดว่านานมาแล้วมันอาจจะเป็น 13 แต่ไม่ใช่ทุกวันนี้
Fivell

1
ฉันคิดว่ามันคือการสนับสนุนแบบดั้งเดิม
Fivell

1
@HermanKan มีอีกสิ่งหนึ่งที่ VISA มีบัตร VPay และสอดคล้องกับแบรนด์ VPay ของวิกิพีเดียวีซ่าของ Visa สามารถระบุความยาว PAN ได้ตั้งแต่ 13 ถึง 19 หลักดังนั้นจึงเห็นหมายเลขบัตรมากกว่า 16 หลัก
Fivell

1
@Ethan ตรวจสอบลิงก์ล่าสุดในคำตอบที่อัปเดตของฉันraw.githubusercontent.com/Fivell/credit_card_validations/master/…
Fivell

13

นี่คือรหัสC # หรือ VB สมบูรณ์สำหรับทุกสิ่งที่เกี่ยวข้องกับ CCใน codeproject

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PassesLuhnTest

บทความนี้ได้รับการขึ้นสองสามปีโดยไม่มีความคิดเห็นเชิงลบ


1
@barett - แก้ไข ดูเหมือนว่าพวกเขาย้ายจากหมวดหมู่ 'aspnet' ไปเป็นหมวดหมู่ 'validation' ซึ่งเปลี่ยนลิงค์
Simon_Weaver

2
ลิงก์เสีย อาจเป็นอรรถประโยชน์เดียวกันหรือไม่ codeproject.com/Articles/20271/…
Josh Noe

รหัส codeproject นั้นมาจากปี 2007 คำเตือนมันอาจจะล้าสมัย
4657

8

รุ่นจาวาสคริปต์ขนาดกะทัดรัด

    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

คำตอบของ 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;
    }
 }

7

นี่คือฟังก์ชั่นระดับ php ส่งกลับ CCtype โดย CCnumber
รหัสนี้ไม่ได้ตรวจสอบความถูกต้องของการ์ดหรือไม่เรียกใช้อัลกอริทึม Luhn เพียงพยายามค้นหาประเภทบัตรเครดิตตามตารางในหน้านี้ ใช้ความยาว CCnumber และคำนำหน้า CCcard เป็นพื้นฐานเพื่อกำหนดประเภท 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

อย่าพยายามตรวจสอบประเภทบัตรเครดิตเป็นส่วนหนึ่งของการประมวลผลการชำระเงิน คุณกำลังเสี่ยงต่อการปฏิเสธธุรกรรมที่ถูกต้อง

หากคุณต้องการให้ข้อมูลแก่ผู้ประมวลผลการชำระเงินของคุณ (เช่นวัตถุบัตรเครดิต 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.');
}

การนำไปใช้นี้ (ใช้เพียงสองหลักแรกเท่านั้น) ก็เพียงพอที่จะระบุรูปแบบบัตรหลักทั้งหมด (และในกรณีของ PayPal ที่รองรับทั้งหมด) ในความเป็นจริงคุณอาจต้องการข้ามข้อยกเว้นทั้งหมดและใช้ค่าเริ่มต้นเป็นประเภทบัตรยอดนิยม ให้เกตเวย์การชำระเงิน / ตัวประมวลผลแจ้งให้คุณทราบหากมีข้อผิดพลาดในการตรวจสอบความถูกต้องตามคำขอของคุณ

ความจริงก็คือประตูการชำระเงินของคุณไม่สนใจเกี่ยวกับค่าที่คุณให้


1
นี่เป็นเรื่องจริง ฉันรู้จักผู้ให้บริการที่แตกต่างกัน 3 รายที่ต้องใช้บัตรประเภทนั้นในการส่งต่อและถ้าคุณไม่ผ่านการทำธุรกรรมจะล้มเหลว
Ed DeGagne

3
@EdDeGagne - "ไม่สนใจสิ่งที่มีค่า" ไม่เหมือนกับ "ไม่สนใจถ้าผ่านไป"
Quentin Skousen

ฉันไม่ได้ระบุที่ใด ฉันเพียงแค่กล่าวว่ามีผู้ให้บริการที่ใช้งานที่ต้องการให้คุณผ่านในประเภท CC ไม่มีอะไรเพิ่มเติม
Ed DeGagne

คุณไม่สามารถลดความซับซ้อนของปัญหานี้ได้ แต่โดยปกติผู้ให้บริการชำระเงินไม่ต้องการให้คุณแนะนำประเภทบัตรพวกเขามีวิธีการตรวจจับของตัวเอง
Janos Szabo

6

หมายเลขแรกของบัตรเครดิตสามารถใช้เพื่อประมาณผู้ขาย:

  • วีซ่า: 49,44 หรือ 47
  • อิเล็กตรอนวีซ่า: 42, 45, 48, 49
  • มาสเตอร์การ์ด: 51
  • Amex: 34
  • ไดเนอร์ส: 30, 36, 38
  • JCB: 35

ช่วงเหล่านี้ได้รับการอัปเดตเป็นส่วนใหญ่ บริษัท ผู้จำหน่ายการ์ดได้เพิ่มวิธีเพิ่มเติมในช่วงที่ระบุไว้ในโพสต์
NJInamdar

6

ในการรับรู้ช่วงบัตร (CRR) ข้อเสียเปรียบที่มีอัลกอริทึมที่ใช้ชุดของ regex หรือช่วงฮาร์ดโค้ดอื่น ๆ คือ BINs / IINs มีการเปลี่ยนแปลงตลอดเวลาในประสบการณ์ของฉัน การสร้างแบรนด์ร่วมของการ์ดเป็นสิ่งที่ยุ่งยากอย่างต่อเนื่อง ผู้ซื้อบัตร / พ่อค้าคนละใบอาจต้องการให้คุณรักษาบัตรใบเดียวกันนี้แตกต่างกันไปขึ้นอยู่กับตำแหน่งทางภูมิศาสตร์เช่น

นอกจากนี้ในช่วงไม่กี่ปีที่ผ่านมาด้วยเช่นบัตร UnionPay ในวงกว้างมากขึ้นรุ่นที่มีอยู่ไม่ได้รับมือกับช่วงใหม่ที่บางครั้ง interleave กับช่วงกว้างที่พวกเขาแทนที่
การรู้ภูมิศาสตร์ที่ระบบของคุณต้องครอบคลุมอาจช่วยได้เนื่องจากบางช่วงถูก จำกัด ให้ใช้ในบางประเทศ ตัวอย่างเช่นช่วง 62 รวมช่วงย่อย AAA บางอย่างในสหรัฐอเมริกา แต่ถ้าฐานผู้ขายของคุณอยู่นอกสหรัฐอเมริกาคุณอาจปฏิบัติต่อ 62 ทั้งหมดเป็น UnionPay
คุณอาจถูกขอให้รักษาบัตรด้วยวิธีที่แตกต่างกันไปตามสถานที่ตั้งร้านค้า เช่นใช้บัตรเดบิตในสหราชอาณาจักรเพื่อชำระในประเทศ แต่เป็นเครดิตในระดับสากล

มีกฎระเบียบที่มีประโยชน์มากซึ่งดูแลโดยธนาคารรับที่สำคัญ เช่นhttps://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdfและhttps://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf (ลิงก์ที่ถูกต้อง ณ เดือนมิถุนายน 2017 ขอขอบคุณผู้ใช้ที่ให้ลิงก์ไปยังข้อมูลอ้างอิงที่อัปเดตแล้ว) แต่โปรดระวังข้อควรระวังในขณะที่กฎ CRR เหล่านี้อาจเป็นตัวแทนจักรวาลที่ออกบัตรเนื่องจากมันใช้กับร้านค้าที่กิจการ ไม่รวมช่วงที่ระบุว่าเป็น CUP / UPI

ความคิดเห็นเหล่านี้นำไปใช้กับสถานการณ์แถบแม่เหล็ก (MagStripe) หรือ PKE (Pan Key Entry) สถานการณ์จะแตกต่างกันอีกครั้งในโลก ICC / EMV

อัปเดต: คำตอบอื่น ๆ ในหน้านี้ (และหน้า WikiPedia ที่เชื่อมโยง) มี JCB เช่นกันนาน 16 ครั้ง อย่างไรก็ตามใน บริษัท ของฉันเรามีทีมวิศวกรเฉพาะที่รับรองอุปกรณ์ POS และซอฟต์แวร์ของเราในธนาคารและภูมิภาคที่มีผู้ซื้อหลายราย ชุดหนังสือรับรองล่าสุดของทีมนี้มาจาก JCB มีตัวอักษร PAN ยาว 19 แผ่น


สวัสดี @CaiqueOliveira โปรดดูลิงก์ที่อัปเดต ขอบคุณ mac9416 ที่ให้ลิงก์ไปยังการอ้างอิง BIN-Rules ที่อัปเดตแล้ว
MikeRoger

1
ขอบคุณ @ mac9416 สำหรับการอ้างอิงกฎ BIN ที่อัปเดตแล้ว
MikeRoger

5

คำตอบของ Usman Y เวอร์ชั่น Swift 2.1 ใช้คำสั่งพิมพ์เพื่อตรวจสอบเพื่อเรียกโดยค่าสตริง

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 ได้จัดให้มีไลบรารีจาวาสคริปต์ที่ยอดเยี่ยมสำหรับการตรวจจับแบบแผนของการ์ด ให้ฉันเพิ่มตัวอย่างโค้ดบางส่วนและแสดงวิธีใช้

ประการแรกรวมไว้ในหน้าเว็บของคุณเป็น

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

ใช้ฟังก์ชั่น cardType เพื่อตรวจจับแบบแผนของการ์ด

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

นี่คือลิงค์อ้างอิงสำหรับตัวอย่างและตัวอย่างเพิ่มเติม

  1. บล็อกลายทางสำหรับ jquery.payment.js
  2. ที่เก็บ Github

4

รวดเร็วคุณสามารถสร้าง enum เพื่อตรวจจับประเภทบัตรเครดิต

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

เรียกวิธีการ CreditCardType.cardTypeForCreditCardNumber ("# หมายเลขบัตร") ซึ่งส่งกลับค่า enum CreditCardType


3

โซลูชันของฉันกับ 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;
}

ในกรณีที่ส่งคืน 0 จะตรวจไม่พบประเภทบัตรเครดิต

ควรเพิ่มคลาส "บัตรเครดิต" ในฟิลด์อินพุตบัตรเครดิต


1
รูปแบบของคำตอบที่มีอยู่
Gajus

1
ใช่ฉันใช้รหัสจากคำตอบข้างต้นปรับปรุงและโพสต์ที่นี่ ขอบคุณสำหรับ downvote ...
ZurabWeb

3
คุณควรมี (a) แนะนำสิ่งนี้เป็นการปรับปรุงรหัสที่มีอยู่ (b) เขียนการมีส่วนร่วมที่เหมาะสมหรือ (c) อ้างอิงแหล่งที่มาที่คุณใช้ในการเขียนนิพจน์ทั่วไป
Gajus

1
Gajus ฉันเชื่อว่าฉันช่วยชุมชนในแบบที่ฉันสามารถทำได้ในขณะนั้นโปรดหยุดบอกฉันว่าฉันควรทำบางสิ่งเพื่อใครบางคน ฉันทำสิ่งที่ฉันคิดว่าเป็นประโยชน์
ZurabWeb

3

ฉันค้นหาการจัดรูปแบบบัตรเครดิตและการจัดรูปแบบหมายเลขโทรศัพท์ค่อนข้างน้อย พบเคล็ดลับที่ดีมากมาย แต่ไม่มีอะไรเหมาะสมกับความต้องการที่แท้จริงของฉันดังนั้นฉันจึงสร้างโค้ดนี้ขึ้นมา คุณใช้มันแบบนี้:

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

คำถามเกี่ยวกับอัลกอริทึมในการตรวจสอบบัตรเครดิตไม่ใช่การใช้งานเฉพาะ รหัสนี้ทำอะไร?
Emil Vikström

2

เพียงให้อาหารช้อนเล็กน้อย:

$("#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

นี่คือตัวอย่างของฟังก์ชั่นบูลีนบางอย่างที่เขียนใน Python ที่ส่งคืนTrueหากตรวจพบการ์ดตามชื่อฟังก์ชัน

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

เลขหกตัวแรกของหมายเลขบัตร (รวมถึงตัวเลข MII เริ่มต้น) เป็นที่รู้จักกันในชื่อหมายเลขประจำตัวผู้ออกบัตร (IIN) ระบุสถาบันที่ออกบัตรที่ออกบัตรให้ผู้ถือบัตร จำนวนที่เหลือจะถูกจัดสรรโดยผู้ออกบัตร ความยาวของหมายเลขบัตรคือจำนวนหลัก ผู้ออกบัตรจำนวนมากพิมพ์ IIN ทั้งหมดและหมายเลขบัญชีในบัตรของพวกเขา

จากข้อเท็จจริงข้างต้นฉันต้องการเก็บข้อมูลโค้ดJAVAเพื่อระบุแบรนด์การ์ด

ตัวอย่างการ์ดประเภทต่างๆ

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

คำนำหน้าบัตร

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

ตรวจสอบเพื่อดูว่าหมายเลขอินพุตมีส่วนนำหน้าใด ๆ ที่กำหนดหรือไม่

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

ในที่สุดวิธีการยูทิลิตี้

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

การอ้างอิง


1

ลองใช้วิธีนี้กับ kotlin เพิ่ม Regex และเพิ่มลงในคำสั่ง when

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

กฎการแสดงออกปกติที่ตรงกับผู้ขายการ์ดที่เกี่ยวข้อง :

  • (4\d{12}(?:\d{3})?) สำหรับวีซ่า
  • (5[1-5]\d{14}) สำหรับ MasterCard
  • (3[47]\d{13}) สำหรับ AMEX
  • ((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?) สำหรับมาสโทร
  • (3(?:0[0-5]|[68][0-9])[0-9]{11}) สำหรับไดเนอร์สคลับ
  • (6(?:011|5[0-9]{2})[0-9]{12}) สำหรับการค้นพบ
  • (35[2-8][89]\d\d\d{10}) สำหรับ JCB

ฉันคิดว่า regex สำหรับ JCB ไม่ถูกต้อง ควรยอมรับตัวเลขสี่หลักแรกทั้งหมดระหว่าง 3528 ถึง 3589 แต่ไม่ได้รับตัวอย่างเช่น 3570
Gabe

0

ฉันใช้https://github.com/bendrucker/creditcards-types/เพื่อตรวจสอบประเภทบัตรเครดิตจากหมายเลข ปัญหาหนึ่งที่ฉันพบคือตรวจสอบหมายเลขทดสอบ 6011 1111 1111 1117

จากhttps://www.cybersource.com/developers/other_resources/quick_references/test_cc_numbers/ เราจะเห็นว่ามันเป็นตัวเลขที่ค้นพบเพราะมันเริ่มต้นด้วย 6011 แต่ผลลัพธ์ที่ฉันได้รับจากประเภทบัตรเครดิตคือ "Maestro" ฉันเปิดปัญหาให้ผู้เขียน เขาตอบฉันในไม่ช้าและให้เอกสาร pdf นี้https://www.discovernetwork.com/downloads/IPP_VAR_Compliance.pdf จากเอกสารเราเห็นได้ชัดเจนว่า 6011 1111 1111 1117 ไม่ได้อยู่ในช่วงของการค้นพบบัตรเครดิต


ฉันมีปัญหาเดียวกันคุณได้รับการแก้ไขไหม?
lucasvm1980

@ lucasvm1980 ฉันคิดว่าไฟล์ pdf discovernetwork.com เชื่อถือได้มากกว่า และหมายเลข 6011 1111 1111 1117 เป็นเพียงหมายเลขทดสอบไม่มีบัตรเครดิตจริงที่มีหมายเลขนี้ ดังนั้นฉันคิดว่าไม่จำเป็นต้องกังวลเกี่ยวกับเรื่องนี้
yuxiaomin

ดูเหมือนว่ามีข้อผิดพลาดบางอย่างกับการ์ด Discover บางตัวฉันได้ลองใช้หมายเลขที่ถูกต้องและได้รับข้อผิดพลาดนั้นแล้ว
lucasvm1980

@ lucasvm1980 คุณสามารถระบุหมายเลขและส่งปัญหาเกี่ยวกับ github ได้หรือไม่?
yuxiaomin

0

ลองสิ่งนี้เพื่อความรวดเร็ว

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
}

ใช้.

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) {

            }
        });
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.