<?php
namespace CodeIgniter\Validation;
class CreditCardRules
{
protected $cards = [
'American Express' => [
'name' => 'amex',
'length' => '15',
'prefixes' => '34,37',
'checkdigit' => true,
],
'China UnionPay' => [
'name' => 'unionpay',
'length' => '16,17,18,19',
'prefixes' => '62',
'checkdigit' => true,
],
'Dankort' => [
'name' => 'dankort',
'length' => '16',
'prefixes' => '5019,4175,4571,4',
'checkdigit' => true,
],
'DinersClub' => [
'name' => 'dinersclub',
'length' => '14,16',
'prefixes' => '300,301,302,303,304,305,309,36,38,39,54,55',
'checkdigit' => true,
],
'DinersClub CarteBlanche' => [
'name' => 'carteblanche',
'length' => '14',
'prefixes' => '300,301,302,303,304,305',
'checkdigit' => true,
],
'Discover Card' => [
'name' => 'discover',
'length' => '16,19',
'prefixes' => '6011,622,644,645,656,647,648,649,65',
'checkdigit' => true,
],
'InterPayment' => [
'name' => 'interpayment',
'length' => '16,17,18,19',
'prefixes' => '4',
'checkdigit' => true,
],
'JCB' => [
'name' => 'jcb',
'length' => '16,17,18,19',
'prefixes' => '352,353,354,355,356,357,358',
'checkdigit' => true,
],
'Maestro' => [
'name' => 'maestro',
'length' => '12,13,14,15,16,18,19',
'prefixes' => '50,56,57,58,59,60,61,62,63,64,65,66,67,68,69',
'checkdigit' => true,
],
'MasterCard' => [
'name' => 'mastercard',
'length' => '16',
'prefixes' => '51,52,53,54,55,22,23,24,25,26,27',
'checkdigit' => true,
],
'NSPK MIR' => [
'name' => 'mir',
'length' => '16',
'prefixes' => '2200,2201,2202,2203,2204',
'checkdigit' => true,
],
'Troy' => [
'name' => 'troy',
'length' => '16',
'prefixes' => '979200,979289',
'checkdigit' => true,
],
'UATP' => [
'name' => 'uatp',
'length' => '15',
'prefixes' => '1',
'checkdigit' => true,
],
'Verve' => [
'name' => 'verve',
'length' => '16,19',
'prefixes' => '506,650',
'checkdigit' => true,
],
'Visa' => [
'name' => 'visa',
'length' => '13,16,19',
'prefixes' => '4',
'checkdigit' => true,
],
'BMO ABM Card' => [
'name' => 'bmoabm',
'length' => '16',
'prefixes' => '500',
'checkdigit' => false,
],
'CIBC Convenience Card' => [
'name' => 'cibc',
'length' => '16',
'prefixes' => '4506',
'checkdigit' => false,
],
'HSBC Canada Card' => [
'name' => 'hsbc',
'length' => '16',
'prefixes' => '56',
'checkdigit' => false,
],
'Royal Bank of Canada Client Card' => [
'name' => 'rbc',
'length' => '16',
'prefixes' => '45',
'checkdigit' => false,
],
'Scotiabank Scotia Card' => [
'name' => 'scotia',
'length' => '16',
'prefixes' => '4536',
'checkdigit' => false,
],
'TD Canada Trust Access Card' => [
'name' => 'tdtrust',
'length' => '16',
'prefixes' => '589297',
'checkdigit' => false,
],
];
public function valid_cc_number(string $ccNumber = null, string $type, array $data): bool
{
$type = strtolower($type);
$info = null;
foreach ($this->cards as $card)
{
if ($card['name'] === $type)
{
$info = $card;
break;
}
}
if (empty($info))
{
return false;
}
if (strlen($ccNumber) === 0)
{
return false;
}
$ccNumber = str_replace([' ', '-'], '', $ccNumber);
if (! is_numeric($ccNumber))
{
return false;
}
$lengths = explode(',', $info['length']);
if (! in_array(strlen($ccNumber), $lengths))
{
return false;
}
$prefixes = explode(',', $info['prefixes']);
$validPrefix = false;
foreach ($prefixes as $prefix)
{
if (strpos($ccNumber, $prefix) === 0)
{
$validPrefix = true;
break;
}
}
if ($validPrefix === false)
{
return false;
}
if ($info['checkdigit'] === true)
{
return $this->isValidLuhn($ccNumber);
}
return true;
}
protected function isValidLuhn(string $number = null): bool
{
settype($number, 'string');
$sumTable = [
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
],
[
0,
2,
4,
6,
8,
1,
3,
5,
7,
9,
],
];
$sum = 0;
$flip = 0;
for ($i = strlen($number) - 1; $i >= 0; $i --)
{
$sum += $sumTable[$flip ++ & 0x1][$number[$i]];
}
return $sum % 10 === 0;
}
}