phpBB2 : Partager une base de données entre plusieurs forums

Guillaume Rossolini

Il est souvent utile d'utiliser une seule base de données pour plusieurs sites différents. Cet article décrit comment une seule base de données peut être utilisée pour alimenter plusieurs forums phpBB2.

Il y a quelques contraintes techniques, mais c'est possible.

Cet article est davantage un retour d'expérience qu'un tutoriel. Je n'ai pas pris une approche didactique, je pose simplement les faits.

Commentez ♪

- Titre : phpBB2 : Partager une base de données entre plusieurs forums

- Auteur : Guillaume Rossolini

- Parution : 1 janvier 2007

- Licence : Copyright ® 2007 Guillaume Rossolini. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. Remerciements

- I-B. Préambule

- I-C. Contraintes techniques

- II. Préliminaires

- II-A. Étude de la structure de phpBB2

- II-A-1. Les données spécifiques à chaque site

- II-A-2. Les données nomades

- II-A-3. Les données partagées entre tous les sites

- II-A-4. Cas particulier : les Utilisateurs

- II-B. Plan d'action

- III. La nouvelle structure des données

- III-A. Création de la nouvelle organisation

- III-B. Modification de la structure existante

- III-C. Création des Vues

- III-D. Le cas des Utilisateurs

- IV. Les scripts à retoucher

- IV-A. config.php

- IV-B. includes/constants.php

- IV-C. admin/admin_forums.php

- IV-C-1. Ajout de forum

- IV-C-2. Ajout de catégorie

- IV-C-3. Suppression de forum

- IV-D. includes/prune.php

- IV-D-1. La surveillance des sujets

- IV-D-2. Les sujets

- IV-D-3. Les messages

- IV-D-4. Le contenu des messages

- IV-E. Le cas des Utilisateurs

- IV-E-1. includes/usercp_register.php

- IV-E-1-a. Ajout d'un utilisateur

- IV-E-1-b. Mise à jour d'un utilisateur

- IV-E-2. admin/admin_users.php

- IV-E-2-a. Mise à jour d'un utilisateur

- IV-E-2-b. Suppression d'un utilisateur

- IV-E-3. Champs spécifiques à un site

- IV-E-4. Champs partagés par tous les sites

- V. Le nouveau module d'administration

- V-A. Les variables de langue

- V-B. Le gabarit du script

- V-C. Le script

- VI. Correction du référencement

- VI-A. Lecture d'un forum déplacé

- VI-B. Lecture d'un sujet ou d'un message déplacé

- VII. Conclusion

- VII-A. Épilogue

- VII-B. Liens

I - Introduction

I-A - Remerciements

Je remercie Florian et Alexandre pour avoir essayé les scripts sur la machine de développement.

I-B - Préambule

L'un des forums dont je m'occupe (en dehors de Developpez) a grossi avec le temps, à tel point qu'il a été temps de réfléchir à son évolution. Après concertation, nous avons décidé de le diviser : le forum principal serait dédié au cinéma, tandis que tous les sujets traitant d'un thème différent (culture, loisirs, etc.) seraient déplacés dans un site distinct. Cependant, ne voulant pas obliger les membres actuels à s'enregistrer sur le nouveau forum (ce qui les ferait probablement partir), nous avons réfléchi à un moyen de partager la base de données entre les deux forums.

Puisque nous utilisons phpBB2 depuis plusieurs années, les scripts de notre installation phpBB2 sont très largement modifiés et cela nous demanderait beaucoup d'efforts de changer de technologie de forum. De plus, où serait le défi technique ? ;-)

Ainsi, cet article décrit la méthode que j'ai suivie pour permettre à plusieurs installations de phpBB2 (sur le même serveur) de partager la même base de données. Tout est prévu pour avoir les mêmes utilisateurs sur les deux sites et pour permettre à un administrateur de déplacer des sujets (catégories, forums ou discussions) d'un site à l'autre.

Il ne s'agit pas ici de vous livrer un paquetage clefs en main. Je n'ai pas l'intention d'adapter ce tutoriel à toutes les déclinaisons de phpBB, je décrirai simplement la procédure pour le paquetage officiel, à vous de faire le reste du chemin. Cela dit, vos questions seront les bienvenues sur les forums ;)

I-C - Contraintes techniques

La seule réelle contrainte est la possibilité d'utiliser des Vues SQL.

Avantage d'utiliser des Vues : nous n'avons pas à toucher aux requêtes de type « SELECT » (qui constituent la très large majorité des requêtes dans phpBB).

Inconvénient : selon le SGBD, il n'est pas toujours possible de modifier ou de supprimer au travers des Vues. Dans mon cas, MySQL 5 permet la modification, mais pas la suppression : je devrai modifier les requêtes de type « DELETE » qui touchent à des vues, mais les requêtes de type « UPDATE » n'ont pas besoin d'être modifiées pour cette raison.

II - Préliminaires

II-A - Étude de la structure de phpBB2

Avant de commencer, il est fondamental de comprendre comment est organisé phpBB2. Nous allons donc passer en revue les différentes tables de la base de données.

Certaines tables seront remplacées par des Vues SQL.

II-A-1 - Les données spécifiques à chaque site

Ces informations n'ont aucune raison d'être transférées d'un site à l'autre :

- phpbb_auth_access : Les autorisations d'accès des utilisateurs ou des groupes pour les catégories ou les forums ;

- phpbb_config : La configuration d'un forum ;

- phpbb_groups : Les groupes d'utilisateurs ;

- phpbb_ranks : Les rangs des utilisateurs ;

- phpbb_sessions : Les sessions utilisateurs ;

- phpbb_sessions_keys : Une gestion supplémentaire des sessions utilisateurs ;

- phpbb_smilies : Les smilies ;

- phpbb_themes : Les styles/thèmes/skins ;

- phpbb_themes_name : Les noms des styles/thèmes/skins ;

- phpbb_user_group : Les relations entre les utilisateurs et les groupes.

