Jump to content

luhn Algorithm - need little hand here plz


Go to solution Solved by Barand,

Recommended Posts

Hello Guys,

You  might have known about Luhn Algorithm, which is used to get checksum of IMEI of phones, credit cards etc etc. It is a public domain so it is not used for security but to ensure that client has passed the correct numbers etc etc.

 

Anyway, I am trying to get my hands on this algorithm and I will build a logic based on luhn algo to get the checksum, where I am stuck is how can I get the alternate numbers from a numeric string, for example I have written the following code to get all the numbers one by one into the array.

$imei = "356565451265856";
$lenOfStr= strlen($imei);
$myArray = array();

//Get all numbers one by one in array
for($i=0; $i < $lenOfStr; $i++){
  $myArray[] = substr($imei,$i,1);
}

// Checking the array
foreach($myArray as $seperatedNumbers){
  echo $seperatedNumbers;
}

No the problem is that I want to select every 2nd number from right to left e-g 5,5,2,... or 6,8,6

How can I get it done?

 

This logic may not be so good, there may be more brilliant solutions to write luhn algo, but I want to try myself once... 

 

Thanks.

Edited by Digitizer

ok, I cannot edit the post now, so this is a little solution I have come up with, getting the alternate numbers into another array using modulus.

$imei = "356565451265856";
$lenOfString = strlen($imei);
$myArray = array();
$alternateArray = array();
for($i=0;$i<$lenOfString;$i++){
	$myArray[] = substr($imei,$i,1);
}
foreach($myArray as $key => $value){
	
  if($key % 2 == 0){
  $alternateArray[] = $value;
  }
}


print_r($alternateArray); //Array will get 36641686

So if there was a more convinient solution? if I can get such numbers from $imei directly??

  • Solution

one way

$imei = "356565451265856";
$odd = $even = array();
$arr = str_split($imei);

foreach ($arr as $k => $v) {
    if ($k%2) {
        $odd[] = $v;
    }
    else {
        $even[] = $v;
    }
}
echo '<pre>',print_r($odd, true),'</pre>';

Why use arrays? How does this help?

 

Simply add the digits in one loop with an if statement. The logic works like this:

  • Loop through the digits from left to right (or right to left, it doesn't matter).
  • If the total number of digits is even, double all digits with an even index (the first index is 0 as usual).
  • If the total number of digits is odd, double all digits with an odd index.
  • If doubling makes the number two-digit, subtract 9.
  • Add the resulting number to a sum.

Thanks for the tip @Jacques1, I am now going to try this as well, Its not about what the logic is about, what i am trying to do is to get the solution as simple way as possible.

 

So I am going to try with different logics making it as short as possible, so I have completed first solution, as follows,

if(isset($_POST['submitIMEI'])){
	$imei = $_POST['imei'];
	$odd = $even = array();
	$arr = str_split($imei);
	$oddFinal = array(); // Will hold addition of odd indexed numbers

	foreach ($arr as $k => $v) {if ($k%2) {$odd[] = $v*2;}else {$even[] = $v;}}

	// Add all 2 Numbered digits to make them 1 digit
	foreach($odd as $sepNo){
		$first = substr($sepNo,0,1);
		$second = substr($sepNo,1,1);
		$total = $first+$second;
		$oddFinal[] = $total;
	}
	$oddSum = array_sum($oddFinal);
	$evenSum = array_sum($even);
	$totalAll = $oddSum+$evenSum;
	$totalFinal = $totalAll*9;
	$imeiSV = substr($totalFinal,2,1);
	
	echo "IMEI: " . $imei . "<br>";
	echo "ChkSum: " . $imeiSV . "<hr>";
}

echo ("
	<form name='imei' method='post' action='#'>
		<input type='text' name='imei' placeholder='IMEI' />
		<input type='submit' name='submitIMEI' />
	</form>
");

I understand the style of writing may be very non professional, if it is so, I humbly request to please point out the mistakes I have done, this will be a great help for me to get me better on writing.

Edited by Digitizer

This implementation is actually incorrect. You somehow forgot about the “right to left” part, even if you've mentioned it in the original question. And when you try to extract the last digit, for some reason you assume that $totalFinal always has exactly three digits.

 

It's important that “doubling every second digit” refers to the direction from right to left. So if the input is “123”, then you'd double 1 and 3 (all even indexes). If the input is “1234”, then you'd double 2 and 4 (all odd indexes). What you do instead is always double all odd indexes. This only works if the input has an even length.

<?php

$input = '7992739871';


$sum = 0;
for ($i = 0; $i < strlen($input); $i++)
{
	$digit = $input[$i];

	/*
	 * If the input length is even, we need to double all digits with an odd
	 * index. If the input length is odd, we need to double all digits with an
	 * even index. In other words, we double those digits where the remainder
	 * of $i ÷ 2 is different from the remainder of strlen($input) ÷ 2.
	 */
	if ($i % 2 != strlen($input) % 2)
	{
		$digit *= 2;

		// Instead of calculating the sum of the digits, you can just subtract 9.
		if ($digit > 9)
			$digit -= 9;
	}

	$sum += $digit;
}

echo $sum;

Then you multiply by 9 and get the last digit. The easiest way to get the last digit is to calculate the remainder of the division by 10:

$checkdigit = ($sum * 9) % 10;

Hello,

sorry for late reply, I have been busy yesterday.

 

Well, as you pointed out, the checksum actually changed from LTR/RTL ... didnt notice.. lolz..

 

As luhn Algo says, After all the adittion/multiplication etc, you will come up with 2 digits which you will need to either,

 

1. Multiple by 9 (it will always give you 3 digits - and last digit is checksum) (e-g 45, 45*9 = 405, [5 is checksum])

2. From those 2 digits, subtract the last from 10 and you will be left with 1 digit, which is check sum. (e-g 45, [10-5],[5 is checksum])

 

I used the first logic. And with your writen algo, I am going to try this too :)

 

Lemme get back to you on this mate

Who says multiplying the sum always gives you 3 digits? That may be true if you only deal with a specific set of input numbers (which one?), but it's obviously not the case for the generic algorithm. Just take the input "9999999999999". That gives you the sum 117. Multipliying the result with 9 yields 1053 which has four digits.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.