fonction de Luhn en php

Après avoir regarder du côté de wikipédia, j’ai pu construire la fonction de Luhn permettant entre autre de vérifier des numéros de carte bancaire.

//Fonction algorithme de Luhn
function isLuhnNum($num)
{
	//longueur de la chaine $num
	$length = strlen($num);
	
	//resultat de l'addition de tous les chiffres
	$tot = 0;
	for($i=$length-1;$i>=0;$i--)
	{
		$digit = substr($num, $i, 1);
		
		if ((($length - $i) % 2) == 0)
		{
			$digit = $digit*2;
			if ($digit>9)
			{
				$digit = $digit-9;
			}
		}
		$tot += $digit;
	}
	
	return (($tot % 10) == 0);
}

Merci à Andras pour sa précision 😉

Commentaires

8 réponses à « fonction de Luhn en php »

  1. Avatar de Xfigpower
    Xfigpower

    Moi, j’utilise perso une version plus courte (je n’aime pas beaucoup le « -9 » dans l’algo)

    //Fonction algorithme de Luhn
    function isCB($numCB)
    {
    //longueur de la chaine $numCB
    $lengthCB = strlen($numCB);

    //resultat de l’addition de tous les chiffres
    $tot = 0;

    for($i=$lengthCB-1;$i>=0;$i–)
    {
    $digit = $numCB[$i];

    $tot += ($i % 2)?((2*$digit)%10 + (2*$digit)/10):$digit;
    }

    return !($tot % 10);
    }

  2. Avatar de Francis Hilaire

    Moi c’est le (2*$digit)/10 qui me gène, ça donne forcément un float lorsque tu fais par exemple $digit = 1; Si tu travailles comme ça dans un autre language tel que Java ou C# ça ne passera jamais. Bon il est vrai que là on est censé recevoir un int et qu’on l’interprète comme un string donc bon…

    Le -9 est déjà plus mathématique car on a forcément un chiffre compris entre 0 et 18 lorsqu’on multiplie par 2 $digit et qu’il correspond exactement à ce que l’algorithme doit faire.

    C’est clair, c’est plus rapide, mais pas à comprendre pour un néophyte…

  3. Avatar de andras

    hum, il me semble bien qu’il y a une erreur dans ton implementation : ça ne marche qu’avec les nombres qui ont un nombre de chiffre pair (comme les CB) mais pas avec ceux qui ont un nombre de chiffres impair (comme les numéros SIREN).

    il faut remplacer la ligne :
    if (($i % 2) == 0)
    par la ligne suivante :
    if ((($length – $i) % 2) == 0)

    et là, ça marche pour tous les cas, il me semble.

  4. Avatar de Francis Hilaire

    Merci pour cette précision Andras 😉

  5. Avatar de Melnofil

    Francis Hilaire :
    J’ai eu du mal à voir du premier coup comment circule la variable « $ret » tout au long de ton programme, pourquoi ne pas utiliser tout simplement :
    return ($tot % 10 == 0);

    As-tu une raison particulière d’appeler la fonction « substr » au lieu de l’opérateur « crochets » ?
    $digit = $num[$i];

    Xfigpower :
    Je paraphrase Francis Hilaire en ajoutant que la division est généralement l’opération de base la plus couteuse en temps processeur (quelque soit le language ou le processeur utilisé). Pire, ta multiplication par 2 est effectuée deux fois de suite pour rien !

  6. Avatar de Francis Hilaire

    Melnofil : Merci de ton intervention, j’avoue que c’est l’habitude qui m’as fait mettre ce $ret… Il est vrai qu’il est complètement inutile.

  7. Avatar de Poulpos
    Poulpos

    Intéressant : en cas de paramètre vide, la fonction renvoie quand même true.
    [ isLuhnNum( ») => true ]

    Penser à ajouter ceci en début de fonction pour remédier simplement au problème


    if($length==0){
    return false;
    }

  8. Avatar de Francis Hilaire

    @Poulpos : Ce n’est qu’un court code très ciblé que vous pouvez modifier et réutiliser, il n’est pas destiné à contrôler autre chose que la validité d’une chaîne de caractère qui aura dut être contrôlée en amont par vos différents validateurs de saisies.

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.