Les tables spécifiques à un site n'ont besoin d'aucune intervention (phpBB les installe et nous n'avons pas besoin de les modifier). Elles contiennent la configuration de chaque site.

Les tables phpbb_sessions et phpbb_sessions_keys peuvent être conservées comme tables spécifiques (ie. l'exemple de ce tutoriel) ou bien gérées en tant que tables partagées. Dans mon cas, j'utilise un nom de domaine pour chaque site donc les sessions sont totalement indépendantes, mais vous pouvez les partager si vos forums sont sur le même domaine.

Si vous décidez de partager les sessions, cela évite à vos visiteurs de se connecter indépendamment pour chaque site. Attention, il est impossible de le faire lorsque les noms de domaine sont différents, car le navigateur Web sépare leurs cookies.

II-A-2 - Les données nomades

Seul le site affecté peut voir ces informations, mais on peut les transférer d'un site à l'autre :

- phpbb_categories : Les catégories de niveau supérieur ;

- phpbb_forums : Les forums ;

- phpbb_forum_prune : Le délestage d'un forum ;

- phpbb_posts : Les messages d'un forum ;

- phpbb_posts_text : Le contenu des messages d'un forum ;

- phpbb_topics : Les sujets de discussion ;

- phpbb_topics_watch : Qui surveille quel sujet de discussion ;

- phpbb_vote_desc : Les sondages ;

- phpbb_vote_results : Les résultats des sondages ;

- phpbb_vote_voters : Les votants aux sondages.

Nous accèderons à ces tables au moyen de Vues SQL. Nous leur ajouterons un identifiant de site, disponible dans une nouvelle table. Les scripts de configuration et de modification de données de chaque site doivent être modifiés pour référencer cet identifiant.

Les vues contiennent les informations qui ne concernent qu'un seul site de l'ensemble, tout en pouvant être déplacées d'un site à l'autre.

II-A-3 - Les données partagées entre tous les sites

Tous les sites utilisent ces mêmes informations :

- phpbb_banlist : Les utilisateurs bannis ;

- phpbb_confirm : Confirmation d'inscription pour les nouveaux utilisateurs ;

- phpbb_disallow : Les noms d'utilisateur interdits ;

- phpbb_privmsgs : Les messages privés des utilisateurs ;

- phpbb_privmsgs_text : Le contenu des messages privés des utilisateurs ;

- phpbb_privmsgs_ignore Chaque utilisateur peut choisir d'ignorer les messages d'autres utilisateurs ;

- phpbb_search_results : Les résultats des recherches ;

- phpbb_search_wordlist : Les mots recherchés ;

- phpbb_search_wordmatch : La correspondance entre les mots (cf. la table ci-dessus) et les messages dans lesquels ils sont utilisés ;

- phpbb_words : Les mots censurés par l'administrateur.

Les tables de partage sont simplement des tables de phpBB renommées pour refléter leur caractère commun. La configuration des différents sites doit être modifiée pour y faire référence, ce qui nous évite de créer des vues.

II-A-4 - Cas particulier : les Utilisateurs

Une partie des informations (sessions, thème, langue, etc.) sont spécifiques à chacun des sites tandis qu'une autre partie (pseudo, mot de passe, etc.) leur est commune. La méthode utilisée pour les autres tables n'est donc pas adaptée, il faut trouver une parade.

Champs communs à tous les sites :

- user_active : Si le profil est actif ;

- username : Pseudonyme ;

- user_pasword : Mot de passe ;

- user_regdate : Date d'enregistrement ;

- user_level : Invité, membre, administrateur ;

- user_posts : Compteur de messages ;

- user_timezone : Zone horaire ;

- user_new_privmsg : S'il y a de nouveaux messages privés ;

- user_unread_privmsg : S'il y a des messages privés non lus ;

- user_last_privmsg : Quel est le dernier message privé ;

- user_login_tries : Compteur de tentatives de connexion ;

- user_last_login_try : Quand a eu lieu la dernière tentative de connexion ;

- user_emailtime : ?

- user_viewemail : Si l'adresse e-mail est publique ;

- user_attachsig : Si la signature est ajoutée aux messages ;

- user_allowhtml : Si le HTML est autorisé dans les messages ;

- user_bbcode : Si le BBCode est autorisé dans les messages ;

- user_smile : Si les smilies sont autorisés dans les messages ;

- user_allowavatar : Si l'avatar est montré ;

- user_allow_pm : Si le membre accepte les messages privés ;

- user_allow_viewonline : Si le membre souhaite montrer sa présence en ligne ;

- user_notify : Si le membre souhaite être prévenu par mail des réponses ;

- user_notify_pm : Si le membre souhaite être prévenu par mail des messages privés ;

- user_popup_pm : Si un popup est utilisé pour alerter de la présence de nouveaux messages privés ;

- user_avatar : L'image avatar

- user_avatar_type : D'où provient l'avatar (galerie, URI)

- user_email : Adresse e-mail ;

- user_icq : Numéro ICQ

- user_website : Adresse du site Web ;

- user_from : Localisation géographique ;

- user_sig : Signature ;

- user_sig_bbcode_uid : BBCode UID de la signature ;

- user_aim : Contact AIM ;

- user_yim : Contact Yahoo! Messenger ;

- user_msnm : Contact Windows Live Messenger ;

- user_occ : Occupation ;

- user_interests : Centres d'intérêt ;

- user_actkey : Clef d'enregistrement ;

- user_newpasswd : Nouveau mot de passe.

Champs spécifiques à chaque site :

- user_session_time : Date de la session ;

- user_session_page : Page en cours ;

- user_lastvisit : Dernière visite ;

- user_style : Thème/gabarit choisi ;

- user_lang : Langue du forum ;

- user_dateformat : Format de la date ;

- user_rank : Rang (r/r au nombre de messages)

II-B - Plan d'action

Nous allons commencer par la base de données en suivant le schéma ci-dessus, puis nous nous attaquerons aux scripts.

Nous mettrons ensuite en place une interface d'administration permettant à un administrateur de déplacer une catégorie depuis un site vers un autre site.

Enfin, il nous faudra apporter quelques corrections supplémentaires aux scripts des sites afin de tenir compte du référencement des catégories/forums/sujets/messages déplacés.

III - La nouvelle structure des données

Nous allons utiliser des vues (CREATE VIEW) pour partager les informations entre les sites. Je vais prendre l'exemple de 2 sites désignés par les préfixes « forum1_ » et « forum2_ » ; le préfixe « forums_ » désigne les tables partagées. Pour suivre mon exemple, installez simplement deux fois phpBB2 en utilisant les préfixes « forum1_ » et « forum2_ » et en prenant soin d'indiquer des noms différents pour les cookies (panneau d'admin / config). Placez les scripts de phpBB dans des répertoires « forum-1 » et « forum-2 » à la racine de votre serveur Web.

III-A - Création de la nouvelle organisation

Exécuter :

-- Une nouvelle table sera nécessaire
CREATE TABLE forums_sites (
site_id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT,
site_uri VARCHAR(255) NOT NULL,
site_users_config_table VARCHAR(255) NOT NULL,
site_groups_table VARCHAR(255) NOT NULL,
site_user_groups_table VARCHAR(255) NOT NULL,
site_config_table VARCHAR(255) NOT NULL,
PRIMARY KEY (site_id),
UNIQUE (site_uri),
UNIQUE (site_users_config_table),
UNIQUE (site_groups_table),
UNIQUE (site_user_groups_table),
UNIQUE (site_config_table)
);

-- Les sites partageant la base de données
INSERT INTO forums_sites (site_uri, site_users_config_table, site_groups_table, site_user_groups_table, site_config_table)
VALUES
('http://localhost/forum-1/', 'forum1_users_config', 'forum1_groups', 'forum1_user_group', 'forum1_config'),
('http://localhost/forum-2/', 'forum2_users_config', 'forum2_groups', 'forum2_user_group', 'forum2_config');

III-B - Modification de la structure existante

Exécuter :

-- Réutilisons les tables de l'un des forums pour créer les vues
ALTER TABLE forum1_categories RENAME TO forums_categories;
ALTER TABLE forum1_forums RENAME TO forums_forums;
ALTER TABLE forum1_forum_prune RENAME TO forums_forum_prune;
ALTER TABLE forum1_posts RENAME TO forums_posts;
ALTER TABLE forum1_posts_text RENAME TO forums_posts_text;
ALTER TABLE forum1_topics RENAME TO forums_topics;
ALTER TABLE forum1_topics_watch RENAME TO forums_topics_watch;
ALTER TABLE forum1_vote_desc RENAME TO forums_vote_desc;
ALTER TABLE forum1_vote_results RENAME TO forums_vote_results;
ALTER TABLE forum1_vote_voters RENAME TO forums_vote_voters;

-- Les mêmes tables des autres forums ne sont plus nécessaires
DROP TABLE forum2_categories, forum2_forums, forum2_forum_prune,
forum2_posts, forum2_posts_text, forum2_topics, forum2_topics_watch,
forum2_vote_desc, forum2_vote_results, forum2_vote_voters;

-- Nous avons besoin de l'identifiant du site dans la table de plus haut niveau
ALTER TABLE forums_categories ADD site_id INT(4) NOT NULL DEFAULT 0;
UPDATE forums_categories SET site_id=1;

-- Réutilisons maintenant les tables communes à tous les sites
ALTER TABLE forum1_banlist RENAME TO forums_banlist;
ALTER TABLE forum1_confirm RENAME TO forums_confirm;
ALTER TABLE forum1_disallow RENAME TO forums_disallow;
ALTER TABLE forum1_privmsgs RENAME TO forums_privmsgs;
ALTER TABLE forum1_privmsgs_text RENAME TO forums_privmsgs_text;
ALTER TABLE forum1_search_results RENAME TO forums_search_results;
ALTER TABLE forum1_search_wordlist RENAME TO forums_search_wordlist;
ALTER TABLE forum1_search_wordmatch RENAME TO forums_search_wordmatch;
ALTER TABLE forum1_words RENAME TO forums_words;

-- Les mêmes tables des autres forums ne sont plus nécessaires
DROP TABLE forum2_banlist, forum2_confirm, forum2_disallow, forum2_privmsgs,
forum2_privmsgs_text, forum2_search_results, forum2_search_wordlist,
forum2_search_wordmatch, forum2_words;

III-C - Création des Vues

Forum 1 :

-- Les catégories ont l'identifiant du site de destination
CREATE OR REPLACE VIEW forum1_categories AS
SELECT *
FROM forums_categories
WHERE site_id IN (0, 1);

-- Ces catégories nous permettent de restreindre les forums à un site
CREATE OR REPLACE VIEW forum1_forums AS
SELECT f.*
FROM forums_forums f
INNER JOIN forum1_categories c ON f.cat_id = c.cat_id;

-- Ces forums nous permettent de restreindre les sujets à un site
CREATE OR REPLACE VIEW forum1_topics AS
SELECT t.*
FROM forums_topics t
INNER JOIN forum1_forums f ON t.forum_id = f.forum_id;

-- Ces sujets nous permettent de restreindre les messages à un site
CREATE OR REPLACE VIEW forum1_posts AS
SELECT p.*
FROM forums_posts p
INNER JOIN forum1_topics t ON p.topic_id = t.topic_id;

-- Ces messages nous permettent de restreindre leur contenu à un site
CREATE OR REPLACE VIEW forum1_posts_text AS
SELECT pt.*
FROM forums_posts_text pt
INNER JOIN forum1_posts p ON p.post_id = pt.post_id;

-- Les forums nous permettent de restreindre les autorisations à un site
CREATE OR REPLACE VIEW forum1_forum_prune AS
SELECT fp.*
FROM forums_forum_prune fp
INNER JOIN forum1_forums f ON fp.forum_id = f.forum_id;

-- Les sujets nous permettent de restreindre leur surveillance à un site
CREATE OR REPLACE VIEW forum1_topics_watch AS
SELECT tw.*
FROM forums_topics_watch tw
INNER JOIN forum1_topics t ON tw.topic_id = t.topic_id;

-- Les sujets nous permettent de restreindre les sondages à un site
CREATE OR REPLACE VIEW forum1_vote_desc AS
SELECT vd.*
FROM forums_vote_desc vd
INNER JOIN forum1_topics t ON vd.topic_id = t.topic_id;

-- Les sujets nous permettent de restreindre les résultats des sondages à un site
CREATE OR REPLACE VIEW forum1_vote_results AS
SELECT vr.*
FROM forums_vote_results vr
INNER JOIN forum1_vote_desc vd ON vr.vote_id = vd.vote_id;

-- Les sujets nous permettent de restreindre les votants des sondages à un site
CREATE OR REPLACE VIEW forum1_vote_voters AS
SELECT vv.*
FROM forums_vote_voters vv
INNER JOIN forum1_vote_desc vt ON vv.vote_id = vt.vote_id;

Forum 2 :

-- Les catégories ont l'identifiant du site de destination
CREATE OR REPLACE VIEW forum2_categories AS
SELECT *
FROM forums_categories
WHERE site_id IN (0, 2);

-- Ces catégories nous permettent de restreindre les forums à un site
CREATE OR REPLACE VIEW forum2_forums AS
SELECT f.*
FROM forums_forums f
INNER JOIN forum2_categories c ON f.cat_id = c.cat_id;

-- Ces forums nous permettent de restreindre les sujets à un site
CREATE OR REPLACE VIEW forum2_topics AS
SELECT t.*
FROM forums_topics t
INNER JOIN forum2_forums f ON t.forum_id = f.forum_id;

-- Ces sujets nous permettent de restreindre les messages à un site
CREATE OR REPLACE VIEW forum2_posts AS
SELECT p.*
FROM forums_posts p
INNER JOIN forum2_topics t ON p.topic_id = t.topic_id;

-- Ces messages nous permettent de restreindre leur contenu à un site
CREATE OR REPLACE VIEW forum2_posts_text AS
SELECT pt.*
FROM forums_posts_text pt
INNER JOIN forum2_posts p ON p.post_id = pt.post_id;

-- Les forums nous permettent de restreindre les autorisations à un site
CREATE OR REPLACE VIEW forum2_forum_prune AS
SELECT fp.*
FROM forums_forum_prune fp
INNER JOIN forum2_forums f ON fp.forum_id = f.forum_id;

-- Les sujets nous permettent de restreindre leur surveillance à un site
CREATE OR REPLACE VIEW forum2_topics_watch AS
SELECT tw.*
FROM forums_topics_watch tw
INNER JOIN forum2_topics t ON tw.topic_id = t.topic_id;

-- Les sujets nous permettent de restreindre les sondages à un site
CREATE OR REPLACE VIEW forum2_vote_desc AS
SELECT vd.*
FROM forums_vote_desc vd
INNER JOIN forum2_topics t ON vd.topic_id = t.topic_id;

-- Les sujets nous permettent de restreindre les résultats des sondages à un site
CREATE OR REPLACE VIEW forum2_vote_results AS
SELECT vr.*
FROM forums_vote_results vr
INNER JOIN forum2_vote_desc vd ON vr.vote_id = vd.vote_id;

-- Les sujets nous permettent de restreindre les votants des sondages à un site
CREATE OR REPLACE VIEW forum2_vote_voters AS
SELECT vv.*
FROM forums_vote_voters vv
INNER JOIN forum2_vote_desc vt ON vv.vote_id = vt.vote_id;

En cas de problème avec une Vue, relancer la requête devrait suffire à la réparer.

III-D - Le cas des Utilisateurs

Nous utiliserons ici aussi des Vues SQL, mais, cette fois, nous les combinerons avec des tables dans chaque site.

phpBB par défaut :

- phpbb_users

Notre besoin :

- forums_users (table)

- forum1_users_config (table)

- forum1_users (vue = forums_users + forum1_users_config)

- forum2_users_config (table)

- forum2_users (vue = forums_users + forum2_users_config)

La configuration utilisateur par site :

-- Structure (forum 1)
CREATE TABLE forum1_users_config (
user_id MEDIUMINT (8) NOT NULL ,
user_session_time INT (11) NOT NULL DEFAULT '0',
user_session_page SMALLINT (5) NOT NULL DEFAULT '0',
user_lastvisit INT (11) NOT NULL DEFAULT '0',
user_style TINYINT (4) DEFAULT NULL ,
user_lang VARCHAR (255) DEFAULT NULL ,
user_dateformat VARCHAR (14) NOT NULL DEFAULT 'd M Y H:i',
user_rank INT (11) DEFAULT '0',
PRIMARY KEY (user_id) ,
KEY user_session_time (user_session_time)
);

-- Copie des infos des utilisateurs (forum 1)
INSERT INTO forum1_users_config
(user_id, user_session_time, user_session_page, user_lastvisit,
user_style, user_lang, user_dateformat, user_rank)
SELECT user_id, user_session_time, user_session_page, user_lastvisit,
user_style, user_lang, user_dateformat, user_rank
FROM forum1_users;

-- Structure (forum 2)
CREATE TABLE forum2_users_config (
user_id MEDIUMINT (8) NOT NULL ,
user_session_time INT (11) NOT NULL DEFAULT '0',
user_session_page SMALLINT (5) NOT NULL DEFAULT '0',
user_lastvisit INT (11) NOT NULL DEFAULT '0',
user_style TINYINT (4) DEFAULT NULL ,
user_lang VARCHAR (255) DEFAULT NULL ,
user_dateformat VARCHAR (14) NOT NULL DEFAULT 'd M Y H:i',
user_rank INT (11) DEFAULT '0',
PRIMARY KEY (user_id) ,
KEY user_session_time (user_session_time)
);

-- Copie des infos des utilisateurs (forum 2) depuis le forum 1
INSERT INTO forum2_users_config
(user_id, user_session_time, user_session_page, user_lastvisit,
user_style, user_lang, user_dateformat, user_rank)
SELECT user_id, user_session_time, user_session_page, user_lastvisit,
user_style, user_lang, user_dateformat, user_rank
FROM forum1_users;

La configuration partagée :

-- Déplacement de la table des utilisateurs
ALTER TABLE forum1_users RENAME TO forums_users;

-- La table du 2° forum n'est plus utile
DROP TABLE forum2_users;

-- Suppression des champs réservés à a config par site
ALTER TABLE forums_users
DROP user_session_time,
DROP user_session_page,
DROP user_lastvisit,
DROP user_style,
DROP user_lang,
DROP user_dateformat,
DROP user_rank;

Les vues pour lire les données :

-- Forum 1
CREATE OR REPLACE VIEW forum1_users AS
SELECT u.*,
uc.user_session_time, uc.user_session_page, uc.user_lastvisit,
uc.user_style, uc.user_lang, uc.user_dateformat, uc.user_rank
FROM forums_users u
INNER JOIN forum1_users_config uc ON u.user_id = uc.user_id;

-- Forum 2
CREATE OR REPLACE VIEW forum2_users AS
SELECT u.*,
uc.user_session_time, uc.user_session_page, uc.user_lastvisit,
uc.user_style, uc.user_lang, uc.user_dateformat, uc.user_rank
FROM forums_users u
INNER JOIN forum2_users_config uc ON u.user_id = uc.user_id;

IV - Les scripts à retoucher

Ces modifications doivent être apportées aux scripts de chacun des sites concernés !

IV-A - config.php

Pensez à mettre l'identifiant du site en cours (pas nécessairement « 1 »).

Ajouter :

$common_prefix = 'forums_';
$site_id = 1;

IV-B - includes/constants.php

Les « tables de partage » n'utilisent pas le préfixe normal du site, mais un préfixe global, défini plus haut comme « forums_ ».

Trouver :

// Table names
define('CONFIRM_TABLE', $table_prefix.'confirm');
define('AUTH_ACCESS_TABLE', $table_prefix.'auth_access');
define('BANLIST_TABLE', $table_prefix.'banlist');
define('CATEGORIES_TABLE', $table_prefix.'categories');
define('CONFIG_TABLE', $table_prefix.'config');
define('DISALLOW_TABLE', $table_prefix.'disallow');
define('FORUMS_TABLE', $table_prefix.'forums');
define('GROUPS_TABLE', $table_prefix.'groups');
define('POSTS_TABLE', $table_prefix.'posts');
define('POSTS_TEXT_TABLE', $table_prefix.'posts_text');
define('PRIVMSGS_TABLE', $table_prefix.'privmsgs');
define('PRIVMSGS_TEXT_TABLE', $table_prefix.'privmsgs_text');
define('PRIVMSGS_IGNORE_TABLE', $table_prefix.'privmsgs_ignore');
define('PRUNE_TABLE', $table_prefix.'forum_prune');
define('RANKS_TABLE', $table_prefix.'ranks');
define('SEARCH_TABLE', $table_prefix.'search_results');
define('SEARCH_WORD_TABLE', $table_prefix.'search_wordlist');
define('SEARCH_MATCH_TABLE', $table_prefix.'search_wordmatch');
define('SESSIONS_TABLE', $table_prefix.'sessions');
define('SESSIONS_KEYS_TABLE', $table_prefix.'sessions_keys');
define('SMILIES_TABLE', $table_prefix.'smilies');
define('THEMES_TABLE', $table_prefix.'themes');
define('THEMES_NAME_TABLE', $table_prefix.'themes_name');
define('TOPICS_TABLE', $table_prefix.'topics');
define('TOPICS_WATCH_TABLE', $table_prefix.'topics_watch');
define('USER_GROUP_TABLE', $table_prefix.'user_group');
define('USERS_TABLE', $table_prefix.'users');
define('WORDS_TABLE', $table_prefix.'words');
define('VOTE_DESC_TABLE', $table_prefix.'vote_desc');
define('VOTE_RESULTS_TABLE', $table_prefix.'vote_results');
define('VOTE_USERS_TABLE', $table_prefix.'vote_voters');

Remplacer par :

// Table names
define('CONFIRM_TABLE', $common_prefix.'confirm');
define('AUTH_ACCESS_TABLE', $table_prefix.'auth_access');
define('BANLIST_TABLE', $common_prefix.'banlist');
define('CATEGORIES_TABLE', $common_prefix.'categories');
define('ALL_CATEGORIES_TABLE', $common_prefix.'categories');
define('CONFIG_TABLE', $table_prefix.'config');
define('DISALLOW_TABLE', $common_prefix.'disallow');
define('FORUMS_TABLE', $table_prefix.'forums');
define('ALL_FORUMS_TABLE', $common_prefix.'forums');
define('GROUPS_TABLE', $table_prefix.'groups');
define('POSTS_TABLE', $table_prefix.'posts');
define('POSTS_TEXT_TABLE', $table_prefix.'posts_text');
define('PRIVMSGS_TABLE', $common_prefix.'privmsgs');
define('PRIVMSGS_TEXT_TABLE', $common_prefix.'privmsgs_text');
define('PRIVMSGS_IGNORE_TABLE', $common_prefix.'privmsgs_ignore');
define('PRUNE_TABLE', $table_prefix.'forum_prune');
define('RANKS_TABLE', $table_prefix.'ranks');
define('SEARCH_TABLE', $common_prefix.'search_results');
define('SEARCH_WORD_TABLE', $common_prefix.'search_wordlist');
define('SEARCH_MATCH_TABLE', $common_prefix.'search_wordmatch');
define('SESSIONS_TABLE', $table_prefix.'sessions');
define('SESSIONS_KEYS_TABLE', $table_prefix.'sessions_keys');
define('SMILIES_TABLE', $table_prefix.'smilies');
define('THEMES_TABLE', $table_prefix.'themes');
define('THEMES_NAME_TABLE', $table_prefix.'themes_name');
define('TOPICS_TABLE', $table_prefix.'topics');
define('TOPICS_WATCH_TABLE', $table_prefix.'topics_watch');
define('USER_GROUP_TABLE', $table_prefix.'user_group');
define('USERS_TABLE', $table_prefix.'users');
define('ALL_USERS_TABLE', $common_prefix.'users');
define('USERS_CONFIG_TABLE', $table_prefix.'users_config');
define('WORDS_TABLE', $common_prefix.'words');
define('VOTE_DESC_TABLE', $table_prefix.'vote_desc');
define('VOTE_RESULTS_TABLE', $table_prefix.'vote_results');
define('VOTE_USERS_TABLE', $table_prefix.'vote_voters');
define('ALL_SITES_TABLE', $common_prefix.'sites');

IV-C - admin/admin_forums.php

Occupons-nous maintenant de corriger le script d'administration standard des forums.

IV-C-1 - Ajout de forum

Pour une raison que j'ignore (ou à laquelle je n'adhère pas), phpBB ne laisse pas l'identifiant de forum en AUTO_INCREMENT : il utilise plutôt l'identifiant maximum et ajoute 1. Il nous faut modifier ce comportement pour utiliser la table de partage plutôt que la vue SQL, sans quoi nous aurions fréquemment des « duplicate key ».

Trouver :

$sql = "SELECT MAX(forum_id) AS max_id
FROM " . FORUMS_TABLE;

Remplacer par :

$sql = "SELECT MAX(forum_id) AS max_id
FROM " . ALL_FORUMS_TABLE;

IV-C-2 - Ajout de catégorie

Toute nouvelle catégorie doit contenir l'identifiant du site où elle apparaîtra.

Trouver :

$sql = "INSERT INTO " . CATEGORIES_TABLE . " (cat_title, cat_order)
VALUES ('" . str_replace("\'", "''", $HTTP_POST_VARS['categoryname']) . "', $next_order)";

Remplacer par :

$sql = "INSERT INTO " . CATEGORIES_TABLE . " (cat_title, site_id, cat_order)
VALUES ('" . str_replace("\'", "''", $HTTP_POST_VARS['categoryname']) . "', $site_id, $next_order)";

IV-C-3 - Suppression de forum

La suppression d'un forum doit être opérée sur la table partagée et non sur les vues.

Trouver :

"DELETE FROM " . FORUMS_TABLE . "

Remplacer par :

"DELETE FROM " . ALL_FORUMS_TABLE . "

IV-D - includes/prune.php

IV-D-1 - La surveillance des sujets

Trouver :

"DELETE FROM " . TOPICS_WATCH_TABLE . "

Remplacer par :

"DELETE FROM " . ALL_TOPICS_WATCH_TABLE . "

IV-D-2 - Les sujets

Trouver :

"DELETE FROM " . TOPICS_TABLE . "

Remplacer par :

"DELETE FROM " . ALL_TOPICS_TABLE . "

IV-D-3 - Les messages

Trouver :

"DELETE FROM " . POSTS_TABLE . "

Remplacer par :

"DELETE FROM " . ALL_POSTS_TABLE . "

IV-D-4 - Le contenu des messages

Trouver :

"DELETE FROM " . POSTS_TEXT_TABLE . "

Remplacer par :

"DELETE FROM " . ALL_POSTS_TEXT_TABLE . "

IV-E - Le cas des Utilisateurs

Il y a deux manières de modifier explicitement un profil d'utilisateur : l'internaute lui-même avec le script usercp_register.php, ou bien un administrateur au moyen des scripts admin/admin_users.php et admin/admin_ug_auth.php.

Mais ce n'est pas tout : il y a également tous les scripts qui mettent à jour en arrière-plan, par exemple pour les sessions.

IV-E-1 - includes/usercp_register.php

IV-E-1-a - Ajout d'un utilisateur

Trouver :

//
// Get current date
//
$sql = "INSERT INTO " . USERS_TABLE . "    (user_id, username, user_regdate, user_password, user_email, user_icq, user_website, user_occ, user_from, user_interests, user_sig, user_sig_bbcode_uid, user_avatar, user_avatar_type, user_viewemail, user_aim, user_yim, user_msnm, user_attachsig, user_allowsmile, user_allowhtml, user_allowbbcode, user_allow_viewonline, user_notify, user_notify_pm, user_popup_pm, user_timezone, user_dateformat, user_lang, user_style, user_level, user_allow_pm, user_active, user_actkey)
VALUES ($user_id, '" . str_replace("\'", "''", $username) . "', " . time() . ", '" . str_replace("\'", "''", $new_password) . "', '" . str_replace("\'", "''", $email) . "', '" . str_replace("\'", "''", $icq) . "', '" . str_replace("\'", "''", $website) . "', '" . str_replace("\'", "''", $occupation) . "', '" . str_replace("\'", "''", $location) . "', '" . str_replace("\'", "''", $interests) . "', '" . str_replace("\'", "''", $signature) . "', '$signature_bbcode_uid', $avatar_sql, $viewemail, '" . str_replace("\'", "''", str_replace(' ', '+', $aim)) . "', '" . str_replace("\'", "''", $yim) . "', '" . str_replace("\'", "''", $msn) . "', $attachsig, $allowsmilies, $allowhtml, $allowbbcode, $allowviewonline, $notifyreply, $notifypm, $popup_pm, $user_timezone, '" . str_replace("\'", "''", $user_dateformat) . "', '" . str_replace("\'", "''", $user_lang) . "', $user_style, 0, 1, ";
if ( $board_config['require_activation'] == USER_ACTIVATION_SELF || $board_config['require_activation'] == USER_ACTIVATION_ADMIN || $coppa )
{
$user_actkey = gen_rand_string(true);
$key_len = 54 - (strlen($server_url));
$key_len = ( $key_len > 6 ) ? $key_len : 6;
$user_actkey = substr($user_actkey, 0, $key_len);
$sql .= "0, '" . str_replace("\'", "''", $user_actkey) . "')";
}
else
{
$sql .= "1, '')";
}

if ( !($result = $db->sql_query($sql, BEGIN_TRANSACTION)) )
{
message_die(GENERAL_ERROR, 'Could not insert data into users table', '', __LINE__, __FILE__, $sql);
}

$sql = "INSERT INTO " . GROUPS_TABLE . " (group_name, group_description, group_single_user, group_moderator)
VALUES ('', 'Personal User', 1, 0)";
if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not insert data into groups table', '', __LINE__, __FILE__, $sql);
}

$group_id = $db->sql_nextid();

$sql = "INSERT INTO " . USER_GROUP_TABLE . " (user_id, group_id, user_pending)
VALUES ($user_id, $group_id, 0)";
if( !($result = $db->sql_query($sql, END_TRANSACTION)) )
{
message_die(GENERAL_ERROR, 'Could not insert data into user_group table', '', __LINE__, __FILE__, $sql);
}

Remplacer par :

$sql = 'SELECT site_users_config_table, site_groups_table, site_user_groups_table, site_config_table
FROM ' . ALL_SITES_TABLE;
if ( !($q_sites = $db->sql_query($sql, BEGIN_TRANSACTION)) )
{
message_die(GENERAL_ERROR, 'Could not get Sites data', '', __LINE__, __FILE__, $sql);
}

//
// We need to insert the user config for each site
//
if($db->sql_numrows($q_sites))
{
$site_rows = $db->sql_fetchrowset($q_sites);
foreach($site_rows as $site_row)
{
//
// We don't know if the lang & style chosen by the user
// will be available for all the sites,
// so let's take the board default lang & style instead
//
$sql = "REPLACE INTO " . $site_row['site_users_config_table'] . "    (user_id, user_dateformat, user_lang, user_style)
VALUES ($user_id, '" . str_replace("\'", "''", $user_dateformat) . "',
(
SELECT MAX(config_value)
FROM " . $site_row['site_config_table'] . "
WHERE config_name = 'default_lang'
),
(
SELECT MAX(config_value)
FROM " . $site_row['site_config_table'] . "
WHERE config_name = 'default_style'
))";
if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not insert data into users config table', '', __LINE__, __FILE__, $sql);
}

$sql = "REPLACE INTO " . $site_row['site_groups_table'] . " (group_name, group_description, group_single_user, group_moderator)
VALUES ('', 'Personal User', 1, 0)";
if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not insert data into groups table', '', __LINE__, __FILE__, $sql);
}

$group_id = $db->sql_nextid();

$sql = "REPLACE INTO " . $site_row['site_user_groups_table'] . " (user_id, group_id, user_pending)
VALUES ($user_id, $group_id, 0)";
if( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not insert data into user_group table', '', __LINE__, __FILE__, $sql);
}
}
}

$sql = "INSERT INTO " . ALL_USERS_TABLE . "    (user_id, username, user_regdate, user_password, user_email, user_icq, user_website, user_occ, user_from, user_interests, user_sig, user_sig_bbcode_uid, user_avatar, user_avatar_type, user_viewemail, user_aim, user_yim, user_msnm, user_attachsig, user_allowsmile, user_allowhtml, user_allowbbcode, user_allow_viewonline, user_notify, user_notify_pm, user_popup_pm, user_timezone, user_level, user_allow_pm, user_active, user_actkey)
VALUES ($user_id, '" . str_replace("\'", "''", $username) . "', " . time() . ", '" . str_replace("\'", "''", $new_password) . "', '" . str_replace("\'", "''", $email) . "', '" . str_replace("\'", "''", $icq) . "', '" . str_replace("\'", "''", $website) . "', '" . str_replace("\'", "''", $occupation) . "', '" . str_replace("\'", "''", $location) . "', '" . str_replace("\'", "''", $interests) . "', '" . str_replace("\'", "''", $signature) . "', '$signature_bbcode_uid', $avatar_sql, $viewemail, '" . str_replace("\'", "''", str_replace(' ', '+', $aim)) . "', '" . str_replace("\'", "''", $yim) . "', '" . str_replace("\'", "''", $msn) . "', $attachsig, $allowsmilies, $allowhtml, $allowbbcode, $allowviewonline, $notifyreply, $notifypm, $popup_pm, $user_timezone, 0, 1, ";
if ( $board_config['require_activation'] == USER_ACTIVATION_SELF || $board_config['require_activation'] == USER_ACTIVATION_ADMIN || $coppa )
{
$user_actkey = gen_rand_string(true);
$key_len = 54 - (strlen($server_url));
$key_len = ( $key_len > 6 ) ? $key_len : 6;
$user_actkey = substr($user_actkey, 0, $key_len);
$sql .= "0, '" . str_replace("\'", "''", $user_actkey) . "')";
}
else
{
$sql .= "1, '')";
}

if ( !($result = $db->sql_query($sql, END_TRANSACTION)) )
{
message_die(GENERAL_ERROR, 'Could not insert data into global users table', '', __LINE__, __FILE__, $sql);
}

IV-E-1-b - Mise à jour d'un utilisateur

Trouver :

$sql = "UPDATE " . USERS_TABLE . "
SET " . $username_sql . $passwd_sql . "user_email = '" . str_replace("\'", "''", $email) ."', user_icq = '" . str_replace("\'", "''", $icq) . "', user_website = '" . str_replace("\'", "''", $website) . "', user_occ = '" . str_replace("\'", "''", $occupation) . "', user_from = '" . str_replace("\'", "''", $location) . "', user_interests = '" . str_replace("\'", "''", $interests) . "', user_sig = '" . str_replace("\'", "''", $signature) . "', user_sig_bbcode_uid = '$signature_bbcode_uid', user_viewemail = $viewemail, user_aim = '" . str_replace("\'", "''", str_replace(' ', '+', $aim)) . "', user_yim = '" . str_replace("\'", "''", $yim) . "', user_msnm = '" . str_replace("\'", "''", $msn) . "', user_attachsig = $attachsig, user_allowsmile = $allowsmilies, user_allowhtml = $allowhtml, user_allowbbcode = $allowbbcode, user_allow_viewonline = $allowviewonline, user_notify = $notifyreply, user_notify_pm = $notifypm, user_popup_pm = $popup_pm, user_timezone = $user_timezone, user_dateformat = '" . str_replace("\'", "''", $user_dateformat) . "', user_lang = '" . str_replace("\'", "''", $user_lang) . "', user_style = $user_style, user_active = $user_active, user_actkey = '" . str_replace("\'", "''", $user_actkey) . "'" . $avatar_sql . "
WHERE user_id = $user_id";
if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not update users table', '', __LINE__, __FILE__, $sql);
}

Remplacer par :

$sql = "UPDATE " . USERS_CONFIG_TABLE . "
SET user_dateformat = '" . str_replace("\'", "''", $user_dateformat) . "', user_lang = '" . str_replace("\'", "''", $user_lang) . "', user_style = $user_style
WHERE user_id = $user_id";
if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not update users config table', '', __LINE__, __FILE__, $sql);
}

$sql = "UPDATE " . ALL_USERS_TABLE . "
SET " . $username_sql . $passwd_sql . "user_email = '" . str_replace("\'", "''", $email) ."', user_icq = '" . str_replace("\'", "''", $icq) . "', user_website = '" . str_replace("\'", "''", $website) . "', user_occ = '" . str_replace("\'", "''", $occupation) . "', user_from = '" . str_replace("\'", "''", $location) . "', user_interests = '" . str_replace("\'", "''", $interests) . "', user_sig = '" . str_replace("\'", "''", $signature) . "', user_sig_bbcode_uid = '$signature_bbcode_uid', user_viewemail = $viewemail, user_aim = '" . str_replace("\'", "''", str_replace(' ', '+', $aim)) . "', user_yim = '" . str_replace("\'", "''", $yim) . "', user_msnm = '" . str_replace("\'", "''", $msn) . "', user_attachsig = $attachsig, user_allowsmile = $allowsmilies, user_allowhtml = $allowhtml, user_allowbbcode = $allowbbcode, user_allow_viewonline = $allowviewonline, user_notify = $notifyreply, user_notify_pm = $notifypm, user_popup_pm = $popup_pm, user_timezone = $user_timezone, user_active = $user_active, user_actkey = '" . str_replace("\'", "''", $user_actkey) . "'" . $avatar_sql . "
WHERE user_id = $user_id";
if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not update users table', '', __LINE__, __FILE__, $sql);
}

