/** * Validates a credit card number using the Luhn (mod10) formula. * @see http://en.wikipedia.org/wiki/Luhn_algorithm * * @param integer credit card number * @param string|array card type, or an array of card types * @return boolean */ public static function credit_card($number, $type = NULL) { // Remove all non-digit characters from the number if (($number = preg_replace('/\\D+/', '', $number)) === '') { return FALSE; } if ($type == NULL) { // Use the default type $type = 'default'; } elseif (is_array($type)) { foreach ($type as $t) { // Test each type for validity if (Valid::credit_card($number, $t)) { return TRUE; } } return FALSE; } $cards = Valid::cards_config(); // Check card type $type = strtolower($type); if (!isset($cards[$type])) { return FALSE; } // Check card number length $length = strlen($number); // Validate the card length by the card type if (!in_array($length, preg_split('/\\D+/', $cards[$type]['length']))) { return FALSE; } // Check card number prefix if (!preg_match('/^' . $cards[$type]['prefix'] . '/', $number)) { return FALSE; } // No Luhn check required if ($cards[$type]['luhn'] == FALSE) { return TRUE; } // Checksum of the card number $checksum = 0; for ($i = $length - 1; $i >= 0; $i -= 2) { // Add up every 2nd digit, starting from the right $checksum += substr($number, $i, 1); } for ($i = $length - 2; $i >= 0; $i -= 2) { // Add up every 2nd digit doubled, starting from the right $double = substr($number, $i, 1) * 2; // Subtract 9 from the double where value is greater than 10 $checksum += $double >= 10 ? $double - 9 : $double; } // If the checksum is a multiple of 10, the number is valid return $checksum % 10 === 0; }