Modules PrestaShop : désinstallation propre, performances et sécurité en production

Procédure ops-friendly pour retirer un module PrestaShop sans casse : inventaire DB, suppression d’overrides/assets, purge cache, mesures TTFB/SQL et checklist sécurité.

Ordinateurs affichant du code entourés de symboles de sécurité numérique.

Table des matières :

  1. Désinstallation propre : ce que le core fait, ce qu’il laisse derrière
  2. Nettoyage base de données : repérer et supprimer les artefacts sans casser la prod
  3. Overrides, assets et cache : les trois sources classiques de “module fantôme”
  4. Modules et performances : mesurer l’impact réel (TTFB, SQL, hooks, OPCache)
  5. Sécuriser les modules en production : surface d’attaque, supply chain, mises à jour
  6. Runbook production : installer, mettre à jour, désinstaller sans downtime inutile

Dans cet article, on parle de désinstallation propre de modules PrestaShop en conditions réelles (production), et de ce que ça implique côté performances et sécurité. Contexte technique visé : PrestaShop 8.1.x et 9.1.x, avec PHP 8.1–8.3 (voire 8.4/8.5 selon votre stack, mais testez) et une approche “ops-friendly” : staging, sauvegardes, logs, runbook.

L’objectif n’est pas “faire du ménage pour faire du ménage”, mais de réduire trois risques très concrets :

  • Risque fonctionnel : un module supprimé laisse un override, une Tab BO ou un hook “fantôme” et casse une page (souvent après une mise à jour PHP/PS).
  • Risque performance : des appels (SQL/HTTP) continuent, ou des assets 404 s’accumulent et dégradent Web Vitals.
  • Risque sécurité / conformité : endpoints et données résiduelles (jetons, logs, données perso) restent accessibles ou conservées trop longtemps (RGPD : minimisation, limitation de conservation).

Désinstallation propre : ce que le core fait, ce qu’il laisse derrière

PrestaShop désinstalle un module en appelant sa méthode uninstall() (celle du module) puis en supprimant l’état “installé” dans la table ps_module et quelques métadonnées (selon la version). Le problème, c’est que le core n’impose pas un contrat strict sur ce que “désinstaller” signifie : si le module ne supprime pas ses clés Configuration, ses tables, ses Tab Back-Office, ses hook_module, ou ses overrides, la boutique se retrouve avec des artefacts.

En pratique, la désinstallation “propre” dépend d’abord de la qualité du module. Si vous développez des modules, structurez votre code proprement (services Symfony, séparation domaine/infrastructure) et pensez au cycle de vie complet install/upgrade/uninstall — c’est exactement ce que détaille l’article interne sur la structure moderne des modules : Module PrestaShop 9 : structure, services et bonnes pratiques Symfony. Si vous intégrez des modules tiers, partez du principe que uninstall() est souvent incomplet : vous devez auditer et compléter.

À garder en tête (souvent oublié en multi-boutique) : un module peut être installé globalement mais activé boutique par boutique. Selon les versions/configurations, vous pouvez donc voir des traces dans des tables de liaison (par exemple liées au multistore), et une “désinstallation” qui n’a pas le même impact qu’une simple “désactivation”. Une désactivation propre peut suffire pour un test A/B (mesurer impact), mais ne nettoie pas ce que l’éditeur a créé (tables, overrides, configuration…).

Côté code, une uninstall() robuste doit être :

  • idempotente (appelable plusieurs fois sans casser),
  • tolérante aux états partiels (install interrompue, upgrade raté),
  • explicite sur la rétention de données (purge totale vs conservation justifiée).

Exemple minimaliste (PHP 8.2, compatible PS 8/9) :

