Digitizer Posted August 31, 2014 Share Posted August 31, 2014 (edited) 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 August 31, 2014 by Digitizer Quote Link to comment Share on other sites More sharing options...
Digitizer Posted August 31, 2014 Author Share Posted August 31, 2014 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?? Quote Link to comment Share on other sites More sharing options...
Solution Barand Posted August 31, 2014 Solution Share Posted August 31, 2014 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>'; Quote Link to comment Share on other sites More sharing options...
Digitizer Posted August 31, 2014 Author Share Posted August 31, 2014 Thanks mate I appreciate your help... Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted August 31, 2014 Share Posted August 31, 2014 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. Quote Link to comment Share on other sites More sharing options...
Digitizer Posted August 31, 2014 Author Share Posted August 31, 2014 (edited) 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 August 31, 2014 by Digitizer Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted September 1, 2014 Share Posted September 1, 2014 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; Quote Link to comment Share on other sites More sharing options...
Digitizer Posted September 2, 2014 Author Share Posted September 2, 2014 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 Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted September 2, 2014 Share Posted September 2, 2014 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.