Suppression en bloc d'utilisateurs

Comment supprimer massivement les spammers qui s'inscrivent sur les forums pour faire indexer des liens sur leur site par les moteurs de recherche?

Il est dommage que fluxBB ne permette pas de moduler l'accès aux renseignements sur les utilisateurs selon leur anciènneté.

Une première riposte au spam est très simple: Le spam devient déjà inutile si le fichier robots.txt interdit aux moteurs de recherche l'accès aux profils:

disallow:/forum/profile.php
disallow:/forum/userlist.php

Ensuite il faudrait de temps en temps nettoyer la base de donnée des inscriptions inutiles, tous les spammeurs dont les messages ont été effacés ou qui n'ont pas posté de message..

Mais ce n'est pas si simple: il y a des relations multiples entre les tables de la base et si l'on supprime une entrée dans l'une d'elles, il faut aussi supprimer toutes les références à cette entrée.

Tables fluxBB et membres inscrits

Nous allons donc voir toutes les tables et colonnes qui se rapportent aux utilisateurs.

users

id: identificateur repris dans d'autres tables.
username: nom repris dans d'autres tables.
num_posts: nombre de messages.

bans

username: l'utilisateur peut être banni, il faut supprimer l'entrée dans bans aussi.

reports

reported_by: (id) pour le cas peu probable ou un spammer aurait fait un rapport.

subscriptions

user_id: (id) pour le cas ou le spammer aurait souscrit à ce fil de discussion.

La requête d'interrogation

A partir de l'interface de PHPMyAdmin ou toute autre interface à SQL, on peut déjà voir combien il y a d'utilisateurs inactifs:

SELECT username FROM users WHERE num_posts='0' AND username != 'Guest'

Remplacer users par xxxxusers si le préfix déclaré dans config.php est xxxx.
On exclut Guest qui est un le nom générique des invités dans la version anglaise. Ce peut être un autre nom dans votre version, vérifier dans la liste des utilisateurs pour l'id 1.

En fait il est indispensable de conserver un utilisateur dont l'id est 1.

Voir les utilisateurs bannis sans messages:

SELECT * FROM bans, users WHERE bans.username=users.username AND users.num_posts='0'

Autre formulation utilisable pour la suppression:

SELECT * FROM bans WHERE username IN (SELECT username FROM users WHERE num_posts='0')

On remplacera SELECT * par DELETE pour la suppression.

La requête de suppression

On supprime les utilisateurs n'ayant aucun message avec cette commande SQL:

DELETE FROM $usertable WHERE num_posts='0' AND username != 'Guest'

Important: Dans la version francisée, remplacer Guest par Invité. Il a l'id 1.

Mais on doit d'abord éliminer les références:

DELETE FROM bans WHERE username IN (SELECT username FROM users WHERE num_posts='0')
DELETE FROM reports WHERE reported_by IN (SELECT id FROM users WHERE num_posts='0')
DELETE FROM subscriptions WHERE user_id IN (SELECT id FROM users WHERE num_posts='0')

On peut se contenter de vérifier d'abord les références, et faire une simple suppresssion s'il n'y en a pas.

En faire un script

Cette seconde partie introduit un script PHP à placer sur le site et qui réalise l'opération automatiquement.

On définit un spammeur comme utilisateur s'inscrivant pour ajouter son profil, avec un lien sur un site éventuellement douteux, et qui n'a pas jamais ajouté de billet ou dont les billets sont des spams et ont été supprimés.

Le script est plus élaboré que la commande SQL simple, car il va tester la table des messages pour vérifier que l'utilisateur n'en a posté aucun et ne se contente pas de consulter le nombre de messages dans la table utilisateur.
Ce dernier en effet n'est pas mis à jour par fluxBB après suppression d'un billet. C'est un compteur à sens unique!

Plus de tables fluxBB

Outre les tables décrites dans la première partie, nous utiliserons cette fois la table posts.

Table posts:

  poster poster_id      
  pseudo de l'utilisateur son numéro d'identification      

On veut seulement de vérifier qu'un utilisateur n'a aucun billet.

Table topics:

  poster      
  pseudo de l'utilisateur      

Normalement le topic est supprimé quand le premier billet est supprimé aussi on n'utilisera pas cette table.

Requête

On reprend les requêtes données dans la première partie et on ajoute un traitement pour la table des messages.

Vérifier le nombre de messages pour un utilisateur (on fera le test pour tous les utilisateurs en fait):

$user = "xxxx";  
$query = SELECT * WHERE  poster='$user'
$hnd = mysqli_query($db_handler, $query);
if(mysqli_num_rows($hnd) == 0)
{
  echo "$user n'a aucun message.<br>";
}

Si le nombre de message est null, on peut mettre à jour le nombre de billets dans la table users:

UPDATE users SET num_posts='0' WHERE poster='$user'

Puis on ajoute au script les requêtes de suppression vues en première partie qui se basent sur la table users et les tables associées:

DELETE FROM bans WHERE username IN (SELECT username FROM users WHERE num_posts='0')
DELETE FROM reports WHERE reported_by IN (SELECT id FROM users WHERE num_posts='0')
DELETE FROM subscriptions WHERE user_id IN (SELECT user_id FROM users WHERE num_posts='0')
DELETE FROM users WHERE num_posts='0' AND id != '1'

On conserve l'entrée 1 qui est celle de l'invité, "Guest" en anglais, qui doit toujours rester présente.

Le script de suppression

include("config.php");

$hnd = mysqli_query($db_handler, "SELECT username FROM users");
while($userlist = mysqli_fetch_assoc($hnd))
{
  $user = $userlist['username'];
  $hndposts = mysqli_query($db_handler, "SELECT * FROM $posts WHERE poster='$user'");
  if(mysqli_num_rows($hndposts) == 0)
  {
       mysql_query("UPDATE users SET num_posts='0' WHERE username='$user'", $db_handler);
  }
}
mysql_query("DELETE FROM bans WHERE username IN (SELECT username FROM users WHERE num_posts='0')",  $db_handler);
mysql_query("DELETE FROM reports WHERE reported_by IN (SELECT id FROM users WHERE num_posts='0')",  $db_handler);
mysql_query("DELETE FROM subscriptions WHERE user_id IN (SELECT id FROM users WHERE num_posts='0')",  $db_handler);
mysql_query("DELETE FROM users WHERE num_posts='0' AND id != '1'",  $db_handler);

echo "Done!";

A cela on doit ajouter le code de connexion à la base de données, ce qui est inclut dans le script à télécharger...

Télécharger et utiliser

Pour utiliser le script, on le place dans le répertoire racine de fluxBB et on appelle directement le fichier à partir d'un navigateur.
Par exemple:

http://www.monsiteweb.com/forum/killbill.php 

Vous pouvez voir ce que fera le script sans modifier quoi que ce soit en activant provisoirement le drapeau DEBUG dans le code source:

$DEBUG = true;   

Script de suppression en masse d'utilisateurs sous fluxBB

Le fichier s'appelle killbill.php. Vous pouvez changer ce nom et lui donner un nom personnalisé.

Faites par précaution une sauvegarde de la base de données avec la commande export de PHPMyAdmin ou la fonction de votre panel d'administration, avant la première utilisation.