¿Cómo se detecta el tipo de tarjeta de crédito según el número?

Estoy tratando de descubrir cómo detectar el tipo de tarjeta de crédito basado únicamente en su número. ¿Alguien sabe de una forma definitiva y confiable de encontrar esto?

El número de la tarjeta de crédito / débito se conoce como PAN o Número de cuenta principal . Los primeros seis dígitos del PAN son tomados del IIN , o Número de Identificación del Emisor , perteneciente al banco emisor (los IIN anteriormente se conocían como BIN – Números de Identificación del Banco – por lo que es posible que vea referencias a esa terminología en algunos documentos). Estos seis dígitos están sujetos a un estándar internacional, ISO / IEC 7812 , y se pueden usar para determinar el tipo de tarjeta del número.

Lamentablemente, la base de datos ISO / IEC 7812 no está públicamente disponible, sin embargo, hay listas no oficiales, tanto comerciales como gratuitas, incluso en Wikipedia .

De todos modos, para detectar el tipo del número, puede usar una expresión regular como las siguientes: Crédito para expresiones originales

Visa: ^4[0-9]{6,}$ Los números de tarjeta Visa comienzan con un 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,}$ Antes de 2016, los números de MasterCard comienzan con el números del 51 al 55, pero esto solo detectará tarjetas de crédito MasterCard ; hay otras tarjetas emitidas usando el sistema MasterCard que no entran en este rango IIN. En 2016, agregarán números en el rango (222100-272099).

American Express: ^3[47][0-9]{5,}$ Los números de tarjeta American Express comienzan con 34 o 37.

Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]{4,}$ números de tarjeta de Diners Club comienzan con 300 a través de 305, 36 o 38. Hay Tarjetas Diners Club que comienzan con 5 y tienen 16 dígitos. Se trata de una empresa conjunta entre Diners Club y MasterCard, y debe procesarse como una MasterCard.

Descubre: ^6(?:011|5[0-9]{2})[0-9]{3,}$ Los números de tarjetas Discover comienzan en 6011 o 65.

JCB: ^(?:2131|1800|35[0-9]{3})[0-9]{3,}$ tarjetas JCB comienzan con 2131, 1800 o 35.

Desafortunadamente, hay una serie de tipos de tarjetas procesadas con el sistema MasterCard que no viven en el rango IIN de MasterCard (números que comienzan en 51 … 55); el caso más importante es el de las tarjetas Maestro, muchas de las cuales han sido emitidas desde los rangos IIN de otros bancos y, por lo tanto, están ubicadas en todo el espacio numérico. Como resultado, puede ser mejor suponer que cualquier tarjeta que no sea de otro tipo que acepte debe ser una MasterCard .

Importante : los números de tarjeta varían en longitud; por ejemplo, Visa ha emitido tarjetas con PAN de 13 dígitos y tarjetas con PAN de 16 dígitos. La documentación de Visa actualmente indica que puede emitir o puede haber emitido números con entre 12 y 19 dígitos. Por lo tanto, no debe verificar la longitud del número de tarjeta, salvo para verificar que tiene al menos 7 dígitos (para un IIN completo más un dígito de control, que debe coincidir con el valor predicho por el algoritmo de Luhn ).

Una sugerencia adicional: antes de procesar un PAN de tarjetahabiente, quite cualquier espacio en blanco y signos de puntuación de la entrada . ¿Por qué? Porque generalmente es mucho más fácil ingresar los dígitos en grupos, de forma similar a cómo se muestran en el frente de una tarjeta de crédito real, es decir,

 4444 4444 4444 4444 

es mucho más fácil ingresar correctamente que

 4444444444444444 

Realmente no hay ningún beneficio en castigar al usuario porque ha ingresado caracteres que no espera aquí.

Esto también implica asegurarse de que sus campos de entrada tengan espacio para al menos 24 caracteres, de lo contrario, los usuarios que ingresen espacios se quedarán sin espacio. Recomiendo que amplíe el campo lo suficiente como para mostrar 32 caracteres y permitir hasta 64; eso le da mucho margen para la expansión.

