Gérer correctement la suppression de fichiers sur un CDN (S3) avec Laravel FileSystem et Spatie Media Library

Lorsqu’on travaille avec un stockage distant comme S3, Cloudflare R2 ou un autre CDN compatible S3, la gestion des fichiers peut rapidement devenir un problème si elle n’est pas correctement contrôlée.

Un cas fréquent apparaît lors de la suppression de fichiers liés à une base de données.

Dans cet article, nous allons voir :

  • le problème courant avec Laravel
  • pourquoi il peut créer des incohérences
  • une stratégie pour sécuriser la suppression des fichiers

Le problème : Laravel ne signale pas toujours les erreurs de suppression

Laravel propose une abstraction très pratique pour la gestion des fichiers avec Laravel via Laravel Filesystem, qui repose sur Flysystem.

Lorsqu’on utilise un stockage distant comme Amazon S3, il arrive que la suppression d’un fichier échoue silencieusement.

Par exemple :

Storage::disk('s3')->delete($path);
Langage du code : PHP (php)

Si le fichier n’est pas supprimé pour une raison quelconque (latence réseau, permissions, erreur API…), aucune exception n’est forcément levée.

Le problème apparaît alors dans ce scénario :

  1. La ligne est supprimée dans la base de données
  2. Le fichier reste sur le CDN
  3. La relation entre la base et le fichier est perdue

Résultat :

  • fichiers orphelins sur le stockage
  • incohérences de données
  • coûts de stockage inutiles
  • impossibilité de retrouver les fichiers

Le cas de Spatie Media Library

La librairie Spatie Laravel Media Library est largement utilisée pour gérer les fichiers associés aux modèles Eloquent.

Elle gère automatiquement :

  • l’upload
  • les conversions
  • les relations avec la base de données

Cependant, la suppression reste dépendante du filesystem Laravel. De plus la suppression n’est exécutée uniquement sur l’évènément de suppression du modèle lié en base de donnée via un observer (deleted).
Donc les mêmes risques existent si la suppression échoue côté stockage.

Une stratégie plus sûre : vérifier avant de supprimer la base

Une approche simple consiste à :

  1. utiliser une transaction SQL
  2. récupérer le fichier
  3. supprimer le modèle
  4. vérifier que le fichier est réellement supprimé
  5. rollback si nécessaire

Exemple :

// 1. Démarre une transaction
DB::beginTransaction();

try {  
    // 2. Récupère le média associé
    // Dans le cas ou le modèle contient qu'un seul media
    $media = $model->media->first();

    // 3. Supprime le modèle
    $media->forceDelete();    

    // 4. Vérifie que le fichier a bien disparu
    if (Storage::disk($media->disk)->exists($media->getPath())) {
        throw new \Exception("File {$media->getPath()} still exists");
    }
}  catch (\Exception $e) {
    // 5. Rollback si ce n’est pas le cas
    DB::rollBack();
    throw $e;
}
DB::commit();
Langage du code : PHP (php)

Cette solution garantit :

✔ cohérence entre la base et le stockage
✔ détection immédiate d’un problème CDN
✔ rollback automatique
✔ pas de fichiers orphelins

Amélioration possible : supprimer le fichier explicitement

Une approche encore plus claire consiste à supprimer le fichier explicitement avant la suppression du modèle :

Storage::disk($media->disk)->delete($media->getPath());
Langage du code : PHP (php)

Puis vérifier :

if (Storage::disk($media->disk)->exists($media->getPath())) {
    throw new Exception("File deletion failed");
}
Langage du code : PHP (php)

Et seulement ensuite supprimer la ligne en base.

Cela inverse la logique :

  1. supprimer le fichier
  2. vérifier
  3. supprimer la base

Conclusion

Lorsque l’on utilise Amazon S3 avec Laravel et Spatie Laravel Media Library, il est important de ne pas supposer que la suppression de fichier fonctionne toujours correctement.

Sans vérification, on peut rapidement se retrouver avec :

  • des fichiers orphelins
  • des incohérences base / stockage
  • des coûts de stockage inutiles

La solution consiste à :

  • Supprimer la ligne en BDD après s’être assuré que le fichier a été supprimé sur le CDN, ou utiliser des transactions dans le cas où il n’est pas possible de supprimer la ligne après (en utilisant Spatie)
  • vérifier explicitement la suppression
  • centraliser la logique dans un service

Cette approche simple permet de garantir l’intégrité entre votre base de données et votre stockage distant.

GhostvOne
GhostvOne

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *