VÉRIFICATION DE LA VALIDITÉ D'UN BILLET DE BANQUE

Evangun Messages postés 1980 Date d'inscription dimanche 20 février 2005 Statut Membre Dernière intervention 24 septembre 2012 - 14 déc. 2007 à 00:24
The_magicien Messages postés 72 Date d'inscription mardi 5 juillet 2005 Statut Membre Dernière intervention 8 février 2009 - 22 déc. 2007 à 13:24
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/45050-verification-de-la-validite-d-un-billet-de-banque

The_magicien Messages postés 72 Date d'inscription mardi 5 juillet 2005 Statut Membre Dernière intervention 8 février 2009
22 déc. 2007 à 13:24
Modifications effectuées ;)
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
16 déc. 2007 à 15:43
@Kankrelune : Bravo pour le monologue, j'aurais pas fait mieux.

@The_Magicien : Ben si on poste en commentaire, c'est pour que tu puisses bénéficier des améliorations qu'on propose. Tu ne t'appropries pas notre travail, on te le donne. C'est pas pareil.

Et puis même si tu considères que ce n'est pas toi qui a écrit ce code, il l'a été en tout cas à ton initiative : il ne me serait pas venu à l'idée de me renseigner sur la manière dont vérifier un numéro de série d'un billet Euro, de même qu'il ne me serait pas venu à l'idée non plus d'écrire un code pour le vérifier.
Les commentaires avaient donc pour but de te montrer comment faire plus simple, plus efficace et plus élégant (en plus, là, t'as directement une fonction utilisable dans n'importe quelle application). Ils avaient aussi pour vocation de le montrer à tout le monde.

Tu peux donc sans scrupule l'utiliser. Si tu ne veux pas le mettre à la place de ton code, ce que je peux comprendre, tu peux le mettre à la suite ;)
Mais je t'en prie... On se fout de droits d'auteurs sur des commentaires sur une source ^^
The_magicien Messages postés 72 Date d'inscription mardi 5 juillet 2005 Statut Membre Dernière intervention 8 février 2009
14 déc. 2007 à 22:19
@ Evangun : Ce code n'est pas difficile à générer singulièrement. Cependant, si on veut entrer dans l'optique d'un faussaire il veut faire beaucoup d'argent donc si on veut générer des milliers, des millions de numéros de série, ça prend beaucoup plus de temps et c'est plus simple de mettre des numéros complètement aléatoires.

@ Kankrelune et Neigedhiver : Je ne sais pas si je vais faire les modifications parce que sinon, ce ne sera plus le code que moi j'ai fait donc c'est également par respect pour ce que vous m'avez proposé, je ne voudrais pas m'approprier le travail des autres.

Merci pour ces commentaires.
kankrelune Messages postés 1293 Date d'inscription mardi 9 novembre 2004 Statut Membre Dernière intervention 21 mai 2015
14 déc. 2007 à 15:40
Muarf je suis con moi... .. .

function validateSerial($num)
{
if(!empty($num) && preg_match('`^([l-npr-vx-z])([0-9]{11})$`i', $num, $matches))
{
return (bcmod(
str_replace(
$matches[1],
ord(strtoupper($matches[1])) - 64,
$matches[0]), '9') === '8');
}
return false;
}

@ tchaOo°
kankrelune Messages postés 1293 Date d'inscription mardi 9 novembre 2004 Statut Membre Dernière intervention 21 mai 2015
14 déc. 2007 à 15:39
>> Neigedhiver : bcmod prend des chaines de caractères en argument et renvoie une chaine... .. .

function validateSerial($num)
{
if(!empty($num)|| preg_match('`^([l-npr-vx-z])([0-9]{11})$`i', $num, $matches))
{
return (bcmod(
str_replace(
$matches[1],
ord(strtoupper($matches[1])) - 64,
$matches[0]), '9') === '8');
}
return false;
}

@ tchaOo°
kankrelune Messages postés 1293 Date d'inscription mardi 9 novembre 2004 Statut Membre Dernière intervention 21 mai 2015
14 déc. 2007 à 13:01
Au final après test...

`^([l-npr-vx-z])([0-9]{11})$`i

les deux autre laissent passer des codes invalides... .. .

@ tchaOo°
kankrelune Messages postés 1293 Date d'inscription mardi 9 novembre 2004 Statut Membre Dernière intervention 21 mai 2015
14 déc. 2007 à 12:52
t'inquiète pas... on ne t'en tiendra pas rigueur... .. . ;)

@ tchaOo°
kankrelune Messages postés 1293 Date d'inscription mardi 9 novembre 2004 Statut Membre Dernière intervention 21 mai 2015
14 déc. 2007 à 12:51
le mien est plus rapide et surtout le tien ne fait pas de différence entre 015509500765 et S15509500765... .. . ;)

@ tchaOo°
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
14 déc. 2007 à 12:51
J'avais effectivement zappé qu'il fallait ^et $ en début et en fin de regex...

Et effectivement, mieux vaut spécifier quels caractères afficher, plutôt que ceux à exclure...

Est-ce que l'excuse de l'heure est valable... ?
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
14 déc. 2007 à 12:48
Hum... Je sais pas si le lien s'affiche bien, il est peut-être trop long...
Voici : http://www.orphyx.net/shortlink.php?l=1
kankrelune Messages postés 1293 Date d'inscription mardi 9 novembre 2004 Statut Membre Dernière intervention 21 mai 2015
14 déc. 2007 à 12:48
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°
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
14 déc. 2007 à 12:43
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
14 déc. 2007 à 12:32
([^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 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
14 déc. 2007 à 02:55
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.
Evangun Messages postés 1980 Date d'inscription dimanche 20 février 2005 Statut Membre Dernière intervention 24 septembre 2012 4
14 déc. 2007 à 00:24
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 :)
Rejoignez-nous