Le plugin hash_documents

Le nombre de documents dans le répertoire IMG/{$ext}/ du site peut devenir beaucoup trop important et avoir un impact sur les performances du système de fichiers du serveur. La solution proposée par ce plugin est de « hasher » le répertoire IMG/.

De manière à limiter le nombre d’inode dans chaque sous-dossier de IMG/, on répartit automatiquement les fichiers dans des sous-sous-répertoires. La structure passe ainsi de
IMG/mp3/fichier-son.mp3
à
IMG/mp3/a/b/c/fichier-son.mp3

Ce plugin s’occupe de tout pour vous.

En SPIP 2, une page ecrire/?exec=hash_documents permet d’aller hasher tous les documents déjà installés (mais il n’est pas indispensable de l’utiliser pour que ça fonctionne). On peut à tout moment revenir en arrière (grâce à cette même page). En SPIP3, elle est accessible via la page d’administration des plugins (ecrire/?exec=configurer_hasher).

Dans tous les cas, la désactivation du plugin n’empêche pas le site de fonctionner normalement.

Ci-dessous, les explications techniques :

Structure du hashage

le sous-répertoire a/b/c/ doit être calculé de manière à ce que la répartition des documents soit homogène et prévisible. On utilisera pour ce faire une fonction de hashage très simple consistant à prendre les n premiers caractères du md5 du nom du fichier.

md5 ayant une représentation hexa, le nombre de sous-répertoires ainsi créés sera de l’ordre de 16^n ; pour répartir correctement un million de documents, on a les possibilités suivantes :

— n=1 16 répertoires * 62500 docs
— n=2 256 rép * 3900 docs
— n=3 4096 rép * 244 docs

Dans cette implémentation, on utilise 3 niveaux de sous-répertoires : pour un fichier d’origine situé dans IMG/{$ext}/xxxx.ext, le hasher consiste à prendre les 3 premiers caractères (a, b, c) du md5(xxxx.ext), et déplacer le fichier dans IMG/$ext/a/b/c/xxxx.ext.

fonction : function hasher_adresser_document(xxxx.ext)

Déplacement d’un document

fonction : function hasher_deplacer_document($id_document) {}

Cette fonction a pour rôle de déplacer un document proprement de sa position non hashée vers sa position hashée. Tous les contrôles d’erreur sont mis en place afin de garantir que tout se passe bien : si la création du sous-répertoire échoue, par exemple, ou si la connexion à la base de données est tombée, il faut pouvoir reprendre.

Elle appelle hasher_adresser_document()

Conversion « batch »

fonction : function hasher_deplacer_n_documents($n) {}

Cette fonction prend les n documents non hashés les plus récents, et appelle hasher_deplacer_document() sur chacun d’eux. Elle renvoie un array() contenant les id_document des documents qu’elle a déplacés.

Elle peut servir à convertir l’existant (on l’appelle répétitivement jusqu’à épuisement du stock), ou juste après un upload (en SPIP 1.9.2, car en SPIP 2 le cas de l’upload est géré nativement via le pipeline ad hoc), ou un spip2spip, afin de hasher les documents qu’on vient d’ajouter [1].

Elle peut aussi être appelée depuis la page ecrire/?exec=hash_documents

Gestion de redirection

Lorsqu’un document a été déplacé, on souhaite qu’un hit sur son ancienne adresse renvoie vers la nouvelle adresse, avec un code HTTP 301 Moved Permanently (redirection définitive).

Ceci permet, d’une part, de gérer proprement la migration ; d’autre part, ça implique qu’il n’est pas indispensable de hasher les documents juste après l’upload, donc beaucoup de souplesse dans l’intégration.

On va pour ce faire ajouter un .htaccess dans le répertoire IMG/ qui lancera, sur les fichiers non trouvés, un script de redirection écrit en PHP ; ce dernier calculera l’adresse hashée du document demandé, vérifiera si ce document est présent, et en fonction du résultat renverra soit un code 301 vers ce document, soit un 404 Not Found.

Le script PHP est le fichier hash_404.php présent dans le plugin ; la seule petite difficulté pour son activation, c’est qu’il nécessite la création d’un .htaccess spécifique dans le répertoire IMG/ contenant le code suivant :

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
# Si spip est range a la racine du domaine
RewriteRule .* ../index.php?action=hash_404 [L] 
# Pour un mutualise, vaut mieux travailler en url absolue
#RewriteRule .* /index.php?action=hash_404 [L]

En fonction de la configuration technique de l’hébergeur, il faudra peut-être adapter un peu ce .htaccess.

Compatibilité

Il est important de noter que la structure proposée pour le code offre nativement une grande compatibilité, puisque, une fois les documents hashés, on peut retirer tout le code de hachage sans impact sur le fonctionnement.

On a pris soin de ne pas utiliser de fonctions « fragiles » de SPIP, qui changeraient d’une version à l’autre, afin que ce plugin soit compatible de SPIP 1.9.2 aux SPIP futurs.