IV-E-2 - admin/admin_users.php

IV-E-2-a - Mise à jour d'un utilisateur

Trouver :

$sql = "UPDATE " . USERS_TABLE . "
SET " . $username_sql . $passwd_sql . "user_email = '" . str_replace("\'", "''", $email) . "', user_icq = '" . str_replace("\'", "''", $icq) . "', user_website = '" . str_replace("\'", "''", $website) . "', user_occ = '" . str_replace("\'", "''", $occupation) . "', user_from = '" . str_replace("\'", "''", $location) . "', user_interests = '" . str_replace("\'", "''", $interests) . "', user_sig = '" . str_replace("\'", "''", $signature) . "', user_viewemail = $viewemail, user_aim = '" . str_replace("\'", "''", $aim) . "', user_yim = '" . str_replace("\'", "''", $yim) . "', user_msnm = '" . str_replace("\'", "''", $msn) . "', user_attachsig = $attachsig, user_sig_bbcode_uid = '$signature_bbcode_uid', user_allowsmile = $allowsmilies, user_allowhtml = $allowhtml, user_allowavatar = $user_allowavatar, user_allowbbcode = $allowbbcode, user_allow_viewonline = $allowviewonline, user_notify = $notifyreply, user_allow_pm = $user_allowpm, user_notify_pm = $notifypm, user_popup_pm = $popuppm, user_lang = '" . str_replace("\'", "''", $user_lang) . "', user_style = $user_style, user_timezone = $user_timezone, user_dateformat = '" . str_replace("\'", "''", $user_dateformat) . "', user_active = $user_status, user_rank = $user_rank" . $avatar_sql . "
WHERE user_id = $user_id";

Remplacer par :

$sql = "UPDATE " . USERS_CONFIG_TABLE . "
SET user_lang = '" . str_replace("\'", "''", $user_lang) . "', user_style = $user_style, user_dateformat = '" . str_replace("\'", "''", $user_dateformat) . "', user_rank = $user_rank
WHERE user_id = $user_id";
if( ! $db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Admin_user_fail', '', __LINE__, __FILE__, $sql);
}

$sql = "UPDATE " . ALL_USERS_TABLE . "
SET " . $username_sql . $passwd_sql . "user_email = '" . str_replace("\'", "''", $email) . "', user_icq = '" . str_replace("\'", "''", $icq) . "', user_website = '" . str_replace("\'", "''", $website) . "', user_occ = '" . str_replace("\'", "''", $occupation) . "', user_from = '" . str_replace("\'", "''", $location) . "', user_interests = '" . str_replace("\'", "''", $interests) . "', user_sig = '" . str_replace("\'", "''", $signature) . "', user_viewemail = $viewemail, user_aim = '" . str_replace("\'", "''", $aim) . "', user_yim = '" . str_replace("\'", "''", $yim) . "', user_msnm = '" . str_replace("\'", "''", $msn) . "', user_attachsig = $attachsig, user_sig_bbcode_uid = '$signature_bbcode_uid', user_allowsmile = $allowsmilies, user_allowhtml = $allowhtml, user_allowavatar = $user_allowavatar, user_allowbbcode = $allowbbcode, user_allow_viewonline = $allowviewonline, user_notify = $notifyreply, user_allow_pm = $user_allowpm, user_notify_pm = $notifypm, user_popup_pm = $popuppm, user_timezone = $user_timezone, user_active = $user_status" . $avatar_sql . "
WHERE user_id = $user_id";

IV-E-2-b - Suppression d'un utilisateur

Trouver :

