Saltar al contenido

Pruebas de número de tarjeta de crédito Regex

Nuestro equipo redactor ha estado por horas investigando para darle soluciones a tu interrogante, te regalamos la resolución de modo que nuestro objetivo es serte de mucha apoyo.

Solución:

Expresiones regulares de proveedores de tarjetas de crédito comunes:

  • Tarjeta Amex: ^3[47][0-9]13$
  • BCGlobal: ^(6541|6556)[0-9]12$
  • Tarjeta Carte Blanche: ^389[0-9]11$
  • Tarjeta Diners Club: ^3(?:0[0-5]|[68][0-9])[0-9]11$
  • Descubrir tarjeta: ^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)$
  • Tarjeta de pago Insta: ^63[7-9][0-9]13$
  • Tarjeta JCB: ^(?:2131|1800|35d3)d11$
  • KoreanLocalCard: ^9[0-9]15$
  • Tarjeta láser: ^(6304|6706|6709|6771)[0-9]12,15$
  • Tarjeta Maestro: ^(5018|5020|5038|6304|6759|6761|6763)[0-9]8,15$
  • Tarjeta MasterCard: ^(5[1-5][0-9]14|2(22[1-9][0-9]12|2[3-9][0-9]13|[3-6][0-9]14|7[0-1][0-9]13|720[0-9]12))$
  • Tarjeta Solo: ^(6334|6767)[0-9]12|(6334|6767)[0-9]14|(6334|6767)[0-9]15$
  • Cambiar tarjeta: ^(4903|4905|4911|4936|6333|6759)[0-9]12|(4903|4905|4911|4936|6333|6759)[0-9]14|(4903|4905|4911|4936|6333|6759)[0-9]15|564182[0-9]10|564182[0-9]12|564182[0-9]13|633110[0-9]10|633110[0-9]12|633110[0-9]13$
  • Tarjeta Union Pay: ^(62[0-9]14,17)$
  • Tarjeta Visa: ^4[0-9]12(?:[0-9]3)?$
  • Visa Mastercard: ^(?:4[0-9]12(?:[0-9]3)?|5[1-5][0-9]14)$

Eliminar todo , y - y otros no dígitos del string primero.

Luego, use esta expresión regular que coincida con las tarjetas Visa, MasterCard, American Express, Diners Club, Discover y JCB:

^(?:4[0-9]12(?:[0-9]3)?|[25][1-7][0-9]14|6(?:011|5[0-9][0-9])[0-9]12|3[47][0-9]13|3(?:0[0-5]|[68][0-9])[0-9]11|(?:2131|1800|35d3)d11)$

2019

HACER. NO. USAR. REGEX !!! (con 3 signos de exclamación)


De los comentarios debo destacar PeteWiFicomentario de:

Solo una advertencia amistosa, te espera un mundo de dolor si intentas combinar esquemas específicos y longitudes de cartas de esta manera. Por ejemplo, Switch no existe desde 2002, Laser se retiró en 2014, Visa debe emitir tarjetas de 19 dígitos y MasterCard ahora está emitiendo en los rangos 2xxxxx, solo para resaltar un par de problemas con este enfoque. Una expresión regular es buena para un básico “¿parece un número de tarjeta?”, Pero no mucho más allá de eso.

Si desea utilizar expresiones regulares solo para conocer la marca de la tarjeta para uso visual (como mostrar el logotipo o la etiqueta de Visa), está bien. Pero si la lógica de su código depende de ello, ¡no use expresiones regulares y no use complementos / bibliotecas de terceros!

Regex detectar números de tarjetas es rápido y fácil (¡muy atractivo, lo sé!). Pero, a la larga, su proyecto se encontrará con muchos errores graves y difíciles de resolver. Los emisores de tarjetas siguen introduciendo nuevos patrones de números de tarjetas, o retiran los antiguos, o pueden cerrar por completo. Quién sabe.


Solución

Cree su propia solución (preferiblemente sin expresiones regulares) basada en algunas páginas oficiales que se actualizan con frecuencia, como esta página en wikipedia.

En cuanto al “-“, “.”, “Espacio” y todos los demás ruidos, simplemente elimine todos estos que no son dígitos, puede usar esto (Basado en esta respuesta):

$number = preg_replace("/[^0-9]/", "", "4111-1111 1111.1111");
// Output: 4111111111111111

¿Aún no estás convencido?

Esta la página va en detalles técnicos profundos por qué las expresiones regulares son un infierno. (Fíjate que el artical usó la palabra “infierno” porque una vez que estás dentro no puedes salir)

EDITAR

Aquí hay una solución que desarrollé (en PHP):

// Based on https://en.wikipedia.org/wiki/Payment_card_number
// This constant is used in get_card_brand()
// Note: We're not using regex anymore, with this approach way we can easily read/write/change bin series in this array for future changes
// Key     (string)           brand, keep it unique in the array
// Value   (array)            for each element in the array:
//   Key   (string)           prefix of card number, minimum 1 digit maximum 6 digits per prefix. You can use "dash" for range. Example: "34" card number starts with 34. Range Example: "34-36" (which means first 6 digits starts with 340000-369999) card number starts with 34, 35 or 36
//   Value (array of strings) valid length of card number. You can set multiple ones. You can also use "dash" for range. Example: "16" means length must be 16 digits. Range Example: "15-17" length must be 15, 16 or 17. Multiple values example: ["12", "15-17"] card number can be 12 or 15 or 16 or 17 digits
define('CARD_NUMBERS', [
    'american_express' => [
        '34' => ['15'],
        '37' => ['15'],
    ],
    'diners_club' => [
        '36'      => ['14-19'],
        '300-305' => ['16-19'],
        '3095'    => ['16-19'],
        '38-39'   => ['16-19'],
    ],
    'jcb' => [
        '3528-3589' => ['16-19'],
    ],
    'discover' => [
        '6011'          => ['16-19'],
        '622126-622925' => ['16-19'],
        '624000-626999' => ['16-19'],
        '628200-628899' => ['16-19'],
        '64'            => ['16-19'],
        '65'            => ['16-19'],
    ],
    'dankort' => [
        '5019' => ['16'],
        //'4571' => ['16'],// Co-branded with Visa, so it should appear as Visa
    ],
    'maestro' => [
        '6759'   => ['12-19'],
        '676770' => ['12-19'],
        '676774' => ['12-19'],
        '50'     => ['12-19'],
        '56-69'  => ['12-19'],
    ],
    'mastercard' => [
        '2221-2720' => ['16'],
        '51-55'     => ['16'],
    ],
    'unionpay' => [
        '81' => ['16'],// Treated as Discover cards on Discover network
    ],
    'visa' => [
        '4' => ['13-19'],// Including related/partner brands: Dankort, Electron, etc. Note: majority of Visa cards are 16 digits, few old Visa cards may have 13 digits, and Visa is introducing 19 digits cards
    ],
]);

/**
 * Pass card number and it will return brand if found
 * Examples:
 *     get_card_brand('4111111111111111');                    // Output: "visa"
 *     get_card_brand('4111.1111 1111-1111');                 // Output: "visa" function will remove following noises: dot, space and dash
 *     get_card_brand('411111######1111');                    // Output: "visa" function can handle hashed card numbers
 *     get_card_brand('41');                                  // Output: "" because invalid length
 *     get_card_brand('41', false);                           // Output: "visa" because we told function to not validate length
 *     get_card_brand('987', false);                          // Output: "" no match found
 *     get_card_brand('4111 1111 1111 1111 1111 1111');       // Output: "" no match found
 *     get_card_brand('4111 1111 1111 1111 1111 1111', false);// Output: "visa" because we told function to not validate length
 * Implementation Note: This function doesn't use regex, instead it compares digit by digit. 
 *                      Because we're not using regex in this function, it's easier to add/edit/delete new bin series to global constant CARD_NUMBERS
 * Performance Note: This function is extremely fast, less than 0.0001 seconds
 * @param  String|Int $cardNumber     (required) Card number to know its brand. Examples: 4111111111111111 or 4111 1111-1111.1111 or 411111###XXX1111
 * @param  Boolean    $validateLength (optional) If true then will check length of the card which must be correct. If false then will not check length of the card. For example you can pass 41 with $validateLength = false still this function will return "visa" correctly
 * @return String                                returns card brand if valid, otherwise returns empty string
 */
function get_card_brand($cardNumber, $validateLength = true) 
    $foundCardBrand = '';

    $cardNumber = (string)$cardNumber;
    $cardNumber = str_replace(['-', ' ', '.'], '', $cardNumber);// Trim and remove noise

    if(in_array(substr($cardNumber, 0, 1), ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])) // Try to find card number only if first digit is a number, if not then there is no need to check
        $cardNumber = preg_replace('/[^0-9]/', '0', $cardNumber);// Set all non-digits to zero, like "X" and "#" that maybe used to hide some digits
        $cardNumber = str_pad($cardNumber, 6, '0', STR_PAD_RIGHT);// If $cardNumber passed is less than 6 digits, will append 0s on right to make it 6

        $firstSixDigits   = (int)substr($cardNumber, 0, 6);// Get first 6 digits
        $cardNumberLength = strlen($cardNumber);// Total digits of the card

        foreach(CARD_NUMBERS as $brand => $rows) 
            foreach($rows as $prefix => $lengths) 
                $prefix    = (string)$prefix;
                $prefixMin = 0;
                $prefixMax = 0;
                if(strpos($prefix, '-') !== false) // If "dash" exist in prefix, then this is a range of prefixes
                    $prefixArray = explode('-', $prefix);
                    $prefixMin = (int)str_pad($prefixArray[0], 6, '0', STR_PAD_RIGHT);
                    $prefixMax = (int)str_pad($prefixArray[1], 6, '9', STR_PAD_RIGHT);
                 else // This is fixed prefix
                    $prefixMin = (int)str_pad($prefix, 6, '0', STR_PAD_RIGHT);
                    $prefixMax = (int)str_pad($prefix, 6, '9', STR_PAD_RIGHT);
                

                $isValidPrefix = $firstSixDigits >= $prefixMin && $firstSixDigits <= $prefixMax;// Is string starts with the prefix

                if($isValidPrefix && !$validateLength) 
                    $foundCardBrand = $brand;
                    break 2;// Break from both loops
                
                if($isValidPrefix && $validateLength) 
                    foreach($lengths as $length) 
                        $isValidLength = false;
                        if(strpos($length, '-') !== false) // If "dash" exist in length, then this is a range of lengths
                            $lengthArray = explode('-', $length);
                            $minLength = (int)$lengthArray[0];
                            $maxLength = (int)$lengthArray[1];
                            $isValidLength = $cardNumberLength >= $minLength && $cardNumberLength <= $maxLength;
                         else // This is fixed length
                            $isValidLength = $cardNumberLength == (int)$length;
                        
                        if($isValidLength) 
                            $foundCardBrand = $brand;
                            break 3;// Break from all 3 loops
                        
                    
                
            
        
    

    return $foundCardBrand;

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *