-
Star
(103)
You must be signed in to star a gist -
Fork
(18)
You must be signed in to fork a gist
-
-
Save gusribeiro/263a165db774f5d78251 to your computer and use it in GitHub Desktop.
Amex: ^3[47][0-9]{13}$ | |
Aura: /^((?!504175))^((?!5067))(^50[0-9])/ | |
Banese Card: '^636117' | |
Cabal: '(60420[1-9]|6042[1-9][0-9]|6043[0-9]{2}|604400)' | |
Diners: '(36[0-8][0-9]{3}|369[0-8][0-9]{2}|3699[0-8][0-9]|36999[0-9]) | |
Discover: /^6(?:011|5[0-9]{2})[0-9]{12}/ | |
Elo: /^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|^627780|^63(6297|6368|6369)|^65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/ | |
Fort Brasil: '^628167' | |
GrandCard: '^605032' | |
Hipercard: ^606282|^3841(?:[0|4|6]{1})0 | |
JCB: /^(?:2131|1800|35\d{3})\d{11}/ | |
Mastercard: ^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10}) | |
Personal Card: '^636085' | |
Sorocred: '^627892|^636414' | |
Valecard: '^606444|^606458|^606482' | |
Visa: ^4[0-9]{15}$ |
Comlementando, os cartões que deram errado passam na REGEX da bandeira esperada, mas também passam na da Discover/Aura. Eu comentei essas duas bandeiras e a maioria passou, só o 5031433215406351 que não está passando na REGEX do mastercard
Isso acontece porque o padrão desses cartões ELO realmente batem com o padrão da discover, porém por algum motivo a caixa registrou o BIN antes (não sei como funciona esses registros de BIN). Essas exceções já estão no regex da elo, podemos ver na parte "|6505[0-2][0-9]". Se jogarmos no bincheck.io inicialmente ele também da discover, mas se fizer o POST pra verificar ele irá retornar elo.
pra resolver podemos criar um switch e dar break antes para não continuar a verificação, e sempre verificar o ELO primeiro. Um exemplo em PHP
$bandeira = match (1) { preg_match( '/^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^504175|^627780|^63(6297|6368|6369)|(65003[5-9]|65004[0-9]|65005[01])|(65040[5-9]|6504[1-3][0-9])|(65048[5-9]|65049[0-9]|6505[0-2][0-9]|65053[0-8])|(65054[1-9]|6505[5-8][0-9]|65059[0-8])|(65070[0-9]|65071[0-8])|(65072[0-7])|(65090[1-9]|6509[1-6][0-9]|65097[0-8])|(65165[2-9]|6516[67][0-9])|(65500[0-9]|65501[0-9])|(65502[1-9]|6550[34][0-9]|65505[0-8])|^(506699|5067[0-6][0-9]|50677[0-8])|^(509[0-8][0-9]{2}|5099[0-8][0-9]|50999[0-9])|^65003[1-3]|^(65003[5-9]|65004\d|65005[0-1])|^(65040[5-9]|6504[1-3]\d)|^(65048[5-9]|65049\d|6505[0-2]\d|65053[0-8])|^(65054[1-9]|6505[5-8]\d|65059[0-8])|^(65070\d|65071[0-8])|^65072[0-7]|^(65090[1-9]|65091\d|650920)|^(65165[2-9]|6516[6-7]\d)|^(65500\d|65501\d)|^(65502[1-9]|6550[3-4]\d|65505[0-8])/', $cartaoNumero ) => 'elo', preg_match('/^4[0-9]{12}(?:[0-9]{3})?/', $cartaoNumero) => 'visa', preg_match('/^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/', $cartaoNumero) => 'mastercard', preg_match('/^3[47][0-9]{13}/', $cartaoNumero) => 'amexs', preg_match('/^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})/', $cartaoNumero) => 'discover', preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}/', $cartaoNumero) => 'diners', preg_match('/^(?:2131|1800|35\d{3})\d{11}/', $cartaoNumero) => 'jcb', preg_match('/^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})/', $cartaoNumero) => 'hipercard', default => '' };
Agora todos os números vão bater corretamente!
Esta bandeira 5031433215406351 no bincheck.io deu que não existe, então pode ser retirada.
Opa, consegui fazer funcionar. Só joguei a linha do elo para ser a primeira regex para checar e funcionou em todos (após remover o 5031433215406351)
Segue o código completo:
export function getCardBrandName (cardNumber: string): string | null {
const numbers = cardNumber.replace(/[^0-9]+/g, '')
const brands = {
elo: /^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|^627780|^63(6297|6368|6369)|^65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/,
amex: /^3[47][0-9]{13}$/,
aura: /^((?!504175))^((?!5067))(^50[0-9])/,
banese_card: /^636117/,
cabal: /(60420[1-9]|6042[1-9][0-9]|6043[0-9]{2}|604400)/,
diners: /(36[0-8][0-9]{3}|369[0-8][0-9]{2}|3699[0-8][0-9]|36999[0-9])/,
discover: /^6(?:011|5[0-9]{2})[0-9]{12}/,
fort_brasil: /^628167/,
grand_card: /^605032/,
hipercard: /^606282|^3841(?:[0|4|6]{1})0/,
jbc: /^(?:2131|1800|35\d{3})\d{11}/,
mastercard: /^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/,
personal_card: /^636085/,
sorocred: /^627892|^636414/,
valecard: /^606444|^606458|^606482/,
visa: /^4[0-9]{15}$/
}
const match = Object.entries(brands).find(([_, value]) => {
if (value.test(numbers)) {
return true
}
return false
})
if (match) {
return match[0]
}
return null
}
const cards = {
// PagSeguro
// https://dev.pagbank.uol.com.br/reference/cartoes-de-teste
'4539620659922097': 'visa',
'4929291898380766': 'visa',
'5240082975622454': 'mastercard',
'5530062640663264': 'mastercard',
'345817690311361': 'amex',
'372938001199778': 'amex',
'4514161122113757': 'elo',
'4389350446134811': 'elo',
'6062828598919021': 'hipercard',
'6062822916014409': 'hipercard',
// https://dev.pagbank.uol.com.br/reference/criar-pagar-pedido-com-3ds-validacao-pagbank
'4000000000002701': 'visa',
'5200000000001005': 'mastercard',
'6505050000001000': 'elo',
'4000000000002503': 'visa',
'5200000000001096': 'mastercard',
'6505050000001091': 'elo',
'4000000000002925': 'visa',
'5200000000001013': 'mastercard',
'6505050000001018': 'elo',
'4000000000002370': 'visa',
'5200000000001104': 'mastercard',
'6505050000001109': 'elo',
// Mercado pago
// https://www.mercadopago.com.br/developers/pt/docs/checkout-api/additional-content/your-integrations/test/cards
'5067766783888311': 'elo',
'4235647728025682': 'visa',
'375365153556885': 'amex',
// Gerados
// https://www.vccgenerator.org/
'5098176533461570': 'elo',
'5067349319312260': 'elo',
'5098193894226609': 'elo',
'5091084515027541': 'elo',
'5098177024386094': 'elo',
'4391395999142147': 'visa',
'4103922157715577': 'visa',
'4380208328771358': 'visa',
'4297672575052840': 'visa',
'4380277454970936': 'visa',
'5551555128049017': 'mastercard',
'5268003770982262': 'mastercard',
'5448382804657501': 'mastercard',
'5582852950163914': 'mastercard',
'5448384161742298': 'mastercard',
'340205640990176': 'amex',
'340205958483061': 'amex',
'340205254489929': 'amex',
'340205493225258': 'amex',
'340205571301401': 'amex',
};
for (const card in cards) {
const expectedBrand = cards[card]
const calculatedBrand = getCardBrandName(card)
if (expectedBrand == calculatedBrand) {
console.log(`${card} OK`)
} else {
console.log(`${card} ERROR. Expected ${expectedBrand}, got ${calculatedBrand}`)
}
}
Eu pequei os cartões dessa resposta do @MMortari :
Boa tarde pessoal,
Minha pequena contribuição, segue uma lista com alguns cartões que estou colecionando de alguns provedores para teste.const cards = { // PagSeguro // https://dev.pagbank.uol.com.br/reference/cartoes-de-teste '4539620659922097': EnumCardBrand.VISA, '4929291898380766': EnumCardBrand.VISA, '5240082975622454': EnumCardBrand.MASTERCARD, '5530062640663264': EnumCardBrand.MASTERCARD, '345817690311361': EnumCardBrand.AMEX, '372938001199778': EnumCardBrand.AMEX, '4514161122113757': EnumCardBrand.ELO, '4389350446134811': EnumCardBrand.ELO, '6062828598919021': EnumCardBrand.HIPERCARD, '6062822916014409': EnumCardBrand.HIPERCARD, // https://dev.pagbank.uol.com.br/reference/criar-pagar-pedido-com-3ds-validacao-pagbank '4000000000002701': EnumCardBrand.VISA, '5200000000001005': EnumCardBrand.MASTERCARD, '6505050000001000': EnumCardBrand.ELO, '4000000000002503': EnumCardBrand.VISA, '5200000000001096': EnumCardBrand.MASTERCARD, '6505050000001091': EnumCardBrand.ELO, '4000000000002925': EnumCardBrand.VISA, '5200000000001013': EnumCardBrand.MASTERCARD, '6505050000001018': EnumCardBrand.ELO, '4000000000002370': EnumCardBrand.VISA, '5200000000001104': EnumCardBrand.MASTERCARD, '6505050000001109': EnumCardBrand.ELO, // Mercado pago // https://www.mercadopago.com.br/developers/pt/docs/checkout-api/additional-content/your-integrations/test/cards '5067766783888311': EnumCardBrand.ELO, '5031433215406351': EnumCardBrand.MASTERCARD, '4235647728025682': EnumCardBrand.VISA, '375365153556885': EnumCardBrand.AMEX, // Gerados // https://www.vccgenerator.org/ '5098176533461570': EnumCardBrand.ELO, '5067349319312260': EnumCardBrand.ELO, '5098193894226609': EnumCardBrand.ELO, '5091084515027541': EnumCardBrand.ELO, '5098177024386094': EnumCardBrand.ELO, '4391395999142147': EnumCardBrand.VISA, '4103922157715577': EnumCardBrand.VISA, '4380208328771358': EnumCardBrand.VISA, '4297672575052840': EnumCardBrand.VISA, '4380277454970936': EnumCardBrand.VISA, '5551555128049017': EnumCardBrand.MASTERCARD, '5268003770982262': EnumCardBrand.MASTERCARD, '5448382804657501': EnumCardBrand.MASTERCARD, '5582852950163914': EnumCardBrand.MASTERCARD, '5448384161742298': EnumCardBrand.MASTERCARD, '340205640990176': EnumCardBrand.AMEX, '340205958483061': EnumCardBrand.AMEX, '340205254489929': EnumCardBrand.AMEX, '340205493225258': EnumCardBrand.AMEX, '340205571301401': EnumCardBrand.AMEX, };E usei os regex da última resposta, conforme o @gfucci colocou em sua resposta:
Comlementando, os cartões que deram errado passam na REGEX da bandeira esperada, mas também passam na da Discover/Aura. Eu comentei essas duas bandeiras e a maioria passou, só o 5031433215406351 que não está passando na REGEX do mastercard
Isso acontece porque o padrão desses cartões ELO realmente batem com o padrão da discover, porém por algum motivo a caixa registrou o BIN antes (não sei como funciona esses registros de BIN). Essas exceções já estão no regex da elo, podemos ver na parte "|6505[0-2][0-9]". Se jogarmos no bincheck.io inicialmente ele também da discover, mas se fizer o POST pra verificar ele irá retornar elo.
pra resolver podemos criar um switch e dar break antes para não continuar a verificação, e sempre verificar o ELO primeiro. Um exemplo em PHP$bandeira = match (1) { preg_match( '/^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^504175|^627780|^63(6297|6368|6369)|(65003[5-9]|65004[0-9]|65005[01])|(65040[5-9]|6504[1-3][0-9])|(65048[5-9]|65049[0-9]|6505[0-2][0-9]|65053[0-8])|(65054[1-9]|6505[5-8][0-9]|65059[0-8])|(65070[0-9]|65071[0-8])|(65072[0-7])|(65090[1-9]|6509[1-6][0-9]|65097[0-8])|(65165[2-9]|6516[67][0-9])|(65500[0-9]|65501[0-9])|(65502[1-9]|6550[34][0-9]|65505[0-8])|^(506699|5067[0-6][0-9]|50677[0-8])|^(509[0-8][0-9]{2}|5099[0-8][0-9]|50999[0-9])|^65003[1-3]|^(65003[5-9]|65004\d|65005[0-1])|^(65040[5-9]|6504[1-3]\d)|^(65048[5-9]|65049\d|6505[0-2]\d|65053[0-8])|^(65054[1-9]|6505[5-8]\d|65059[0-8])|^(65070\d|65071[0-8])|^65072[0-7]|^(65090[1-9]|65091\d|650920)|^(65165[2-9]|6516[6-7]\d)|^(65500\d|65501\d)|^(65502[1-9]|6550[3-4]\d|65505[0-8])/', $cartaoNumero ) => 'elo', preg_match('/^4[0-9]{12}(?:[0-9]{3})?/', $cartaoNumero) => 'visa', preg_match('/^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/', $cartaoNumero) => 'mastercard', preg_match('/^3[47][0-9]{13}/', $cartaoNumero) => 'amexs', preg_match('/^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})/', $cartaoNumero) => 'discover', preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}/', $cartaoNumero) => 'diners', preg_match('/^(?:2131|1800|35\d{3})\d{11}/', $cartaoNumero) => 'jcb', preg_match('/^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})/', $cartaoNumero) => 'hipercard', default => '' };
Agora todos os números vão bater corretamente!
Esta bandeira 5031433215406351 no bincheck.io deu que não existe, então pode ser retirada.Aparentemente está falhando para alguns ainda... Olha o resultado que eu tive:
Qual código você tá usando?
No meu exemplo em TypeScript funcionou todos os cartões
Eu pequei os cartões dessa resposta do @MMortari :
E usei os regex da última resposta, conforme o @gfucci colocou em sua resposta:
Aparentemente está falhando para alguns ainda... Olha o resultado que eu tive: