Categories: Para não esquecerPHP

Função para validar cartões de crédito com detecção automática da bandeira

Função para validar cartões de crédito, com suporte a validação de CVC.

O primeiro parâmetro é o número do cartão e o segundo o CVC (opcional), os dados serão sanitizados, sendo filtrado somente os números.

A saida é um array de três posições, a primeira retorna false (em caso de erro) ou a bandeira, a segunda se o número do cartão é válido e a terceira se o CVC é válido.

 

/**
 * @author Felipe Braz
 * @website https://braz.dev/blog
 * @param int $cartao
 * @param int $cvc
 * @return array
 */
function valida_cartao($cartao, $cvc=false){
	$cartao = preg_replace("/[^0-9]/", "", $cartao);
	if($cvc) $cvc = preg_replace("/[^0-9]/", "", $cvc);

	$cartoes = array(
			'visa'		 => array('len' => array(13,16),    'cvc' => 3),
			'mastercard' => array('len' => array(16),       'cvc' => 3),
			'diners'	 => array('len' => array(14,16),    'cvc' => 3),
			'elo'		 => array('len' => array(16),       'cvc' => 3),
			'amex'	 	 => array('len' => array(15),       'cvc' => 4),
			'discover'	 => array('len' => array(16),       'cvc' => 4),
			'aura'		 => array('len' => array(16),       'cvc' => 3),
			'jcb'		 => array('len' => array(16),       'cvc' => 3),
			'hipercard'  => array('len' => array(13,16,19), 'cvc' => 3),
	);

	
	switch($cartao){
		case (bool) preg_match('/^(636368|438935|504175|451416|636297)/', $cartao) :
			$bandeira = 'elo';			
		break;

		case (bool) preg_match('/^(606282)/', $cartao) :
			$bandeira = 'hipercard';			
		break;

		case (bool) preg_match('/^(5067|4576|4011)/', $cartao) :
			$bandeira = 'elo';			
		break;

		case (bool) preg_match('/^(3841)/', $cartao) :
			$bandeira = 'hipercard';			
		break;

		case (bool) preg_match('/^(6011)/', $cartao) :
			$bandeira = 'discover';			
		break;

		case (bool) preg_match('/^(622)/', $cartao) :
			$bandeira = 'discover';			
		break;

		case (bool) preg_match('/^(301|305)/', $cartao) :
			$bandeira = 'diners';			
		break;

		case (bool) preg_match('/^(34|37)/', $cartao) :
			$bandeira = 'amex';			
		break;

		case (bool) preg_match('/^(36,38)/', $cartao) :
			$bandeira = 'diners';			
		break;

		case (bool) preg_match('/^(64,65)/', $cartao) :
			$bandeira = 'discover';			
		break;

		case (bool) preg_match('/^(50)/', $cartao) :
			$bandeira = 'aura';			
		break;

		case (bool) preg_match('/^(35)/', $cartao) :
			$bandeira = 'jcb';			
		break;

		case (bool) preg_match('/^(60)/', $cartao) :
			$bandeira = 'hipercard';			
		break;

		case (bool) preg_match('/^(4)/', $cartao) :
			$bandeira = 'visa';			
		break;

		case (bool) preg_match('/^(5)/', $cartao) :
			$bandeira = 'mastercard';			
		break;
	}

	$dados_cartao = $cartoes[$bandeira];
	if(!is_array($dados_cartao)) return array(false, false, false);

	$valid     = true;
	$valid_cvc = false;

	if(!in_array(strlen($cartao), $dados_cartao['len'])) $valid = false;
	if($cvc AND strlen($cvc) <= $dados_cartao['cvc'] AND strlen($cvc) !=0) $valid_cvc = true;
	return array($bandeira, $valid, $valid_cvc);
}

Ah, a minha esposa queria que eu botasse nesse post uma foto de gatinho, então lá vai:

Fonte: https://gist.github.com/erikhenrique/5931368

Felipe Braz

View Comments

    • Passa o número do cartão sem traços como primeiro parâmetro na função.
      Ele retorna um array aonde na primeira posição tem a string com a bandeira.

  • Obrigado por compartilhar ! Você cogitou fazer a verificação do checksum dos dígitos do cartão também ? Caso afirmativo, poderia me dizer por que achou melhor não incluir essa verificação ?

    • Olá Francisco, eu que agradeço por visitar o meu blog, espero que a informação tenha lhe sido útil.

      Quando eu fiz essa função, o objetivo era somente detectar a bandeira mesmo, deste modo acabei não precisando fazer a validação do checksum.

      Pelo que eu li essa validação usa o algoritimo luhn, talvez essa função possa servir.

      function luhnCheck($number)
      {
      $checksum = 0;
      for ($i=(2-(strlen($number) % 2)); $i<=strlen($number); $i+=2) {
      $checksum += (int) ($number{$i-1});
      }
      // Analyze odd digits in even length strings or even digits in odd length strings.
      for ($i=(strlen($number)% 2) + 1; $i<strlen($number); $i+=2) {
      $digit = (int) ($number{$i-1}) * 2;
      if ($digit < 10) {
      $checksum += $digit;
      } else {
      $checksum += ($digit-9);
      }
      }
      if (($checksum % 10) == 0) {
      return true;
      } else {
      return false;
      }
      }

      Se funcionar, só peço o favor de me avisar que eu atualizo o post no blog =D

Recent Posts

Como Criar Rede Wi-Fi de Visitante em Roteadores Ax3000t com OpenWRT

Depois que comprei os roteadores ax3000t e finalmente consegui instalar o openwrt neles. Agora chegou…

3 meses ago

Como criar e validar credenciais seguras em Ansible sem dor de cabeça – Guia passo a passo

A criação e validação de credenciais seguras em ansible sempre gera um pouco de dor…

2 anos ago

Magento e o mistério do servidor somente-leitura

Dia desses, um dos meus servidores entrou com o sistema de arquivos / em modo…

5 anos ago

Localização de arquivos .desktop no ubuntu

O launcher do ubuntu não fornece muitas opções me relação aos icones, muitas vezes apps…

5 anos ago

Ordenar array por tamanho em php

Três meios diferentes para a mesma finalidade: Usando funções nativas do PHP (recomendado): array_multisort(array_map('strlen', $array),…

6 anos ago

Adicionar suporte a rc.local no ubuntu 16.04 ou superior

Embora um script muito útil para tarefas de inicialização de um servidor, essa funcionalidade se…

6 anos ago