public function uninstall(): bool
{
    // Désinscription hooks
    foreach ([
        'displayHeader',
        'actionFrontControllerSetMedia',
        'actionDispatcher',
    ] as $hook) {
        $this->unregisterHook($hook);
    }

    // Suppression de configuration
    Configuration::deleteByName('MYMODULE_ENABLED');
    Configuration::deleteByName('MYMODULE_API_KEY');

    // Suppression de tabs BO (si vous en avez créé)
    $idTab = (int) Tab::getIdFromClassName('AdminMyModule');
    if ($idTab) {
        $tab = new Tab($idTab);
        $tab->delete();
    }

    // Nettoyage DB (à condition d’avoir une stratégie de rétention claire)
    // Db::getInstance()->execute('DROP TABLE IF EXISTS ...');

    return parent::uninstall();
}

Point important : parent::uninstall() doit être appelé en dernier, sinon vous vous retrouvez avec un module “non installé” dont les hooks/config restent actifs en base dans certains scénarios. Et si vous créez des tables, évitez de les nommer n’importe comment : utilisez un préfixe stable (ps_mymodule_*) pour faciliter l’audit et la purge.

Checklist rapide “module bien élevé” (utile en revue de code interne ou audit d’un tiers) :

  • la méthode uninstall() désenregistre hooks + exceptions de hooks (si utilisées),
  • les Tab BO sont supprimées (et les droits associés suivent),
  • les clés Configuration (et ps_configuration_lang si nécessaire) sont supprimées,
  • les tâches planifiées (cron) sont supprimées ou invalidées,
  • aucun fichier n’est déposé hors du module sans stratégie de retrait (notamment overrides).

Nettoyage base de données : repérer et supprimer les artefacts sans casser la prod

Une désinstallation propre n’est pas juste “supprimer le dossier /modules”. C’est d’abord remettre la base dans un état cohérent. Sur des boutiques ayant vécu (migrations 1.7 → 8 → 9, modules installés/désinstallés à la volée), on retrouve fréquemment : tables orphelines, clés ps_configuration oubliées, entrées de hooks persistantes, cron stockés en DB (selon le module), et surtout des indexes manquants sur des tables “fantômes” qui continuent d’être interrogées (oui, certains modules laissent du code ailleurs, via overrides ou injections).

Avant de toucher à la base : backup (dump SQL + fichiers) et exécution en staging. Côté MySQL/MariaDB, le problème classique n’est pas seulement “DROP TABLE = lent”, c’est surtout le metadata lock : une opération DDL peut attendre (ou bloquer) si des requêtes tiennent un verrou de métadonnées, ce qui se traduit par une latence qui grimpe brutalement en prod. Si vous n’avez pas de routine de maintenance DB, posez les bases (purges, analyse, index, vérifs) : Base de données PrestaShop : routine de maintenance et nettoyage automatisé.

Pour détecter rapidement les artefacts “classiques” :

-- Clés de configuration d’un module (adaptez le prefix)
SELECT name, value
FROM ps_configuration
WHERE name LIKE 'MYMODULE_%'
ORDER BY name;

-- Hooks encore liés à un module désinstallé (module_name)
SELECT hm.id_hook, h.name, m.name AS module_name
FROM ps_hook_module hm
JOIN ps_hook h ON h.id_hook = hm.id_hook
JOIN ps_module m ON m.id_module = hm.id_module
WHERE m.name = 'mymodule'
ORDER BY h.name;

-- Tables candidates (préfixe)
SHOW TABLES LIKE 'ps_mymodule_%';

En complément (souvent utile quand l’éditeur n’a pas préfixé “proprement”) :

-- Tabs Back-Office déposées par un module (class_name typique)
SELECT id_tab, class_name, active
FROM ps_tab
WHERE class_name LIKE 'Admin%MyModule%';

-- Exceptions de hooks (sources fréquentes de bruit/incohérences)
SELECT h.name, hme.file_name, m.name AS module_name
FROM ps_hook_module_exceptions hme
JOIN ps_hook h ON h.id_hook = hme.id_hook
JOIN ps_module m ON m.id_module = hme.id_module
WHERE m.name = 'mymodule';