La seule difficulté à prendre en compte est que le nommage des documents dans la table spip_documents a changé entre SPIP 1.9.2 et la série SPIP 2.0. En SPIP 1.9.2, en effet, spip_documents.fichier contenait une chaîne de la forme IMG/jpg/postcards.jpg, tandis qu’en SPIP 2 on a simplement jpg/postcards.jpg (le IMG/ a été supprimé).

Le plugin fonctionne nativement avec les deux représentations (avec ou sans IMG/).

Réversibilité

Les fonctions de hashage sont réversibles : un paramètre $rev permet de revenir à la structure « à plat ». Cela permet de revenir en arrière si finalement on ne souhaitait pas utiliser ce système, ou pour en utiliser un autre. Cela a aussi permis de tester le plugin, lors de son développement, en faisant des allers-retours.

Notes

[1Patch à appliquer aux fonctions qui ajoutent des fichiers dans spip_documents :

// hasher les documents
include_spip('hash_fonctions');
if (function_exists('hasher_deplacer_n_documents')) {
  hasher_deplacer_n_documents(10);
}

Discussion

3 discussions

  • 11

    Bonjour,
    Depuis le passage de SPIP à la version 4.0.2, le plugin ne fonctionne plus : les nouveaux documents sont stockés à la racine du répertoire de l’extension.
    De plus, étrangement, s’il est toujours possible de hasher et déhasher les anciens documents (ceux ajoutés avant le passage à la 4.0.2), cela n’est plus possible pour ceux ajouter après le passage (la liste des Id des documents modifiés est vides). Je dis « étrangement » parce que rien dans la base de données ne semble différencier les uns et les autres...

    • Je viens de tester avec spip 4.0.4 + plugin en v3.0.0 > pas de souci de mon côté.

    • Est-ce que ça pourrait venir de PHP 8.1 ? Comment le vérifier ?

    • Cela vient peut-être de PHP8.1 (mais c’était déjà le cas auparavant). Comment le vérifier ?

    • Ah c’est possible... je vais voir si j’arrive à me mettre une 8.1...

    • En 8.1 mais avec la version de dev de SPIP : ca marche.

      En 8.1 avec spip 4.1.0-alpha : ca marche

      En 8.1 avec spip 4.0.4 : j’ai trop de warning pour ne serait-ce qu’arriver à une page d’upload de document.

      A vu de nez, je dirais qu’à mon avis vue que spip 4 n’est pas censé être compatible php 8.1 mais uniquement 8.0, cela pourrait venir de là...

    • J’ai identifié un premier soucis : désormais, les logos apparaissent dans la table spip_documents. Or, le plugin ne les hashe pas.
      Lorsque, depuis la page de configuration, on souhaite hasher 100 documents, mais qu’il n’y a que des logos, le plugin ne hashe rien, alors qu’il peut y avoir des documents à hasher en 101è position.
      En revanche, je n’ai pas trouvé pourquoi l’adresse n’est pas hashée lorsqu’on ajoute un nouveau document.

    • Ah oui, car il y a un presupposé dans la regexp que le nom du dossier = le nom de l’extension.

      Bon, faut reussi à trovuer une regexp qui passe aussi pour les logos...

    • Pour le premier problème, peux tu tester la branche suivante :

      https://git.spip.net/spip-contrib-extensions/hash_documents/src/branch/bugs_gilles

      pour le second problème, difficile de dire, mais vu ce que je te disais sur les compats de spip 4 avec php 8 ce serait pas impossible que le pb viennent de là.

      Tu a accès aux logs PHP ?

    • Cela fonctionne : les logos sont désormais hashés.
      Pour le 2d, il semble avoir disparu lorsque j’ai installé cette branche, peut-être une mauvaise installation lors du passage à la 3.0.0 ?

    • Cela fonctionne : les logos sont désormais hashés.
      Pour le 2è problème, il semble avoir disparu avec cette branche.

    • OK,
      et bien c’est releasé sous le numero v3.0.1

    Répondre à ce message

  • 3

    Bonjour, le plugin ne fonctionne plus sous SPIP 4.0. Sa mise à jour est-elle prévue ?

    • Il faudrait tester en modifiant les bornes dans paquet.xnl pour voir si cela marche, et si c’est le alors on pourra modifier la version distribué. Sinon faudra que quelqu’un s’attelle à la tache d’une maj.

    • Après quelques recherches, il suffit de remplacer la fonction spip_fetch_array() par sql_fetch() dans le fichier hasher_fonctions.php

    • Je vais en profiter pour corriger tous les appels aux vieilles fonctions.

    Répondre à ce message

  • Pour compléter la documentation, pourrait-on préciser à partir de quand ce plugin devient intéressant. De l’ordre de 10kdocument ? 100kdocument ? 1MDocument ?

    Répondre à ce message

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom