Как определить тип кредитной карты на основе номера?
Я пытаюсь выяснить, как определить тип кредитной карты, основанный исключительно на ее количестве. Кто-нибудь знает об окончательном, надежном способе найти это?
- Как найти пару с k-й наибольшей суммой?
- Как проверить, пересекает ли сегмент линии прямоугольник?
- Алгоритм естественной сортировки
- Как измерить сходство между двумя изображениями?
- Для чего нужен пузырь?
- Что такое самоуверенное программное обеспечение?
- Сбита ли математика с плавающей запятой?
- Как вы находите точку на заданном перпендикулярном расстоянии от линии?
Номер кредитной / дебетовой карты называется PAN или номером первичной учетной записи . Первые шесть цифр PAN берутся из идентификационного номера IIN или идентификационного номера эмитента , принадлежащего банку-эмитенту (IIN ранее назывались BIN – идентификационные номера банков, поэтому вы можете увидеть ссылки на эту терминологию в некоторых документах). Эти шесть цифр соответствуют международному стандарту ISO / IEC 7812 и могут использоваться для определения типа карты из числа.
К сожалению, фактическая firebase database ISO / IEC 7812 не является общедоступной, однако есть неофициальные списки, как коммерческие, так и бесплатные, в том числе в Википедии .
В любом случае, чтобы определить тип из числа, вы можете использовать регулярное выражение, подобное приведенным ниже: Кредит для оригинальных выражений
Виза: ^4[0-9]{6,}$
Номера карт Visa начинаются с 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,}$
До 2016 года номера MasterCard начинаются с номера от 51 до 55, но это будет определять только кредитные карты MasterCard ; есть другие карты, выпущенные с использованием системы MasterCard, которые не попадают в этот диапазон IIN. В 2016 году они добавят числа в диапазоне (222100-272099).
American Express: ^3[47][0-9]{5,}$
Номера карт American Express начинаются с 34 или 37.
Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$
Номера карт Diners Club начинаются с 300 до 305, 36 или 38. Diners Club, которые начинаются с 5 и имеют 16 цифр. Это совместное предприятие Diners Club и MasterCard и должно обрабатываться как MasterCard.
Откройте: ^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 других банков и поэтому расположены по всему номеру. В результате может быть лучше предположить, что любая карта, которая не принадлежит вам какого-либо другого типа, которую вы принимаете, должна быть MasterCard .
Важно : номера карт различаются по длине; например, Visa имеет в прошлом выпущенные карточки с 13-значными PAN и карточками с 16-разрядными PAN. Документация Visa в настоящее время указывает, что она может выдавать или может выдавать номера от 12 до 19 цифр. Поэтому вы не должны проверять длину номера карты, кроме проверки того, что она содержит как минимум 7 цифр (для полной IIN плюс одна контрольная цифра, которая должна соответствовать значению, предсказанному алгоритмом Луна ).
Еще один намек: перед обработкой держателя карты PAN поместите на вход любые символы пробелов и знаков пунктуации . Зачем? Потому что, как правило, гораздо проще вводить цифры в группах, подобно тому, как они отображаются на лицевой стороне фактической кредитной карты, т. Е.
4444 4444 4444 4444
намного легче ввести правильно, чем
4444444444444444
На самом деле нет никакой пользы в том, чтобы наказывать пользователя, потому что они ввели символы, которых вы не ожидаете здесь.
Это также подразумевает, что ваши поля ввода могут содержать как минимум 24 символа, иначе пользователи, которые вводят пробелы, будут работать вне комнаты. Я бы рекомендовал вам сделать поле достаточно широким, чтобы отображать 32 символа и допускать до 64; что дает большой запас для расширения.
Вот изображение, которое дает немного больше информации:
UPDATE (2014): метод контрольной суммы больше не является действительным способом проверки подлинности карты, как указано в комментариях к этому ответу.
UPDATE (2016): Mastercard – это реализация новых диапазонов BIN, начиная с Ach Payment .
В 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 } } }
Модульный тест:
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]); }); }); }); });
Обновлено: 15 июня 2016 года (как окончательное решение в настоящее время)
Обратите внимание, что я даже проголосую за то, что один из них проголосован, но чтобы понять, что это регулярные выражения, на самом деле работает, я тестировал его с тысячами реальных кодов BIN. Самое главное – использовать стартовые строки (^), иначе это даст ложные результаты в реальном мире!
JCB ^(?:2131|1800|35)[0-9]{0,}$
Начать с: 2131, 1800, 35 (3528-3589)
American Express ^3[47][0-9]{0,}$
Начать с: 34, 37
Diners Club ^3(?:0[0-59]{1}|[689])[0-9]{0,}$
Начать с: 300-305, 309, 36, 38-39
Visa ^4[0-9]{0,}$
Начать с: 4
MasterCard ^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$
Начните с : 2221-2720, 51-55
Maestro ^(5[06789]|6)[0-9]{0,}$
Maestro всегда растет в диапазоне: 60-69 , начинается с / не что-то еще, но начало 5 должно быть закодировано как mastercard в любом случае. Карты Maestro должны быть обнаружены в конце кода, потому что некоторые другие имеют диапазон 60-69. Посмотрите на код.
Обнаружение ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$
Обнаруживать довольно сложно, начиная с: 6011, 622126-622925, 644-649, 65
В javascript я использую эту функцию. Это хорошо, когда u назначает его событию 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; }
Здесь вы можете играть с ним:
Для использования этой функции PHP это также обнаруживает некоторые дополнительные карты VISA / MC:
/** * Obtain a brand constant from a PAN * * @param type $pan Credit card number * @param type $include_sub_types Include detection of sub visa brands * @return string */ public static function getCardBrand($pan, $include_sub_types = false) { //maximum length is not fixed now, there are growing number of CCs has more numbers in length, limiting can give false negatives atm //these regexps accept not whole cc numbers too //visa $visa_regex = "/^4[0-9]{0,}$/"; $vpreca_regex = "/^428485[0-9]{0,}$/"; $postepay_regex = "/^(402360|402361|403035|417631|529948){0,}$/"; $cartasi_regex = "/^(432917|432930|453998)[0-9]{0,}$/"; $entropay_regex = "/^(406742|410162|431380|459061|533844|522093)[0-9]{0,}$/"; $o2money_regex = "/^(422793|475743)[0-9]{0,}$/"; // MasterCard $mastercard_regex = "/^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$/"; $maestro_regex = "/^(5[06789]|6)[0-9]{0,}$/"; $kukuruza_regex = "/^525477[0-9]{0,}$/"; $yunacard_regex = "/^541275[0-9]{0,}$/"; // American Express $amex_regex = "/^3[47][0-9]{0,}$/"; // Diners Club $diners_regex = "/^3(?:0[0-59]{1}|[689])[0-9]{0,}$/"; //Discover $discover_regex = "/^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$/"; //JCB $jcb_regex = "/^(?:2131|1800|35)[0-9]{0,}$/"; //ordering matter in detection, otherwise can give false results in rare cases if (preg_match($jcb_regex, $pan)) { return "jcb"; } if (preg_match($amex_regex, $pan)) { return "amex"; } if (preg_match($diners_regex, $pan)) { return "diners_club"; } //sub visa/mastercard cards if ($include_sub_types) { if (preg_match($vpreca_regex, $pan)) { return "v-preca"; } if (preg_match($postepay_regex, $pan)) { return "postepay"; } if (preg_match($cartasi_regex, $pan)) { return "cartasi"; } if (preg_match($entropay_regex, $pan)) { return "entropay"; } if (preg_match($o2money_regex, $pan)) { return "o2money"; } if (preg_match($kukuruza_regex, $pan)) { return "kukuruza"; } if (preg_match($yunacard_regex, $pan)) { return "yunacard"; } } if (preg_match($visa_regex, $pan)) { return "visa"; } if (preg_match($mastercard_regex, $pan)) { return "mastercard"; } if (preg_match($discover_regex, $pan)) { return "discover"; } if (preg_match($maestro_regex, $pan)) { if ($pan[0] == '5') {//started 5 must be mastercard return "mastercard"; } return "maestro"; //maestro is all 60-69 which is not something else, thats why this condition in the end } return "unknown"; //unknown for this system }
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 #
Проверь это:
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
недавно мне нужна была такая функциональность, я портировал Zend Framework Credit Card Validator на ruby. ruby gem: https://github.com/Fivell/credit_card_validations zend framework: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php
Они используют диапазоны INN для определения типа. Здесь вы можете прочитать о INN
В соответствии с этим вы можете обнаружить кредитную карту в качестве альтернативы (без регулярных выражений, но объявив некоторые правила о префиксах и возможной длине)
Итак, у нас есть следующие правила для большинства использованных карт
######## most used brands ######### visa: [ {length: [13, 16], prefixes: ['4']} ], mastercard: [ {length: [16], prefixes: ['51', '52', '53', '54', '55']} ], amex: [ {length: [15], prefixes: ['34', '37']} ], ######## other brands ######## diners: [ {length: [14], prefixes: ['300', '301', '302', '303', '304', '305', '36', '38']}, ], #There are Diners Club (North America) cards that begin with 5. These are a joint venture between Diners Club and MasterCard, and are processed like a MasterCard # will be removed in next major version diners_us: [ {length: [16], prefixes: ['54', '55']} ], discover: [ {length: [16], prefixes: ['6011', '644', '645', '646', '647', '648', '649', '65']} ], jcb: [ {length: [16], prefixes: ['3528', '3529', '353', '354', '355', '356', '357', '358', '1800', '2131']} ], laser: [ {length: [16, 17, 18, 19], prefixes: ['6304', '6706', '6771']} ], solo: [ {length: [16, 18, 19], prefixes: ['6334', '6767']} ], switch: [ {length: [16, 18, 19], prefixes: ['633110', '633312', '633304', '633303', '633301', '633300']} ], maestro: [ {length: [12, 13, 14, 15, 16, 17, 18, 19], prefixes: ['5010', '5011', '5012', '5013', '5014', '5015', '5016', '5017', '5018', '502', '503', '504', '505', '506', '507', '508', '6012', '6013', '6014', '6015', '6016', '6017', '6018', '6019', '602', '603', '604', '605', '6060', '677', '675', '674', '673', '672', '671', '670', '6760', '6761', '6762', '6763', '6764', '6765', '6766', '6768', '6769']} ], # Luhn validation are skipped for union pay cards because they have unknown generation algoritm unionpay: [ {length: [16, 17, 18, 19], prefixes: ['622', '624', '625', '626', '628'], skip_luhn: true} ], dankrot: [ {length: [16], prefixes: ['5019']} ], rupay: [ {length: [16], prefixes: ['6061', '6062', '6063', '6064', '6065', '6066', '6067', '6068', '6069', '607', '608'], skip_luhn: true} ] }
Затем, просматривая префикс и сравнивая длину, вы можете обнаружить бренд кредитной карты. Также не забывайте про luhn algoritm (здесь описано http://en.wikipedia.org/wiki/Luhn ).
Вот полный код C # или VB для всех видов связанных с CC вещей на codeproject.
- IsValidNumber
- GetCardTypeFromNumber
- GetCardTestNumber
- PassesLuhnTest
Эта статья была в течение нескольких лет без отрицательных комментариев.
Компактная версия javascript
var getCardType = function (number) { var cards = { visa: /^4[0-9]{12}(?:[0-9]{3})?$/, mastercard: /^5[1-5][0-9]{14}$/, amex: /^3[47][0-9]{13}$/, diners: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/, discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/, jcb: /^(?:2131|1800|35\d{3})\d{11}$/ }; for (var card in cards) { if (cards[card].test(number)) { return card; } } };
Ответ Анатолия на 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; } }
Здесь функция classа php возвращает CCtype по CCnumber.
Этот код не проверяет карту или не работает. Алгоритм Luhn пытается найти тип кредитной карты на основе таблицы на этой странице . в основном использует длину CCnumber и префикс CCcard для определения типа CCcard.
'American Express','cardLength'=>array(15),'cardPrefix'=>array('34', '37')) ,array('Name'=>'Maestro','cardLength'=>array(12, 13, 14, 15, 16, 17, 18, 19),'cardPrefix'=>array('5018', '5020', '5038', '6304', '6759', '6761', '6763')) ,array('Name'=>'Mastercard','cardLength'=>array(16),'cardPrefix'=>array('51', '52', '53', '54', '55')) ,array('Name'=>'Visa','cardLength'=>array(13,16),'cardPrefix'=>array('4')) ,array('Name'=>'JCB','cardLength'=>array(16),'cardPrefix'=>array('3528', '3529', '353', '354', '355', '356', '357', '358')) ,array('Name'=>'Discover','cardLength'=>array(16),'cardPrefix'=>array('6011', '622126', '622127', '622128', '622129', '62213', '62214', '62215', '62216', '62217', '62218', '62219', '6222', '6223', '6224', '6225', '6226', '6227', '6228', '62290', '62291', '622920', '622921', '622922', '622923', '622924', '622925', '644', '645', '646', '647', '648', '649', '65')) ,array('Name'=>'Solo','cardLength'=>array(16, 18, 19),'cardPrefix'=>array('6334', '6767')) ,array('Name'=>'Unionpay','cardLength'=>array(16, 17, 18, 19),'cardPrefix'=>array('622126', '622127', '622128', '622129', '62213', '62214', '62215', '62216', '62217', '62218', '62219', '6222', '6223', '6224', '6225', '6226', '6227', '6228', '62290', '62291', '622920', '622921', '622922', '622923', '622924', '622925')) ,array('Name'=>'Diners Club','cardLength'=>array(14),'cardPrefix'=>array('300', '301', '302', '303', '304', '305', '36')) ,array('Name'=>'Diners Club US','cardLength'=>array(16),'cardPrefix'=>array('54', '55')) ,array('Name'=>'Diners Club Carte Blanche','cardLength'=>array(14),'cardPrefix'=>array('300','305')) ,array('Name'=>'Laser','cardLength'=>array(16, 17, 18, 19),'cardPrefix'=>array('6304', '6706', '6771', '6709')) ); private function __construct() {} public static function getType($CCNumber) { $CCNumber= trim($CCNumber); $type='Unknown'; foreach (CreditcardType::$creditcardTypes as $card){ if (! in_array(strlen($CCNumber),$card['cardLength'])) { continue; } $prefixes = '/^('.implode('|',$card['cardPrefix']).')/'; if(preg_match($prefixes,$CCNumber) == 1 ){ $type= $card['Name']; break; } } return $type; } } ?>
Не пытайтесь определить тип кредитной карты как часть обработки платежа. Вы рискуете отклонить действительные транзакции.
Если вам необходимо предоставить информацию платежному процессу (например, для объекта кредитной карты 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 случае все поддерживаемые) схемы карт. Фактически, вы можете вообще пропустить исключение и использовать по умолчанию самый популярный тип карты. Пусть платежный шлюз / процессор скажет вам, есть ли ошибка проверки в ответ на ваш запрос.
Реальность заключается в том, что ваш платежный шлюз не заботится о стоимости, которую вы предоставляете .
Первые номера кредитной карты можно использовать для аппроксимации поставщика:
- Visa: 49,44 или 47
- Visa electronic: 42, 45, 48, 49
- MasterCard: 51
- Amex: 34
- Diners: 30, 36, 38
- JCB: 35
В распознавании диапазона карт (CRR) недостатком с алгоритмами, использующими ряд регулярных выражений или других диапазонов с жестким кодированием, является то, что BIN / IIN со временем меняются со временем. Совместное брендинг карт является постоянным осложнением. Разным карточным приобретателям / торговцам может потребоваться, чтобы вы относились к одной и той же карте по-разному, в зависимости от геолокации.
Кроме того, в последние несколько лет, например, с картами UnionPay в более широком кругообороте, существующие модели не справляются с новыми диапазонами, которые иногда чередуются с более широкими диапазонами, которые они заменяют.
Знание географии, которую должна охватить ваша система, может помочь, поскольку некоторые диапазоны ограничены для использования в конкретных странах. Например, диапазоны 62 include в себя некоторые поддиапазоны 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 могут представлять собой Вseleniumную для выпуска карт, как это применимо к продавцам, приобретенным этим лицом, он не включает, например, диапазоны, обозначенные как CUP / UPI.
Эти комментарии относятся к сценариям магнитной полосы (MagStripe) или PKE (Pan Key Entry). В мире ICC / EMV ситуация снова изменилась.
Обновление. Другие ответы на этой странице (а также на связанной странице WikiPedia) имеют JCB, как всегда, 16 длинных. Однако в моей компании у нас есть команда инженеров, которые сертифицируют наши POS-устройства и программное обеспечение в нескольких банках и географических регионах. Самый последний пакет сертификатов, который имеет эта команда из JCB, имел проезд для 19-летнего PAN.
Мое решение с 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 тип кредитной карты не обнаружен.
class «кредитная карта» должен быть добавлен в поле ввода кредитной карты.
Swift 2.1 Версия ответа Usman Y. Используйте оператор печати, чтобы проверить, чтобы вызов вызывал некоторое строковое значение
print(self.validateCardType(self.creditCardField.text!)) func validateCardType(testCard: String) -> String { let regVisa = "^4[0-9]{12}(?:[0-9]{3})?$" let regMaster = "^5[1-5][0-9]{14}$" let regExpress = "^3[47][0-9]{13}$" let regDiners = "^3(?:0[0-5]|[68][0-9])[0-9]{11}$" let regDiscover = "^6(?:011|5[0-9]{2})[0-9]{12}$" let regJCB = "^(?:2131|1800|35\\d{3})\\d{11}$" let regVisaTest = NSPredicate(format: "SELF MATCHES %@", regVisa) let regMasterTest = NSPredicate(format: "SELF MATCHES %@", regMaster) let regExpressTest = NSPredicate(format: "SELF MATCHES %@", regExpress) let regDinersTest = NSPredicate(format: "SELF MATCHES %@", regDiners) let regDiscoverTest = NSPredicate(format: "SELF MATCHES %@", regDiscover) let regJCBTest = NSPredicate(format: "SELF MATCHES %@", regJCB) if regVisaTest.evaluateWithObject(testCard){ return "Visa" } else if regMasterTest.evaluateWithObject(testCard){ return "MasterCard" } else if regExpressTest.evaluateWithObject(testCard){ return "American Express" } else if regDinersTest.evaluateWithObject(testCard){ return "Diners Club" } else if regDiscoverTest.evaluateWithObject(testCard){ return "Discover" } else if regJCBTest.evaluateWithObject(testCard){ return "JCB" } return "" }
Stripe has provided this fantastic javascript library for card scheme detection. Let me add few code snippets and show you how to use it.
Firstly Include it to your web page as
Secondly use the function cardType for detecting the card scheme.
$(document).ready(function() { var type = $.payment.cardType("4242 4242 4242 4242"); //test card number console.log(type); });
Here are the reference links for more examples and demos.
- Stripe blog for jquery.payment.js
- Репозиторий Github
I searched around quite a bit for credit card formatting and phone number formatting. Found lots of good tips but nothing really suited my exact desires so I created this bit of code . Вы используете его следующим образом:
var sf = smartForm.formatCC(myInputString); var cardType = sf.cardType;
In swift you can create an enum to detect the credit card type.
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 } }
Call the method CreditCardType.cardTypeForCreditCardNumber(“#card number”) which returns CreditCardType enum value.
// 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 credit card is invalid"); Type * $("#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 },
Just a little spoon feeding:
$("#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("
"); } else if (regMasterCard.test($(this).val())) { $("#CCImage").html("
"); } else if (regAmex.test($(this).val())) { $("#CCImage").html("
"); } else if (regDiscover.test($(this).val())) { $("#CCImage").html("
"); } else { $("#CCImage").html("NA"); } });
Here is an example of some boolean functions written in Python that return True
if the card is detected as per the function name.
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
The regular expression rules that match the respective card vendors :
-
(4\d{12}(?:\d{3})?)
for VISA. -
(5[1-5]\d{14})
for MasterCard. -
(3[47]\d{13})
for AMEX. -
((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?)
for Maestro. -
(3(?:0[0-5]|[68][0-9])[0-9]{11})
for Diners Club. -
(6(?:011|5[0-9]{2})[0-9]{12})
for Discover. -
(35[2-8][89]\d\d\d{10})
for JCB.
The first six digits of a card number (including the initial MII digit) are known as the issuer identification number (IIN). These identify the card issuing institution that issued the card to the card holder. The rest of the number is allocated by the card issuer. The card number’s length is its number of digits. Many card issuers print the entire IIN and account number on their card.
Based on the above facts I would like to keep a snippet of JAVA code to identify card brand.
Sample card types
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";
Card Prefixes
// 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" };
Check to see if the input number has any of the given prefixes.
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; }
Finally, The Utility method
/** * 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; }
Справка
- Stripe Card Builder
I use https://github.com/bendrucker/creditcards-types/ to detect the credit card type from number. One issue I ran into is discover test number 6011 1111 1111 1117
from https://www.cybersource.com/developers/other_resources/quick_references/test_cc_numbers/ we can see it is a discover number because it starts by 6011. But the result I get from the creditcards-types is “Maestro”. I opened the issue to the author. He replied me very soon and provide this pdf doc https://www.discovernetwork.com/downloads/IPP_VAR_Compliance.pdf From the doc we can see clearly that 6011 1111 1111 1117 does not fall into the range of discover credit card.
Try this.For swift.
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 }
Use.
if (self.checkCardValidation(number: "yourNumber") == true) { print("Card Number valid") }else{ print("Card Number not valid") }
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) { } });