Aller au contenu

Unicité et anti-doublon

Extension payante. Une règle par formulaire décide si une réponse déjà reçue doit être refusée ou simplement signalée, selon une clé que vous désignez : une adresse, un numéro d’adhérent, une combinaison de champs.

Ce n’est pas de l’anti-spam, et c’est la première chose à comprendre

L’anti-spam demande « est-ce un robot ». Cette règle demande « cette personne a-t-elle déjà répondu ». Les deux se trompent, mais pas de la même façon.

Un faux positif d’anti-spam perd un message : c’est ennuyeux, et le message existe encore quelque part. Un faux positif d’unicité empêche quelqu’un de s’inscrire, et cette personne n’a aucun moyen de contourner le refus — elle ne peut ni changer d’adresse ni deviner pourquoi on la refuse.

Tout le module découle de cette asymétrie :

  • comparaison exacte, jamais approchée ;
  • normalisation qui tient en une phrase ;
  • signaler par défaut, pas bloquer ;
  • message public qui ne renseigne personne.

Le plan l’écarte en quelques mots — « pas de matching flou, score de fraude, comparaison cross-site ou blocage sur IP » — et aucun de ces quatre n’existe ici.

La clé

Vous désignez de un à cinq champs. Leurs valeurs, mises bout à bout, forment la clé. Deux réponses qui produisent la même clé sont la même personne, au sens de cette règle.

L’ordre est celui du formulaire, pas celui où vous cochez les champs : deux réglages qui citent les mêmes champs dans un ordre différent produisent la même clé, sans quoi modifier le réglage sans rien changer d’autre invaliderait tout l’historique.

Ce que la normalisation fait, et s’arrête de faire

Les espaces de tête et de fin sont retirés, les suites d’espaces ramenées à une, la casse abaissée. C’est tout.

Camille@Exemple.fr et camille@exemple.fr sont donc la même clé — c’est la seule équivalence qu’on puisse affirmer sans connaître le champ, puisque tous les serveurs de messagerie en usage traitent la casse ainsi.

En revanche, jean.dupont@ et jeandupont@ restent deux clés. Retirer les points unit deux adresses chez un fournisseur et deux boîtes distinctes chez un autre. De même, les accents restent : René n’est pas Rene.

Chaque règle de rapprochement supplémentaire a ses faux positifs, et un faux positif ici empêche quelqu’un de s’inscrire.

Les champs qui ne peuvent pas composer la clé

Un fichier, une signature et un règlement ne se répètent jamais à l’identique : un nouveau chemin, un nouveau tracé, une nouvelle référence. Un mot de passe ne sort d’aucune des sorties du plugin.

Le champ calculé est écarté pour une autre raison : sa valeur dépend d’une formule qui peut changer. Le jour où elle change, toutes les clés déjà posées cessent de correspondre, et la règle s’arrête de fonctionner sans que rien ne le signale.

Ce qui est conservé

Une empreinte, jamais la valeur. C’est un HMAC-SHA256 pris sous un sel du site : il ne se renverse pas, et il ne vaut que pour cette installation.

Un hachage nu n’aurait pas suffi. La liste des adresses électroniques d’un pays tient sur un disque ; comparer des empreintes simples est l’affaire d’une minute. Le sel ferme cela, et ferme au passage la comparaison entre sites que le plan exclut.

Conséquence à connaître : regénérer les sels de wp-config.php rend les empreintes déjà posées inutilisables. Les règles repartent de zéro. C’est gênant, jamais destructeur — aucune soumission n’est perdue.

Bloquer ou signaler

Signaler est le défaut. La réponse est enregistrée et marquée ; vous la voyez dans l’écran « Doublons » et sur le détail de la soumission. Convient à un formulaire de contact : on veut recevoir le message, et savoir qu’il ressemble à un précédent.

Bloquer refuse la réponse. Convient à une inscription, où la seconde tentative n’a pas lieu d’être.

Commencer par « signaler » n’est pas de la prudence de principe : c’est la seule façon de voir ce que la règle attrape avant qu’elle ne refuse quelqu’un.

Le message ne dit rien

Ni quand, ni par qui, ni sous quelle valeur la première réponse est arrivée. Sur un formulaire public, « cette adresse a déjà répondu le 3 mars » renseigne exactement qui essaie des adresses au hasard.

L’écran d’administration, lui, montre le rapprochement : c’est là qu’il a sa place.

La fenêtre

En jours. Zéro veut dire toujours — ce n’est pas une absence de règle, c’est la règle la plus stricte. 365 autorise une réponse par personne et par an.

Une détention dont la fenêtre est passée se reprend d’elle-même, à la soumission suivante : il n’y a pas de tâche de ménage, et donc rien qui puisse ne pas tourner.

Deux soumissions au même instant

C’est la raison d’être du module, et le seul endroit où une implémentation naïve se trompe.

« Chercher si la clé existe, et l’écrire sinon » est juste tant qu’une seule requête s’exécute. Deux soumissions simultanées — un double clic, deux onglets, un robot — lisent toutes deux « aucune », et toutes deux écrivent.

La prise est donc une seule requête, un INSERT … ON DUPLICATE KEY UPDATE sur un index unique. Le serveur de base de données tranche, une requête repart avec la clé, et le nombre de lignes touchées dit laquelle. Aucun contrôle posé à côté de l’écriture n’aurait tenu.

La clé se prend avant que la soumission n’existe

C’est la seule façon de refuser un doublon sans d’abord enregistrer ce qu’on va refuser. La prise vit donc un instant sans soumission attachée.

Si l’enregistrement échoue entre les deux, la ligne resterait à bloquer la personne pour toute la fenêtre. Une prise non rattachée est donc abandonnée au bout d’une minute, et reprenable — large pour une requête qui dure quelques centièmes, court pour quelqu’un qui réessaie. Le module la rend d’ailleurs lui-même en fin de requête quand il le peut.

Les exemptions

Une soumission mise à la corbeille, marquée indésirable ou effacée rend sa clé. Sans cela, quelqu’un resterait empêché de répondre par une entrée que l’administrateur a précisément retirée de chez lui, et il n’aurait aucun moyen de comprendre pourquoi.

Un brouillon ne prend jamais de clé : il n’est pas une réponse. C’est la reprise du brouillon, au moment où elle devient la soumission, qui la prend.

Rétablir depuis la corbeille ne reprend pas la clé. C’est une limite assumée : la reprendre pourrait échouer si quelqu’un l’a prise entre-temps, et un rétablissement qui échoue à moitié serait pire que le trou qu’il comble.

L’écran

« Doublons », sous le menu des formulaires. Il montre le nombre de clés détenues, le nombre de doublons signalés, et la liste de ces derniers avec un lien vers la soumission qu’ils rapprochent.

Les soumissions bloquées n’y figurent pas, et ne peuvent pas y figurer : elles n’ont jamais été enregistrées, c’est tout l’intérêt du blocage. Qui veut un décompte règle la règle sur « signaler ».

La valeur qui rapproche deux soumissions n’y est pas non plus — seule l’empreinte est conservée. On ouvre les deux soumissions pour la lire, où elle est à sa place et soumise au même effacement que le reste.

Pour les développeurs

Ce module a demandé un point d’extension au cœur : solis_forms_entry_status_changed, diffusé par le dépôt quand le statut d’une soumission change réellement. Il porte l’état quitté et le nouveau, parce que le premier ne se déduit pas — une soumission peut passer de la corbeille à indésirable sans repasser par l’actif.

Il est documenté dans hooks-reference.md, et sert à tout module qui doit défaire quelque chose quand une soumission quitte l’actif.

Ce que la V1 ne fait pas

Une seule règle par formulaire. Pas de rapprochement approché, pas de score, pas de comparaison entre formulaires ni entre sites, pas de blocage sur adresse IP, pas de liste d’exceptions par personne, pas de reprise de clé au rétablissement.