$sql = "DELETE FROM " . USERS_TABLE . "
WHERE user_id = $user_id";
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Could not delete user', '', __LINE__, __FILE__, $sql);
}

$sql = "DELETE FROM " . USER_GROUP_TABLE . "
WHERE user_id = $user_id";
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Could not delete user from user_group table', '', __LINE__, __FILE__, $sql);
}

$sql = "DELETE FROM " . GROUPS_TABLE . "
WHERE group_id = " . $row['group_id'];
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Could not delete group for this user', '', __LINE__, __FILE__, $sql);
}

Remplacer par :

$sql = "DELETE FROM " . ALL_USERS_TABLE . "
WHERE user_id = $user_id";
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Could not delete user', '', __LINE__, __FILE__, $sql);
}

$sql = 'SELECT site_users_config_table, site_groups_table, site_user_groups_table
FROM ' . ALL_SITES_TABLE;
if ( !($q_sites = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, 'Could not get Sites data', '', __LINE__, __FILE__, $sql);
}

//
// We need to delete the user config for each site
//
if($db->sql_numrows($q_sites))
{
$site_rows = $db->sql_fetchrowset($q_sites);
foreach($site_rows as $site_row)
{
$sql = "DELETE FROM " . $site_row['site_users_config_table'] . "
WHERE user_id = $user_id";
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Could not delete user', '', __LINE__, __FILE__, $sql);
}

$sql = "DELETE FROM " . $site_row['site_user_groups_table'] . "
WHERE user_id = $user_id";
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Could not delete user from user_group table', '', __LINE__, __FILE__, $sql);
}

$sql = "DELETE FROM " . $site_row['site_groups_table'] . "
WHERE group_id = " . $row['group_id'];
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, 'Could not delete group for this user', '', __LINE__, __FILE__, $sql);
}
}
}

IV-E-3 - Champs spécifiques à un site

Dans les scripts suivants :

- includes/sessions.php

Trouver tous :

"UPDATE " . USERS_TABLE . "

Remplacer tous par :

"UPDATE " . USERS_CONFIG_TABLE . "

IV-E-4 - Champs partagés par tous les sites

Dans les scripts suivants :

- admin/admin_forums.php

- admin/admin_groups.php

- admin/admin_ranks.php

- admin/admin_styles.php

- admin/admin_ug_auth.php

- includes/functions_post.php

- includes/page_header.php

- includes/usercp_activate.php

- includes/usercp_email.php

- includes/usercp_sendpasswd.php

- groupcp.php

- privmsg.php

Trouver tous :

$sql = "UPDATE " . USERS_TABLE . "

Remplacer tous par :

$sql = "UPDATE " . ALL_USERS_TABLE . "

Dans les scripts suivants :

- modcp.php

Trouver :

$count_sql[] = "UPDATE " . USERS_TABLE . "

Remplacer par :

$count_sql[] = "UPDATE " . ALL_USERS_TABLE . "

V - Le nouveau module d'administration

Nous avons la structure et nos scripts sont prêts à l'utiliser. Il ne nous reste plus qu'à prévoir une interface permettant de transférer une catégorie depuis un site vers un autre : les sujets et messages suivront la catégorie à laquelle ils appartiennent.

V-A - Les variables de langue

Dans les scripts suivants :

- language/lang_english/lang_admin.php

Trouver :

//
// That's all Folks!
// -------------------------------------------------

Remplacer par :

//
// Module to move forums from one site to another
//
$lang['Migrate'] = 'Migrating';
$lang['Category'] = 'Category';
$lang['Destination'] = 'Destination';
$lang['Forums'] = 'Forums';
$lang['Topics'] = 'Topics';
$lang['Posts'] = 'Posts';

//
// That's all Folks!
// -------------------------------------------------

Il faut appliquer cette modification pour chacune des langues du forum !

V-B - Le gabarit du script

Créer le fichier :

- templates/subSilver/admin/forum_admin_migrate.tpl

forum_admin_migrate.tpl

<h1>{L_FORUM_TITLE}</h1>

<p>{L_FORUM_EXPLAIN}</p>

<table width="100%" cellpadding="4" cellspacing="1" border="0" class="forumline" align="center">
<!-- BEGIN siterow -->
<tr>
<th class="thHead" colspan="5">{siterow.SITE_URI}</th>
</tr>
<tr>
<td class="catLeft"><span class="gen"><b>{L_CATEGORY}</b></span></td>
<td class="catLeft" align="center" valign="middle"><span class="gen"><b>{L_DESTINATION}</b></span></td>
<td class="catLeft" align="center" valign="middle"><span class="gen"><b>{L_FORUMS}</b></span></td>
<td class="catLeft" align="center" valign="middle"><span class="gen"><b>{L_TOPICS}</b></span></td>
<td class="catLeft" align="center" valign="middle"><span class="gen"><b>{L_POSTS}</b></span></td>
</tr>
<!-- BEGIN catrow -->
<tr>
<td class="row1"><span class="cattitle"><b><a href="{siterow.catrow.U_VIEWCAT}">{siterow.catrow.CAT_DESC}</a></b></span></td>
<td class="row2" align="center" valign="middle">
<form method="post" action="{S_FORUM_ACTION}">
<select name="site_id">
<!-- BEGIN site -->
<option value="{siterow.catrow.site.SITE_ID}" class="liteoption">{siterow.catrow.site.SITE_URI}</option>
<!-- END site -->
</select>
<input type="hidden" name="cat_id" value="{siterow.catrow.CAT_ID}" />
<input type="submit" value="Envoyer" class="mainoption" />
</form>
</td>
<td class="row1" align="center" valign="middle"><span class="gen">{siterow.catrow.NUM_FORUMS}</span></td>
<td class="row2" align="center" valign="middle"><span class="gen">{siterow.catrow.NUM_TOPICS}</span></td>
<td class="row1" align="center" valign="middle"><span class="gen">{siterow.catrow.NUM_POSTS}</span></td>
</tr>
<tr>
<td colspan="5" height="1" class="spaceRow"><img src="../templates/lpch_cinema/images/spacer.gif" alt="" width="1" height="1" /></td>
</tr>
<!-- END catrow -->
<!-- END siterow -->
</table>

Il faut créer ce fichier pour chacun des templates du forum !

V-C - Le script

Créer le fichier :

- admin/admin_migrate.php

admin_migrate.php

<?php
/***************************************************************************
*                             admin_migrate.php
*                            -------------------
*    begin                : Monday, May 1, 2007
*    copyright            : (C) Guillaume Rossolini
*    email                : g-rossolini@redaction-developpez.com
*
***************************************************************************/

/***************************************************************************
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
***************************************************************************/

define('IN_PHPBB', 1);

if( !empty($setmodules) )
{
$file = basename(__FILE__);
$module['Forums']['Migrate'] = $file;
return;
}

//
// Load default header
//
$phpbb_root_path = "./../";
require($phpbb_root_path . 'extension.inc');
require('./pagestart.' . $phpEx);
include($phpbb_root_path . 'includes/functions_admin.'.$phpEx);

//
// Mode setting
//
if( isset($HTTP_POST_VARS['mode']) || isset($HTTP_GET_VARS['mode']) )
{
$mode = ( isset($HTTP_POST_VARS['mode']) ) ? $HTTP_POST_VARS['mode'] : $HTTP_GET_VARS['mode'];
$mode = htmlspecialchars($mode);
}
else
{
$mode = "";
}

//
// Begin program proper
//
if(strtolower($_SERVER['REQUEST_METHOD']) == 'post')
{
$sql = 'UPDATE ' . ALL_CATEGORIES_TABLE . '
SET site_id = ' . intval($_POST['site_id']) . '
WHERE cat_id = ' . intval($_POST['cat_id']);
if( !$db->sql_query($sql) )
{
message_die(GENERAL_ERROR, "Couldn't update the Category", "", __LINE__, __FILE__, $sql);
}
}

