Vérification de la validité d'un billet de banque

Soyez le premier à donner votre avis sur cette source.

Vue 26 217 fois - Téléchargée 538 fois

Description

Ce script va, lorsque vous rentrez le numéro de série (avec la lettre au début) de n'importe quel billet Euro, vous dire si le billet que vous avez en votre possession est un vrai ou un faux. :)

Source / Exemple :


##########################################
## AUTRE VERSION DISPONIBLE DANS LE ZIP ##
##########################################

      <?php
if(isset($_POST['num']))
{
  if(preg_match("/[^:alnum:]/", $_POST['num'])) 
  {
  $letter = $_POST['num']{0};
    if(preg_match("/^[L-Z]/", $letter) && $letter != ("O"|"Q"|"W"))
    {
      switch ($letter) 
      {
        case 'L':
			$pre = '12';
			$num = str_replace("L", "12", $_POST['num']);
			break;
		case 'M':
			$pre = '13';
			$num = str_replace("M", "13", $_POST['num']);
			break;
		case 'N':
			$pre = '14';
			$num = str_replace("N", "14", $_POST['num']);
			break;
		case 'P':
			$pre = '16';
			$num = str_replace("P", "16", $_POST['num']);
			break;
		case 'R':
			$pre = '18';
			$num = str_replace("R", "18", $_POST['num']);
			break;
		case 'S':
			$pre = '19';
			$num = str_replace("S", "19", $_POST['num']);
			break;
		case 'T':
			$pre = '20';
			$num = str_replace("T", "20", $_POST['num']);
			break;
		case 'U':
			$pre = '21';
			$num = str_replace("U", "21", $_POST['num']);
			break;
		case 'V':
			$pre = '22';
			$num = str_replace("V", "22", $_POST['num']);
			break;
		case 'X':
			$pre = '24';
			$num = str_replace("X", "24", $_POST['num']);
			break;
		case 'Y':
			$pre = '25';
			$num = str_replace("Y", "25", $_POST['num']);
			break;
		case 'Z':
			$pre = '26';
			$num = str_replace("Z", "26", $_POST['num']);
			break;
	  }
	  if((strlen($num) == 13) OR (preg_match("/[^0-9]/", $num)))
	  {
	    if ( bcmod($num, "9") == 8) 
		{
		  echo "<br /><br /><h2><font color='green'>Votre billet est <b>vrai</b></font></h2><br /><br />";
		}
		else
		{
		  echo "<br /><br /><h2><font color='red'>Votre billet est <b>faux</b></font></h2><br /><br />";
		}
	  }
	  else
	  {
    	echo "<font color='red'><b>Numéro de série invalide!<br /><br /><font size='2'><u>Rappel:</u> 1 lettre (entre L et Z exceptées O, Q et W) puis 11 chiffres.</font></b></font><br /><br />";
	  }
	}
	else
	{
      echo "<font color='red'><b>Numéro de série invalide!<br /><br /><font size='2'><u>Rappel:</u> 1 lettre (entre L et Z exceptées O, Q et W) puis 11 chiffres.</font></b></font><br /><br />";
	}
  }
}
else
{
  echo "<br /><br /><br />";
}
    ?>
	
    <form id="form1" name="form1" method="post" action="">
      <label for="num">Numéro de série :</label>
      <input type="text" name="num" id="num" maxlength="12" />
      <p>
        <input type="submit" name="Envoyer" id="Envoyer" value="Envoyer" />
        <input type="reset" name="Envoyer2" id="Envoyer2" value="Réinitialiser" />
      </p>
    </form>

Conclusion :


Petites explications quand au travail du script.
En fait, la vérification d'un billet de banque (Euro) se fait de la manière suivante : On prend la première lettre du numéro de série et on détermine son rang dans l'alphabet. Ensuite on rassemble ce chiffre (par exemple 21 si c'est la lettre U) avec le reste du numéro de série.
Ce nombre doit donner 8 lorsqu'on le met modulo 9. Si le résultat est différent de 8, le billet est faux ;)

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Evangun
Messages postés
1980
Date d'inscription
dimanche 20 février 2005
Statut
Membre
Dernière intervention
24 septembre 2012
5 -
Hello,
Je ne connaissais pas ce truc, c'est marrant ! Ceci dit, si j'étais faussaire, je le connaîtrais, et du coup je ferais des numéros corrects :)
neigedhiver
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
13 -
Salut,

Quelques petites améliorations sur les regex : plutôt que d'en faire je ne sais pas combien dans ton script, tu peux te contenter de n'en faire qu'une.
Je crois comprendre à la lecture de ton code qu'un numéro de série est composée d'une lettre entre L et Z inclus, à l'exception de O, Q et W, suivie de 11 chiffres. Une seule regex suffit pour vérifier la validité du numéro et récupérer la lettre et le numéro :