Une fois l’inventaire fait, vous devez choisir une stratégie : purge totale (drop tables + suppression configuration) ou rétention (garder des données métiers/traçabilité). La rétention est parfois justifiée (ex : logs de paiement, mapping ERP), mais elle doit être explicite, documentée, et compatible RGPD (minimisation, durée de conservation). Dans l’UE, la logique RGPD est claire : ne conservez que ce qui est nécessaire, le temps nécessaire, et sécurisez ce qui reste (contrôles d’accès, journalisation, chiffrement si pertinent). Si vous gérez des données personnelles, recoupez avec votre audit : Audit RGPD PrestaShop : 88 points de contrôle pour boutiques.

Table de décision (simple, mais efficace en runbook) :

Artefact Où le trouver Risque principal Action recommandée
Clés de config ps_configuration / ps_configuration_lang secrets en clair, comportement résiduel supprimer ou migrer vers variables d’env
Hooks ps_hook_module + exceptions surcoût, comportement inattendu unregister + purge entrées restantes
Tabs BO ps_tab + droits accès BO inutile supprimer Tab et vérifier droits
Tables module ps_mymodule_* (ou sans préfixe…) surcoût stockage, données perso purge ou rétention documentée
Tâches cron table du module / crontab système appels continuent “dans le vide” supprimer job + endpoints

Overrides, assets et cache : les trois sources classiques de “module fantôme”

Le piège le plus fréquent après désinstallation : le module n’est plus présent, mais son impact persiste. Les causes n°1 : overrides non supprimés, assets front toujours chargés (par thème, ou par cache), et caches applicatifs non purgés correctement. Sur PrestaShop 8/9, le back-office est Symfony (donc cache Symfony), tandis que le front reste majoritairement legacy ; vous pouvez donc avoir deux “mondes” de cache à purger.

Les overrides sont particulièrement dangereux : un module peut déposer un fichier dans /override/classes/ ou /override/controllers/, et même si vous supprimez le module, l’override continue de s’appliquer tant qu’il est là et tant que l’index de classes n’a pas été régénéré. En production, ce type de résidu génère des bugs “aléatoires” après mise à jour (méthodes manquantes, signatures incompatibles en PHP 8.2+).

Procédure standard (prudente, reproductible) :

  • identifier les overrides ajoutés par le module (git diff si votre code est versionné, sinon inventaire des fichiers récents),
  • retirer l’override,
  • purger les caches,
  • redémarrer proprement PHP-FPM si nécessaire (OPcache peut maintenir en mémoire des versions précédentes selon votre politique de revalidation).