$sql = "SELECT site_id, site_uri
FROM " . ALL_SITES_TABLE . "
ORDER BY site_uri";
if( !$q_sites = $db->sql_query($sql) )
{
message_die(GENERAL_ERROR, "Couldn't get list of Sites", "", __LINE__, __FILE__, $sql);
}

if($db->sql_numrows($q_sites))
{
$site_rows = $db->sql_fetchrowset($q_sites);

foreach($site_rows as $site_row)
{
$template->assign_block_vars('siterow', array(
'SITE_URI' => $site_row['site_uri'])
);

$sql = "SELECT c.cat_id, c.cat_title, c.cat_order, c.site_id,
(
SELECT COUNT(*)
FROM " . ALL_FORUMS_TABLE . " f
WHERE f.cat_id = c.cat_id
) num_forums,
(
SELECT COUNT(*)
FROM " . ALL_TOPICS_TABLE . " t
INNER JOIN " . ALL_FORUMS_TABLE . " f ON t.forum_id = f.forum_id
WHERE f.cat_id = c.cat_id
) num_topics,
(
SELECT COUNT(*)
FROM " . ALL_POSTS_TABLE . " p
INNER JOIN " . ALL_TOPICS_TABLE . " t ON p.topic_id = t.topic_id
INNER JOIN " . ALL_FORUMS_TABLE . " f ON t.forum_id = f.forum_id
WHERE f.cat_id = c.cat_id
) num_posts
FROM " . ALL_CATEGORIES_TABLE . " c
WHERE site_id = " . $site_row['site_id'] . "
ORDER BY cat_order";
if( !$q_categories = $db->sql_query($sql) )
{
message_die(GENERAL_ERROR, "Couldn't get list of Categories", "", __LINE__, __FILE__, $sql);
}

if( $db->sql_numrows($q_categories) )
{
$category_rows = $db->sql_fetchrowset($q_categories);
foreach($category_rows as $i => $category_row)
{
$template->assign_block_vars('siterow.catrow', array(
'CAT_ID' => $category_row['cat_id'],
'CAT_DESC' => $category_row['cat_title'],
'NUM_FORUMS' => $category_row['num_forums'],
'NUM_TOPICS' => $category_row['num_topics'],
'NUM_POSTS' => $category_row['num_posts'],
'U_VIEWCAT' => append_sid($phpbb_root_path."index.$phpEx?" . POST_CAT_URL . "=$category_row[cat_id]"))
);

$sql = "SELECT site_id, site_uri
FROM " . ALL_SITES_TABLE . "
WHERE site_id <> " . $category_row['site_id'] . "
ORDER BY site_uri";
if( !$q_catsites = $db->sql_query($sql) )
{
message_die(GENERAL_ERROR, "Couldn't get list of Sites", "", __LINE__, __FILE__, $sql);
}

if($db->sql_numrows($q_catsites))
{
$catsites = $db->sql_fetchrowset($q_catsites);
foreach($catsites as $catsite)
{
$template->assign_block_vars('siterow.catrow.site', array(
'SITE_ID' => $catsite['site_id'],
'SITE_URI' => $catsite['site_uri'])
);
}
}
}
}
}
}

//
// Start page proper
//
$template->set_filenames(array(
"body" => "admin/forum_admin_migrate.tpl")
);

$template->assign_vars(array(
'S_FORUM_ACTION' => append_sid("admin_migrate.$phpEx"),
'L_CATEGORY' => $lang['Category'],
'L_DESTINATION' => $lang['Destination'],
'L_FORUMS' => $lang['Forums'],
'L_TOPICS' => $lang['Topics'],
'L_POSTS' => $lang['Posts'],
'L_FORUM_TITLE' => $lang['Forum_admin'],
'L_FORUM_EXPLAIN' => $lang['Forum_admin_explain'])
);

$template->pparse("body");

include('./page_footer_admin.'.$phpEx);

?>

VI - Correction du référencement

Puisque nous sommes en train de déplacer le contenu d'un site à l'autre, il est bon de penser au suivi des liens déjà référencés. Cela fait toujours mauvaise figure d'avoir un lien mort, surtout lorsqu'on peut y remédier…

VI-A - Lecture d'un forum déplacé

Dans le script suivant :

- viewforum.php

Chercher :

if ( !($forum_row = $db->sql_fetchrow($result)) )
{
message_die(GENERAL_MESSAGE, 'Forum_not_exist');
}

Remplacer par :

if ( !($forum_row = $db->sql_fetchrow($result)) )
{
$sql = 'SELECT site_uri, f.forum_id
FROM ' . ALL_SITES_TABLE . ' s
INNER JOIN ' . ALL_CATEGORIES_TABLE . ' c ON c.site_id = s.site_id
INNER JOIN ' . ALL_FORUMS_TABLE . ' f ON f.cat_id = c.cat_id
WHERE f.forum_id = ' . $forum_id;

if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, "Could not obtain forum information", '', __LINE__, __FILE__, $sql);
}

if( $forum_topic_data = $db->sql_fetchrow($result) )
{
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . $forum_topic_data['site_uri'] . "viewforum.$phpEx?" . POST_FORUM_URL . "=$forum_id");
}

message_die(GENERAL_MESSAGE, 'Forum_not_exist');
}

VI-B - Lecture d'un sujet ou d'un message déplacé

Dans le script suivant :

- viewtopic.php

Chercher :

if ( !($forum_topic_data = $db->sql_fetchrow($result)) )
{
message_die(GENERAL_MESSAGE, 'Topic_post_not_exist');
}

Remplacer par :

if ( !($forum_topic_data = $db->sql_fetchrow($result)) )
{
if($post_id)
{
$sql = 'SELECT site_uri, t.topic_id
FROM ' . ALL_SITES_TABLE . ' s
INNER JOIN ' . ALL_CATEGORIES_TABLE . ' c ON c.site_id = s.site_id
INNER JOIN ' . ALL_FORUMS_TABLE . ' f ON f.cat_id = c.cat_id
INNER JOIN ' . ALL_TOPICS_TABLE . ' t ON t.forum_id = f.forum_id
INNER JOIN ' . ALL_POSTS_TABLE . ' p ON p.topic_id = t.topic_id
WHERE p.post_id = ' . $post_id;

if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, "Could not obtain topic information", '', __LINE__, __FILE__, $sql);
}

if( $forum_topic_data = $db->sql_fetchrow($result) )
{
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . $forum_topic_data['site_uri'] . "viewtopic.$phpEx?" . POST_TOPIC_URL . "=" . $forum_topic_data['topic_id'] . "#$post_id");
}
}
else
{
$sql = 'SELECT site_uri, t.topic_id
FROM ' . ALL_SITES_TABLE . ' s
INNER JOIN ' . ALL_CATEGORIES_TABLE . ' c ON c.site_id = s.site_id
INNER JOIN ' . ALL_FORUMS_TABLE . ' f ON f.cat_id = c.cat_id
INNER JOIN ' . ALL_TOPICS_TABLE . ' t ON t.forum_id = f.forum_id
WHERE t.topic_id = ' . $topic_id;

if ( !($result = $db->sql_query($sql)) )
{
message_die(GENERAL_ERROR, "Could not obtain topic information", '', __LINE__, __FILE__, $sql);
}

if( $forum_topic_data = $db->sql_fetchrow($result) )
{
header('HTTP/1.0 301 Moved Permanently');
header('Location: ' . $forum_topic_data['site_uri'] . "viewtopic.$phpEx?" . POST_TOPIC_URL . "=$topic_id");
}
}

message_die(GENERAL_MESSAGE, 'Topic_post_not_exist');
}

VII - Conclusion

VII-A - Épilogue

J'ai décrit ma méthode pour une installation standard de phpBB2. Il est évident qu'il faut l'adapter pour l'utiliser sur un forum en production, et surtout essayer sur une copie du véritable forum. N'appliquez PAS cette méthode directement sur votre forum, car les modifications proposées s'appliquent à la structure du forum !

VII-B - Liens

- Tutoriels phpBB ;

- Tutoriels PHP/MySQL ;

- Cours MySQL.