Aquí hay una imagen que da un poco más de información:

ACTUALIZACIÓN (2014): el método de sum de comprobación ya no parece ser una forma válida de verificar la autenticidad de una tarjeta como se señala en los comentarios de esta respuesta.

ACTUALIZACIÓN (2016): Mastercard implementará nuevos rangos de BIN a partir de Ach Payment .

Verificación de tarjeta de crédito

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

Prueba de unidad:

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

Actualizado: 15 de junio de 2016 (como solución definitiva actualmente)

Tenga en cuenta que incluso doy mi voto a favor de que el votado sea el más votado, pero para dejar en claro que estas son las expresiones regulares, en realidad funciona, lo probé con miles de códigos BIN reales. Lo más importante es usar cadenas de inicio (^); de lo contrario, dará resultados falsos en el mundo real.

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

American Express ^3[47][0-9]{0,}$ Comience con: 34, 37

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

Visa ^4[0-9]{0,}$ Comience con: 4

MasterCard ^(5[1-5]|222[1-9]|22[3-9]|2[3-6]|27[01]|2720)[0-9]{0,}$ Comience con : 2221-2720, 51-55

Maestro ^(5[06789]|6)[0-9]{0,}$ Maestro siempre crece en el rango: 60-69 , comenzó con / no algo más, pero de todos modos el 5 debe estar codificado como tarjeta maestra. Las cartas Maestro deben detectarse al final del código porque algunas otras tienen un rango de 60-69. Por favor mira el código.

Descubra ^(6011|65|64[4-9]|62212[6-9]|6221[3-9]|622[2-8]|6229[01]|62292[0-5])[0-9]{0,}$ Descubrir código bastante difícil, comienza con: 6011, 622126-622925, 644-649, 65

En javascript , uso esta función. Esto es bueno cuando lo asigna a un evento onkeyup y da resultado tan pronto como sea posible.

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

Aquí puedes jugar con él:

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

Para PHP use esta función, esta detecta algunas tarjetas sub-VISA / MC también:

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

Aquí está la función para verificar el tipo de tarjeta de crédito usando Regex, c #

Mira esto:

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 

Recientemente necesité dicha funcionalidad, estaba transfiriendo Zend Framework Card Card Validator a ruby. ruby gem: https://github.com/Fivell/credit_card_validations zend framework: https://github.com/zendframework/zf2/blob/master/library/Zend/Validator/CreditCard.php

Ambos usan rangos de INN para detectar el tipo. Aquí puedes leer sobre INN

De acuerdo con esto, puede detectar la tarjeta de crédito alternativamente (sin expresiones regulares, pero declarando algunas reglas sobre prefijos y longitud posible)

Entonces tenemos las siguientes reglas para la mayoría de las tarjetas usadas

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

Luego, al buscar el prefijo y comparar la longitud, puede detectar la marca de la tarjeta de crédito. Además, no olvide el algoritmo de Luhn (se describe aquí http://en.wikipedia.org/wiki/Luhn ).

Aquí está el código completo de C # o VB para todo tipo de cosas relacionadas con CC en codeproject.

  • IsValidNumber
  • GetCardTypeFromNumber
  • GetCardTestNumber
  • PasesLuhnTest

Este artículo ha estado en pie durante un par de años sin comentarios negativos.

Versión compacta de 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; } } }; 

La respuesta de Anatoliy en 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; } } 

Aquí hay una función php class que devuelve CCtype por CCnumber.
Este código no valida la tarjeta o no ejecuta el algoritmo de Luhn, solo trata de encontrar el tipo de tarjeta de crédito en la tabla de esta página . Básicamente, utiliza la longitud CCnumber y el prefijo CCcard para determinar el tipo de 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; } } ?> 

No intente detectar el tipo de tarjeta de crédito como parte del procesamiento de un pago. Usted corre el riesgo de rechazar transacciones válidas.

