Carnet Wiki

Gestion des dossiers /plugins

Version 2 — Novembre 2009 cy_altern

NB : cet article est désormais obsolète puisque la version SPIP SVN intègre la possibilité de déclarer un dossier de plugins personnalisé pour chaque site et que cette possibilité est portée en version 2.0.x par le plugin Multiplug. Pour plus d’infos voir : le fichier plugin.xml de Multiplug

Dans le cas d’une mutualisation pour différents domaines, la bidouille suivante permet de disposer à la fois d’un répertoire de plugin « centralisé » (comme c’est le cas général dans la mutualisation) mais également d’un répertoire /plugins pour certaines des instance de mutualisation (i.e. les sites mutualisés pour lesquels on estime pouvoir faire confiance au webmestre...).

Testé pour le plugin Mutualisation installé pour avoir des sites avec domaines différents avec la configuration suivante :

  • le SPIP « maître » est installé dans /var/www/toto
  • dossier /mutualisation à la racine du SPIP « maître » /var/www/toto/mutualisation
  • les sites mutualisés ont chacun leur nom de domaine et un vhost apache qui pointe sur /var/www/toto
  • chaque site correspond à un sous-dossier de /sites portant le nom de domaine du site : /var/www/toto/sites/mon-site.tld [1]
  • un dossier /plugins (= « central » pour la suite) également à la racine de ce SPIP : celui-ci est utilisé par tous les sites mutualisés (i.e. les plugins dedans sont visibles dans tous les sites) /var/www/toto/plugins
  • la config du apache et des vhost authorise le suivi des liens symboliques (Options FollowSymLinks)

Pour chaque instance de site mutualisé pour laquelle on veut laisser au webmestre la possibilité d’installer des plugins supplémentaires, on crée un sous-dossier /plugins (= « spécifique » pour la suite) dans le sous-dossier de site correspondant : /var/www/toto/sites/mon-site.tld/plugins. On va alors créer un lien symbolique dans le dossier plugins central qui pointe vers ce sous-dossier, ce lien sera nommé avec le nom de domaine du site :
/var/www/toto/plugins/mon-site.tld(=symlink)—>/var/www/toto/sites/mon-site.tld/plugins
Tel quel on se retrouve donc avec tous les plugins de tous les répertoire « spécifiques » mélangés avec ceux du répertoire « central » donc visibles et disponibles pour tous les sites mutualisés, ce qui n’est pas exactement le but recherché...

Il reste donc à « filtrer » les liens symboliques qui seront suivis en fonction du site : le lien portant le nom de domaine du site, on à donc un moyen simple de « faire le tri ». Ce tri sera fait au niveau de la fonction de SPIP qui scanne le répertoire des plugins : liste_plugin_files() dans le fichier /inc/plugin.php

La seule difficulté pour réaliser cette opération est que cette fonction du core n’est pas surchargeable puisqu’elle n’est pas de la forme nom_de_la_fonction_dist()... Du coup on doit procéder via la surcharge de l’ensemble du fichier /inc/plugin.php ce qui revient à « forker » celui-ci (c’est très mal !).

Pour minimiser la chose et essayer de gérer au mieux les éventuels changements du fichier lors des prochaines versions de SPIP, on peut procéder en faisant une bidouille à base de copie « à la volée » du fichier /inc/plugin.php de la dist et ne modifiant que le strict nécéssaire dans la fonction liste_plugin_files(). Ce qui peut être obtenu de la façon suivante :

  • déclarer /mutualisation dans les répertoires scannés par find_in_path() en l’ajoutant dans les dossiers de squelettes du fichier mes_options.php (après demarrer_site()) :
    $GLOBALS['dossier_squelettes'] .= ':mutualisation';
  • créer un sous-dossier /inc dans /mutualisation
  • créer un fichier plugin.php dans ce dossier et mettre dedans le code suivant :
    <?php
    // mutualisation: pour pouvoir utiliser à la fois le rep /plugins central
    // et le rep /plugins du site via un lien symbolique dans /plugins central, 
    // on filtre la liste des ss-reps de plugins retournée par liste_plugin_files() de /inc/plugin.php
    // ce qui nécessite une mauvaise bidouille pour hacker la fonction  
    // et pour ne pas trop galérer avec les mises à jour du core de SPIP 
    // on recrée le fichier à partir de celui de la dist en ne modifiant que le strict minimum
        $inc_plugin_mutu = _DIR_TMP.'inc_plugin_mutu_'.$GLOBALS['spip_version_code'].'.php';
        if (is_file($inc_plugin_mutu)) include($inc_plugin_mutu);
        else {
          // faire le remplacement dans le code de la fonction pour avoir le filtrage
            $a_remplacer = '$plugin_files[]=substr(dirname($plugin), strlen(_DIR_PLUGINS));';
            $code_sup_mutu = '// filtrage des liens symboliques vers les autres sites de mutu'."\r\n";
            $code_sup_mutu .= '$rep_plugin = explode("/",substr(dirname($plugin), strlen(_DIR_PLUGINS)));'."\r\n";
            $code_sup_mutu .= '$rep_plugin = $rep_plugin[0];'."\r\n";
            $code_sup_mutu .= '$site = str_replace("www.", "", $_SERVER["HTTP_HOST"]);'."\r\n";
            $code_sup_mutu .= 'if (is_link(_DIR_PLUGINS.$rep_plugin) AND $rep_plugin != $site) continue;'."\r\n";
            $code_sup_mutu .= $a_remplacer."\r\n";
            $contenu = file_get_contents(_DIR_RESTREINT.'inc/plugin.php');
            $contenu = str_replace($a_remplacer, $code_sup_mutu, $contenu);
            
          // finalement enregistrer le contenu dans /tmp/inc_plugin_mutu_XXX.php puis l'inclure
            if (function_exists('file_put_contents')) {
                if (!file_put_contents($inc_plugin_mutu, $contenu)) include _DIR_RESTREINT.'inc/plugin.php';
                else include $inc_plugin_mutu;
            }
            else {  // php4
                $fic = fopen($inc_plugin_mutu, 'wb');
                if (!fwrite($fic, $contenu)) include _DIR_RESTREINT.'inc/plugin.php';
                else { 
                    fclose($fic);
                    include $inc_plugin_mutu;
                }
            }
        }
    ?>

    Comme on peut le voir en lisant le code, le principe est de créer un fichier inc_plugin_mutu_XXX.php dans le répertoire /tmp du site mutualisé dans lequel on recopie le fichier /inc/plugin.php de la dist en ajoutant le système de filtrage par remplacement d’une ligne de la fonction liste_plugin_files(). Ce fichier est intégré par un include() dans le fichier en cours (i.e. le fichier qui forke l’original). Une fois ce fichier créé il sera réutilisé tel quel les fois suivantes : chaque site mutualisé dispose donc de son fichier « personnalisé » mis en « cache ».

Le XXX correspond à la version du code de SPIP de façon à ce qu’à chaque modification de la version de SPIP le fichier soit régénéré pour être à jour d’une éventuelle modification du fichier original.