This is a class to help with credit card validation. Most merchant accounts charge you a fee when a card is declined. This class will make sure the CC# is compatible with the account# it is associated with. IE: 123456 will NOT check out under the Visa guide lines. This class won’t approve/deny CC#'s, but it WILL make sure the CC# is valid.
<?php
class CCValidate
{
/**
* An array to hold the valid prefixes and
* valid lengths for various credit cards.
*/
private $card_specs = array(
'Master Card' => array(
'prefixes' => array(
51,
52,
53,
54,
55
),
'lengths' => array(
16
)
),
'Visa' => array(
'prefixes' => array(
4
),
'lengths' => array(
13,
16
)
),
'American Express' => array(
'prefixes' => array(
34,
37
),
'lengths' => array(
15
)
),
// Adding a duplicate entry under the abbreviated name just to make it easier for some people
'AMEX' => array(
'prefixes' => array(
34,
37
),
'lengths' => array(
15
)
),
'Diners Club' => array(
'prefixes' => array(
300,
301,
302,
303,
304,
305,
36,
38
),
'lengths' => array(
14
)
),
// Another name for Diners Club
'Carte Blanche' => array(
'prefixes' => array(
300,
301,
302,
303,
304,
305,
36,
38
),
'lengths' => array(
14
)
),
// Who the hell still uses Discover?
'Discover' => array(
'prefixes' => array(
6011
),
'lengths' => array(
16
)
),
'enRoute' => array(
'prefixes' => array(
2014,
2149
),
'lengths' => array(
15
)
)
);
private $card_type;
private $card_number;
public function __construct() { }
/**
* Main function to validate a CC#
*/
public function validateNumber($card_type, $card_number)
{
$this->card_type = $card_type;
$this->card_number = $card_number;
if (!isset($this->card_specs[$this->card_type])) {
return "'{$this->card_type}' is an unknown card type.";
}
// Remove any non-digit characters
$this->card_number = preg_replace('/\\D/', '', $this->card_number);
if ($this->card_number == '') { // Must have had no digits in the "number"
return false;
}
if (!$this->checkPrefix()) { return false; }
if (!$this->checkLength()) { return false; }
if (!$this->checkAlgorithm()) { return false; }
return true;
}
/**
* Checks to make sure the CC# has one of the valid prefixes for that card type.
*/
private function checkPrefix()
{
$valid_prefixes = $this->card_specs[$this->card_type]['prefixes'];
foreach ($valid_prefixes as $prefix)
{
if (substr($this->card_number, 0, strlen($prefix)) == $prefix) { return true; }
}
return false;
}
/**
* Makes sure the CC# length is one of the valid lengths for that card type.
*/
private function checkLength()
{
$valid_lengths = $this->card_specs[$this->card_type]['lengths'];
foreach ($valid_lengths as $length)
{
if (strlen($this->card_number) == $length) { return true; }
}
return false;
}
/**
* Makes sure the entire number is a valid account number format.
*
* First start from the right side of the number and multiply each
* number by 2 -- skipping the right most digit and starting from the second to last.
* If the product has more than one digit, that product will become the sum of it's digits.
* IE: if the product is 18, that product will become 9 (1+8).
* Then, starting from the left of the CC#, add the corrosponding products to the CC digits that
* you did not multiply earlier. Then add all the resulting sums. The result should be divisible by 10
* with no remainder for valid CC#s. Otherwise, it's an invalid number and is guaranteed to be denied.
*/
private function checkAlgorithm()
{
$sums = array();
$num = $this->card_number;
// Create an array with each key containing one of the CC# digits
// Reverse it to make it easier to work "right to left" on each digits.
$each_num = array_reverse(str_split($num));
foreach ($each_num as $index => $number)
{
// Skip the first digit and start with the next and every other one from there
if ($index % 2) {
$result = 0;
$product = $number * 2; // Multiply by two
$product = str_split($product); // Separate each digit
foreach ($product as $digit)
{
$result += $digit; // Add individual digits to each other if there is more than one
}
$sums[] = $result;
unset($each_num[$index]); // Remove this CC# digit from the array making it easier to tell which digits to use in the next step.
}
}
$result = 0;
// Reverse the resulting sums and the array containing the CC digits so it's easier to work "left to right" this time.
$sums = array_reverse($sums);
$each_num = array_reverse($each_num);
foreach ($each_num as $key => $val)
{
// Add the digit to the sum from the prev step to the total so far
$result += $val + $sums[$key];
}
// Check to see if the result is divisable by 10 with no remainder
if (($result != 0) && ($result % 10 == 0)) {
return true;
}
return false;
}
}