Si necesita proporcionar información a su procesador de pagos (por ejemplo, el objeto de la tarjeta de crédito de PayPal requiere el nombre del tipo de tarjeta ), adivínelo de la menor información disponible, por ejemplo:

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

Esta implementación (utilizando solo los dos primeros dígitos) es suficiente para identificar todos los esquemas de tarjeta principales (y en el caso de PayPal todos los admitidos). De hecho, es posible que desee omitir la excepción por completo y de forma predeterminada al tipo de tarjeta más popular. Deje que el gateway / procesador de pagos le indique si hay un error de validación en respuesta a su solicitud.

La realidad es que su pasarela de pago no se preocupa por el valor que proporciona .

Los primeros números de la tarjeta de crédito se pueden usar para aproximar al vendedor:

  • Visa: 49,44 o 47
  • Electron Visa: 42, 45, 48, 49
  • MasterCard: 51
  • Amex: 34
  • Comensales: 30, 36, 38
  • JCB: 35

En Card Range Recognition (CRR), un inconveniente con los algoritmos que usan una serie de regex u otros rangos codificados, es que los BIN / IIN cambian con el tiempo en mi experiencia. La marca compartida de las tarjetas es una complicación en curso. Los diferentes adquirentes / comerciantes de tarjetas pueden necesitar que trates la misma tarjeta de manera diferente, dependiendo de, por ejemplo, la geolocalización.

Además, en los últimos años, por ejemplo, con las tarjetas UnionPay en mayor circulación, los modelos existentes no cubren los nuevos rangos que a veces se entrelazan con rangos más amplios que reemplazan.
Conocer la geografía que su sistema necesita cubrir puede ser útil, ya que algunos rangos están restringidos para su uso en determinados países. Por ejemplo, los rangos 62 incluyen algunos rangos secundarios de AAA en los EE. UU., Pero si su base de comerciantes está fuera de los EE. UU., Es posible que pueda tratar a los 62 como UnionPay.
También se le puede pedir que trate una tarjeta de manera diferente según la ubicación del comerciante. Por ejemplo, para tratar ciertas tarjetas del Reino Unido como débito a nivel nacional, pero como crédito internacional.

Hay un conjunto de reglas muy útil mantenido por un importante banco adquirente. Por ejemplo, https://www.barclaycard.co.uk/business/files/BIN-Rules-EIRE.pdf y https://www.barclaycard.co.uk/business/files/BIN-Rules-UK.pdf . (Enlaces válidos a partir de junio de 2017, gracias al usuario que proporcionó un enlace a la referencia actualizada). Pero tenga en cuenta la advertencia de que, si bien estas reglas de CRR pueden representar el universo de emisión de tarjeta tal como se aplica a los comerciantes adquiridos por esa entidad, no incluye, por ejemplo, rangos identificados como CUP / UPI.

Estos comentarios se aplican a escenarios de banda magnética (MagStripe) o PKE (entrada de tecla de panorámica). La situación es diferente nuevamente en el mundo ICC / EMV.

Actualización: otras respuestas en esta página (y también la página enlazada de WikiPedia) tienen JCB como siempre 16 de largo. Sin embargo, en mi compañía contamos con un equipo dedicado de ingenieros que certifican nuestros dispositivos y software POS en múltiples bancos y geografías adquirientes. El paquete de tarjetas de certificación más reciente que este equipo tiene de JCB, tenía un pase para un PAN largo de 19.

Mi solución con 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; } 

En caso de que se devuelva 0, no se detecta el tipo de tarjeta de crédito.

La clase “tarjeta de crédito” debe agregarse al campo de entrada de la tarjeta de crédito.

Swift 2.1 Versión de la respuesta de Usman Y. Use una statement de impresión para verificar así llame por algún valor de cadena

 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.

  1. Stripe blog for jquery.payment.js
  2. Repositorio de 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 . Lo usas así:

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

Referencia

  • 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) { } });