Sur PrestaShop 9 (Symfony 6.4), vous avez aussi la couche var/cache/* à nettoyer via php bin/console cache:clear (en tenant compte des permissions et du user systemd/php-fpm). En pratique, en prod on voit souvent :

# À exécuter avec le même user que celui qui exécute PHP (ex: www-data)
php bin/console cache:clear --env=prod

# En cas de doute sur des résidus, purge "physique" (attention aux permissions)
rm -rf var/cache/prod/*

Enfin, les assets : des modules injectent du JS/CSS via displayHeader ou actionFrontControllerSetMedia, et certains thèmes finissent par “hardcoder” une dépendance (ou un bundling) qui pointe encore vers /modules/mymodule/views/js/.... Résultat : 404 sur assets, dégradation du LCP/INP, et bruit dans les logs.

Mini-scénario réel (très courant) : vous désinstallez un module de slider, mais le thème garde un script src="/modules/slider/views/js/front.js" → la page d’accueil génère des 404, le navigateur retente, et votre monitoring “front” remonte une hausse d’erreurs + une dégradation d’interactivité. Pour traiter ça proprement, instrumentez : erreurs 404, waterfall, coverage JS, et purge de cache reverse-proxy si vous en avez. Pour l’outillage et la méthode, vous avez déjà une base solide : DevTools : méthodes professionnelles pour mesurer et optimiser les performances web et Cache PrestaShop : Varnish, Redis, Memcached et OPcache côté serveur.

Modules et performances : mesurer l’impact réel (TTFB, SQL, hooks, OPCache)

En production, un module “inutile” n’est pas neutre : il augmente la surface d’exécution (hooks), ajoute des requêtes SQL, des appels HTTP sortants, et parfois du traitement CPU sur chaque hit. Le symptôme visible, c’est souvent un TTFB qui s’allonge, une latence panier/checkout qui grimpe, ou des spikes CPU sur PHP-FPM. Pour cadrer le sujet sans folklore, on revient à une vérité simple formulée par Donald Knuth : « Premature optimization is the root of all evil (or at least most of it) in programming. » (Knuth, 1974). Traduction ops : on ne débat pas “au feeling”, on mesure avant/après.

La métrique la plus utile pour qualifier l’impact module côté serveur reste le triptyque : TTFB, temps PHP, et temps SQL. Si votre TTFB dépasse 200–300 ms sur des pages cacheables, vous avez généralement soit un problème d’infra/cache, soit un empilement de modules/hook trop lourd. Vous pouvez vous appuyer sur une démarche structurée : TTFB PrestaShop : réduire le Time To First Byte sous 200 ms et, pour le côté serveur pur (PHP-FPM/OPcache/MySQL), Performance PrestaShop : benchmarks et optimisation PHP-FPM, OPCache, MySQL.

  • désactivez d’abord le module sur une fenêtre courte (ou en staging avec charge représentative) et comparez les métriques (TTFB, erreurs, SQL),
  • redémarrez PHP-FPM après changements importants : l’OPcache peut lisser certains effets, et vous voulez comparer des situations comparables (même politique de cache).

Côté SQL, les modules “catalogue”, “recherche”, “pricing” et “stats” sont les plus agressifs. Ils ajoutent des jointures sur des tables volumineuses, ou des requêtes exécutées en boucle dans des hooks. Activez un slow query log (au moins en staging), et utilisez EXPLAIN/EXPLAIN ANALYZE pour vérifier les indexes. La discipline de base est détaillée ici : Index MySQL : optimiser WHERE, JOIN et ORDER BY avec EXPLAIN. Et si vous gérez de la concurrence (stocks, panier, réservation), évitez les modules qui “bricolent” des verrous applicatifs sans cache distribué : Performance e-commerce : prévenir la concurrence sur les stocks avec Redis.

Requête utile pour repérer les hooks “surpeuplés” (souvent signe d’empilement) :

SELECT h.name, COUNT(*) AS nb_modules
FROM ps_hook_module hm
JOIN ps_hook h ON h.id_hook = hm.id_hook
GROUP BY h.id_hook
ORDER BY nb_modules DESC, h.name ASC
LIMIT 20;

Si vous voyez displayHeader (ou des hooks de rendu) avec une liste très longue, posez-vous la question : quels modules injectent du JS/CSS, des trackers, des widgets… et lesquels pouvez-vous fusionner, remplacer ou retirer.

Sécuriser les modules en production : surface d’attaque, supply chain, mises à jour

Un module PrestaShop, c’est du code PHP avec accès au contexte boutique (session, panier, client, back-office), donc une extension de votre surface d’attaque. Les risques concrets : contrôleurs front exposés (sans authent), endpoints AJAX faibles, webservices internes, injections SQL si le module ne respecte pas les patterns DbQuery/paramétrage, XSS via templates, upload de fichiers mal filtré, et secrets stockés en clair. Pour cadrer la menace, OWASP reste une référence opérationnelle : OWASP Top 10.

Le volet supply chain est devenu critique. Sur PrestaShop 9, les modules “modernes” embarquent souvent des dépendances via Composer : imposez une politique de scan (composer audit, SCA type Snyk/Trivy) et une gestion des versions claire. Sur ce point, Semantic Versioning résume le contrat attendu : « MAJOR version when you make incompatible API changes, MINOR version when you add functionality in a backwards compatible manner, and PATCH version when you make backwards compatible bug fixes. » (semver.org). Si l’éditeur publie des releases sans changelog, ou casse des compatibilités en “patch”, vous ne pouvez pas industrialiser vos updates.

Enfin, la gestion des secrets et des accès : arrêtez de stocker des clés API dans des champs visibles ou des tables où n’importe quel employé BO peut les lire. L’approche Twelve-Factor est brutale mais juste : « Store config in the environment. » (12factor.net/config). Dans PrestaShop, ça veut dire : variables d’environnement (ou secrets du runtime), limitation des droits BO (profils), et durcissement des endpoints.

Checklist sécurité “module” (pratique en revue avant mise en prod) :

  • endpoints front/AJAX : authentification, contrôle CSRF si pertinent, validation stricte des entrées,
  • uploads : whitelist MIME/extension, renommage, stockage hors webroot si possible,
  • secrets : pas de clé en clair affichable en BO ; rotation documentée,
  • dépendances : composer.lock maîtrisé, audit régulier, suppression de libs inutiles,
  • logs : pas de données sensibles (tokens, cartes, mots de passe) dans les logs applicatifs.

Pour aller plus loin sur le hardening (WAF, logs, API BO), appuyez-vous sur : Sécurité PrestaShop : protéger API backoffice, WAF et journalisation SIEM et Sécurité PrestaShop 2026 : risques majeurs et protections professionnelles. Exemple concret de gestion de crise : CVE-2025-61922 ps_checkout : mise à jour 5.0.5 et mesures.

Runbook production : installer, mettre à jour, désinstaller sans downtime inutile

En production, la règle n’est pas “installer/désinstaller vite”, c’est “installer/désinstaller de façon répétable”. Si votre process dépend d’un clic manuel + FTP, vous ne pourrez ni auditer ni rollback correctement. Mettez un pipeline minimal : build reproductible, artefacts versionnés, déploiement en staging, tests de non-régression tunnel (panier/commande), puis prod. Pour l’industrialisation, la base est ici : Intégration continue PrestaShop : BuildKit, GitHub Actions et build reproductible et, pour les checklists fonctionnelles post-change : Contrôle PrestaShop post-modification : checklist tunnel de commande et règles panier.

Ensuite, un runbook “module” concret (à adapter) :

  • Avant installation / update : snapshot DB, sauvegarde /modules + thème, inventaire des overrides, export ps_configuration (ou au moins les clés du module), et contrôle des dépendances (Composer si PS9).
  • Pendant : activer le mode maintenance si le module touche au checkout, exécuter les migrations éventuelles, purger caches applicatifs (Symfony + legacy) et reverse-proxy, puis réchauffer les caches critiques.
  • Après : tests de charge ciblés (pages clés), vérification logs (PHP, Nginx/Apache, slow queries), et monitoring des métriques (TTFB, erreurs 5xx, DB CPU).

Ajout utile pour les désinstallations (souvent plus risquées que les installs, car on découvre les dépendances implicites) :

  • désactiver le module et observer 15–30 min (ou en staging sous charge) : erreurs 404/500, temps de réponse,
  • rechercher et supprimer références dans le thème (templates, bundles, overrides),
  • nettoyer base (config/hooks/tabs/tables) uniquement après validation en staging,
  • redémarrer PHP-FPM si vous suspectez des effets “cache code” (OPcache) après retrait d’overrides/classes.

Ce runbook n’est pas cosmétique : il évite les scénarios où une désinstallation “rapide” casse des pages (assets 404), laisse des endpoints accessibles, ou augmente la charge DB. Pour la partie monitoring et préparation aux pics (soldes, campagnes), vous avez déjà un cadre : PrestaShop performance : monitoring, tests de charge et runbooks soldes.

Enfin, si vous hébergez sur VPS, n’oubliez pas que beaucoup de “problèmes modules” sont en fait des problèmes d’environnement : permissions, isolation, SMTP, anti-DDoS, journalisation. Une boutique qui n’a pas de posture sécurité système finira par attribuer à un module ce qui relève du serveur. Référence utile côté admin : VPS OVHcloud : sécurité, anti-DDoS, SMTP 25 et bonnes pratiques admin. Le bon ordre d’exécution est simple : stabiliser l’infra, mesurer, puis seulement arbitrer l’impact des modules.


À lire aussi