if (preg_match('`^([^a-koqw])([0-9]{11})`i', $_POST['num'], $matches)) {
// Numéro syntaxiquement valide
}
else {
// Numéro invalide !
}

Si le numéro est syntaxiquement correct, $matches est alors un tableau de ce genre :

* [0]=>S15509500765
* [1]=>S
* [2]=>15509500765

$matches[0] est la chaine qui correspond au motif
$matches[1] la lettre, et $matches[2] la série de chiffres.

Déjà, tu économises des perfs (une seule pcre au lieu de 3) et tu gagnes en quantité de code (et donc en lisibilité) : tu n'as plus qu'un seul test qui débouche sur le message d'erreur numéro invalide.

Ensuite, pour la valeur des lettres... Switch n'est pas optimal, puisque le script parcourt toutes les possibilités jusqu'à tomber sur la bonne.

Puisqu'on a utilisé une regex très sévère en terme de filtrage, on sait que la lettre ne peut être qu'une lettre entre L et Z sauf O, Q et W et pas un autre caractère. On peut donc utiliser directement sa valeur ascii :

$pre = ord(strtoupper($matches[1])) - 64;

Ca, c'est fait : une ligne qui te fait économiser 49 lignes de ton switch($letter)

Ensuite, pour concaténer le tout et obtenir un nombre :

$num = (int) ($matches[1] . $matches[2]);

Maintenant, plus qu'à vérifier la validité du numéro :

if ( bcmod($num, "9") == 8)

Ca, c'est beurk. Mettre 9 entre guillemets change son type en chaine de caractères. bcmod, qui opère sur des nombres, va devoir le changer encore en nombre, alors qu'il était déjà dans le bon type.

if (bcmod($num, 9) == 8)

Voilà : 3 lignes au lieu de plusieurs dizaines. T'as gagné tellement de lignes et en lisibilité que tu peux même te permettre d'ajouter des commentaires ^^ Parce que ça manque, et c'est dommage, tu t'es donné la peine de faire un code XHTML 1.0 Transitionnal valide...

Et si tu veux faire encore plus propre, tu peux mettre tout le html à la fin du script, pour bien séparer le traitement de l'affichage.

Encore un dernier détail... Dans un soucis de factorisation (qui consiste à ne pas écrire 2 fois un code identique utilisé à 2 endroits différents) tu peux modifier l'affichage du message final vrai ou faux billet.

Par exemple :
$billet (bcmod($num, 9) 8) ? 'vrai' : 'faux';

Utilise une classe pour la mise en forme de ton texte (et pas un h2 qui sert à identifier un titre, et uniquement à cela, et pas à écrire plus gros);

echo 'Votre billet est ' . $billet . ' !

';

Dans ton css :

p#resultat {
font-weight: bold;
background-color: transparent;
}

p.vrai {
color: green;
}

p.faux {
color: red;
}

Et là, tu auras un code php performant, élégant, documenté (si tu mets des commentaires ;) ) et séparé du code html.
Quant au html, en plus d'être valide, il sera aussi sémantiquement correct.
kankrelune
Messages postés
1293
Date d'inscription
mardi 9 novembre 2004
Statut
Membre
Dernière intervention
21 mai 2015
-
([^a-koqw])

>

([a-k^oqw])

sinon c'est marrant pour valider le code d'un billet de banque effectivement... mais ça s'arrête là un billet pouvant bien entendu être faux avec un code valide... .. .

@ tchaOo°
neigedhiver
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
13 -
Tu voulais surement dire :
([l-z^oqw])

Les deux regex sont à peu près équivalentes :
http://www.lumadis.be/regex/test_regex.php?lang=fr&pat1=%60^([^a-koqw])([0-9]{11})%60i&pat1typ=preg_match&pat2=%60^([^a-koqw])([0-9]{11})%60i&pat2typ=preg_match&txt=S15509500765&result=Ti

La première est un coup plus rapide, un coup plus lente...
kankrelune
Messages postés
1293
Date d'inscription
mardi 9 novembre 2004
Statut
Membre
Dernière intervention
21 mai 2015
-
Merde j'avais compris l'exception dans le sens inverse... j'ai rien dis... par contre y a quand même un truc qui cloche car tu exclu des caractère sans spécifier quel caractère peut apparaitre... mieux vaut peut être mettre...

([L-Z^OQW])

je rajouterais un $ à la fin pour bien délimiter la chaine que l'on attend... .. .

function validate($num)
{
if(!empty($num))
{
if(preg_match('~^([L-Z^OQW])([0-9]{11})$~i', $num, $matches))
{
return (bcmod(
(int)str_replace(
$matches[1],
ord(strtoupper($matches[1])) - 64,
$matches[0]), 9) === 8)
}
}
return false;
}

A tester j'ai codé ça en vrac... .. .

@ tchaOo°

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.

Du même auteur (The_magicien)