<?php | |
function is_valid_luhn($number) { | |
settype($number, 'string'); | |
$sumTable = array( | |
array(0,1,2,3,4,5,6,7,8,9), | |
array(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; | |
} |
Please be aware that this functions will only work if the passed argument is a string, else it will fail.
For more info read:
It has to do with 1 thing:
- Your platform (32 or 64 bit)
Be aware of this
Here is a simple implementation:
/**
* @see http://en.wikipedia.org/wiki/Luhn_algorithm
*/
private function checksum ($card_number) {
$card_number_checksum = '';
foreach (str_split(strrev((string) $card_number)) as $i => $d) {
$card_number_checksum .= $i %2 !== 0 ? $d * 2 : $d;
}
return array_sum(str_split($card_number_checksum)) % 10 === 0;
}
You can simply typecast whatever input you have into a string before applying it to the function or you could incorporate a step to first typecast your arguments into strings.
This function works perfectly if your number is already in a 16-character string, is_valid_luhn("4111111111111111")
But the function will fail if the string contains any symbols or spaces, is_valid_luhn("4111 1111 1111 1111")
= false
This can be easily fixed by placing a preg_replace at the beginning of the function to strip all non-digit characters.
$number = preg_replace("/[^0-9]/", "", $number);
PHP:
function isValid($num) {
$num = preg_replace('/[^\d]/', '', $num);
$sum = '';
for ($i = strlen($num) - 1; $i >= 0; -- $i) {
$sum .= $i & 1 ? $num[$i] : $num[$i] * 2;
}
return array_sum(str_split($sum)) % 10 === 0;
}
Javascript:
function isValid(number) {
var num = number.replace(/[^\d]/, '');
var str = '';
for (var i = num.length - 1; i >= 0; -- i) {
str += i & 1 ? num[i] : (parseInt(num[i]) * 2).toString();
}
var sum = str.split('').reduce(function(prev, current) {
return prev + parseInt(current);
}, 0);
return sum % 10 === 0;
};
//Using Luhn's algorithm to validate a credit card
public static function isValidCardNumber($number){
settype($number, 'string');
$number = preg_replace("/[^0-9]/", "", $number);
$numberChecksum= '';
$reversedNumberArray = str_split(strrev($number));
foreach ($reversedNumberArray as $i => $d) {
$numberChecksum.= (($i % 2) !== 0) ? (string)((int)$d * 2) : $d;
}
$sum = array_sum(str_split($numberChecksum));
return ($sum % 10) === 0;
}
is there any possibility to get bpay biller address and info by biller code?
@mikemirten first I thought thats really small and simple to understand but unfortunately it's wrong. have you tried this with a credit card number of odd length? visas can have 13 - 16 numbers and that fails.
my solution is now:
function validateLuhn(string $number): bool
{
$sum = 0;
$revNumber = strrev($number);
$len = strlen($number);
for ($i = 0; $i < $len; $i++) {
$sum += $i & 1 ? ($revNumber[$i] > 4 ? $revNumber[$i] * 2 - 9 : $revNumber[$i] * 2) : $revNumber[$i];
}
return $sum % 10 === 0;
}
@mogzol: you are right: the string sum does not make sense... So I removed it.
edit fixed the calculation without string split and unused variables
Alternative version of @tflori's code that doesn't rely on strrev, array_sum or str_split, which makes it more readable IMO, and slightly faster (though at this point it's basically just the original code without the sum table):
function validateLuhn(string $number): bool
{
$sum = 0;
$flag = 0;
for ($i = strlen($number) - 1; $i >= 0; $i--) {
$add = $flag++ & 1 ? $number[$i] * 2 : $number[$i];
$sum += $add > 9 ? $add - 9 : $add;
}
return $sum % 10 === 0;
}
@tflori Your updated code doesn't work just FYI. You actually did need the array_sum. This is because of the first step outlined here: https://en.wikipedia.org/wiki/Luhn_algorithm#Description
If the result of this doubling operation is greater than 9 (e.g., 8 × 2 = 16), then add the digits of the result (e.g., 16: 1 + 6 = 7, 18: 1 + 8 = 9)
Your original code achieved this by using a string and summing all the numbers in the string. My code uses the alternate method mentioned:
alternatively, the same final result can be found by subtracting 9 from that result (e.g., 16: 16 − 9 = 7, 18: 18 − 9 = 9)
But your newly edited code does neither, and as such returns false for many valid numbers.
@mogzol ah f**k.. thanks for the info
rainysia commentedAug 27, 2012