CONTRÔLE DE LA CONFORMITÉ D'UN NUMÉRO DE CARTE BANCAIRE (ALGORITHME DE LUHN)

Messages postés
8
Date d'inscription
jeudi 3 août 2006
Statut
Membre
Dernière intervention
18 février 2009
- - Dernière réponse : verdy_p
Messages postés
203
Date d'inscription
vendredi 27 janvier 2006
Statut
Membre
Dernière intervention
29 janvier 2019
- 17 févr. 2009 à 11:11
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/49262-controle-de-la-conformite-d-un-numero-de-carte-bancaire-algorithme-de-luhn

Afficher la suite 
fs074995
Messages postés
8
Date d'inscription
jeudi 3 août 2006
Statut
Membre
Dernière intervention
18 février 2009
-
Bonjour
Mais pourquoi faire compliqué si cela peut être simple
origine: wiki alogarithme de luhn

01.//Fonction algorithme de Luhn
02.function isLuhnNum($num){
03. //longueur de la chaine $num
04. $length = strlen($num);
05. //resultat de l'addition de tous les chiffres
06. $tot = 0;
07. for($i=$length-1;$i>=0;$i--)
08. {
09. $digit = substr($num, $i, 1);
10. if ((($length - $i) / 2) == 0){
11. $digit = $digit*2;
12. if ($digit>9){
13. $digit = $digit-9;
14. }
15. }
16. $tot += $digit;
17. }
18. return (($tot / 10) == 0);
19.}

Ceci dit cela peut être utile à beaucoup Merci
verdy_p
Messages postés
203
Date d'inscription
vendredi 27 janvier 2006
Statut
Membre
Dernière intervention
29 janvier 2019
-
Désolé, FS074995, mais ton code est *presque* bon, mais incorrect (tu a mis une division flottante par 2 au lieu d'un modulo 2 entier pour tester la parité de la position du chiffre par rapport à la fin du nombre, ainsi qu'une division flottante par 10 au lieu d'un modulo 10 pour tester la somme finale). Ton résultat sera donc faux.

Voici une version corrigée (qui en plus sait ignorer les séparateurs comme les blancs, points ou tirets et ne tient compte que des chiffres):
//Fonction algorithme de Luhn
function isLuhnNum($num) {
//longueur de la chaine $num
$len = strlen($num);
$pair = true;
$tot = 0;
for ($i = 0; $i < $len; $i++)
if (($digit = substr($num, $len - $i - 1, 1))
>= '0' && $digit <= '9')
$tot += $digit +
( ($pair = ! $pair)
? $digit - (($digit >= 5) ? 9 : 0)
: 0
);
return ($tot % 10) == 0;
}

Note: la variable $pair est nécessaire ci-dessus si on veut filter les non-chiffres dans la chaîne.

En revanche, si la chaîne est assurée de n'avoir plus QUE des chiffres, alors $pair est inutile et il suffit juste de tester ($i & 1) == 0 ci-dessus:

function isLuhnNum($num) {
//longueur de la chaine $num
$len = strlen($num);
$tot = 0;
for ($i = 0; $i < $len; $i++) $tot +($digit substr($num, $len - $i - 1, 1)
+ ( ($i & 1) == 0 ?
? $digit - (($digit >= 5) ? 9 : 0)
: 0;
return ($tot % 10) == 0;
}

L'algo de Luhn complet devrait aussi prendre en compte et accepter les lettres (pour vérifier les numéros de comptes de la banque postale par exemple) : à chaque lettre correspond un chiffre équivalent (pour l'algorithme du LUHN uniquement, mais significatif autrement), fonction de son rang dans l'alphabet:
A=0, B=1, C=2, ..., H=9,
I=0, J=1, K=2, ..., S=9,
T=0, U=1, V=1, ..., Z=4
verdy_p
Messages postés
203
Date d'inscription
vendredi 27 janvier 2006
Statut
Membre
Dernière intervention
29 janvier 2019
-
Note: dans la seconde version, j'ai oublié de coller 2 parenthèses ci-dessus, et en plus j'ai inversé le test de parité: le dernier chiffre n'est pas doublé (c'est l'avant-dernier qui l'est) :
$tot +($digit substr($num, $len - $i - 1, 1))
+ ( ($i & 1) != 0 ?
? $digit - (($digit >= 5) ? 9 : 0)
: 0);

La première version en revanche (qui teste et élimine les séparateurs) était correcte et est plus proche de celle visant à supporter aussi les lettres à convertir en chiffre.
Seb33300
Messages postés
16
Date d'inscription
dimanche 9 avril 2006
Statut
Membre
Dernière intervention
25 janvier 2011
-
En fait au départ je comptais utiliser un 2eme algo de contrôle à la suite pour plus de fiabilité et du coup je voulais bien séparer la vérification de la chaine / contrôle 1 / contrôle 2

Et finalement je n'ai pas mis en place le 2nd contrôle.
verdy_p
Messages postés
203
Date d'inscription
vendredi 27 janvier 2006
Statut
Membre
Dernière intervention
29 janvier 2019
-
Seb, il aurait fallu quand même éviter les deux bogues de la division par 2 et par 10. Pas la peine de poster ici un code tapé en vitesse qui donne un résultat faux et ne décrit pas l'alogo correctement (alors qu'il est documenté correctement partout ailleurs).