Drupal: Medien, Dateien und wie man ihre Sichtbarkeit steuert
Missverständnisse im Verhältnis zwischen Medien und Dateien
Spätestens seit das Media Modul und die Media Library im Drupal Core angekommen waren (also schon seit einiger Zeit) ist es sinnvoll, mit Medien statt Bildfeldern zu arbeiten, um alle Vorteile von Media Entities nutzen zu können (eigener Publikationsstatus des Entity, beliebige Felder für Beschreibung, Bildunterschrift.., Revisionen u.v.m).
Hin und wieder sorgen jedoch zwei Phänomene für Irritationen:
- Wenn ein Medien-Objekt gelöscht wird, ist die entsprechende Datei immer noch da (und über die Datei-URL öffentlich abrufbar)!
- Wenn ein Medien-Objekt depubliziert wird (und es als solches auch nirgends mehr angezeigt wird), ist ebenso die von ihm verwendete Datei immer noch über die direkte Datei-URL öffentlich abrufbar!
Beides ist für Nutzer natürlich völlig kontraintuitiv: wer ein Medien-Objekt löscht bzw. depubliziert, erwartet natürlich, dass die damit korrespondierende Datei (jpg, pdf,..) auch gelöscht wird bzw. nicht mehr erreichbar ist.
Das Problem ist, dass Medien und Dateien verschiedene Entitäten sind und die Datei, die von einem Medien-Objekt benutzt wird, unabhängig von ihm ist. Der Webserver weiß nichts über einen Zusammenhang zwischen Medien-Objekt, Publikationsstaus und Datei. Ist die Datei in einem öffentlichen Verzeichnis vorhanden, liefert der Webserver sie aus – ohne dass Drupal in diesen Vorgang involviert ist.
So kann es passieren, dass jemand beispielsweise über einen Suchtreffer über die direkte Datei-URL ein Dokument oder Bild öffnet, das aus redaktioneller Sicht längst depubliziert oder sogar gelöscht ist und überhaupt nicht mehr verfügbar sein sollte (und das im eigentlichen, redaktionellen Sinn als Drupal Media eingebettetes Objekt tatsächlich auch nicht mehr sichtbar ist).
Abhilfe beim Löschen von Medien
Um Dateien mit zu löschen, wenn ein Medien-Objekt gelöscht wird, gibt es das Modul Media File Delete. Das Modul fügt dem Formular beim Löschen von Medien einen Schalter mit der Option hinzu, die Datei des Medien-Objekts gleich mitzulöschen – Problem 1) gelöst!

Durch Media File Delete erweiterter Dialog beim Löschen von Medien
Depublizieren – komplizierter, als einfach nur zu löschen...
Im Fall des Depublizierens ist es natürlich komplizierter, denn hier muss die Datei unzugänglich gemacht statt gelöscht werden. Sie soll nur temporär nicht erreichbar sein – solange eben das korrespondierende Medien-Objekt depubliziert ist.
Es gibt das Drupal-Modul File Visibility, das zusammen mit Track Usage arbeitet und für verschiedene Anwendungsfälle konfiguriert werden kann. Das Modul verschiebt dann Dateien, die in (noch) nicht publizierten Inhalten oder Medien verwendet werden, in das private Dateisystem von Drupal und holt sie zurück in das öffentliche Dateisystem, sobald der übergeordnete Inhalt (Node, Paragraph oder Media) publiziert wird.
Die Konfiguration ist jedoch relativ umfangreich und auch nicht direkt sebsterklärend, so dass man sich ein wenig in das Zusammenspiel beider Module einlesen muss. Andererseits kam es mir hier auch so vor, als würde damit ein ziemlicher Overhead im Hintergrund entstehen. Außerdem ist der ursprüngliche Anwendungsfall des File Visibility Moduls ein anderer, es geht hier hauptsächlich um die Vermeidung von Spamdexing.
Man könnte also versucht sein, direkt das private Dateisystem als Default zu benutzen, um die beiden problematischen Fälle auszuschließen. Das würde aber in den meisten Fällen zu unsinnig hoher Serverlast führen, weil Drupal dann die Ausgabe jeder einzelnen Datei prüfen müsste – wie Claudiu Cristea auf der Projektseite von File Visibility ausführt:
The site builder might be tempted to set the private file system as the default scheme for all uploaded files. But this is not recommended, as Drupal might crash in heavy traffic. Actually, for each file the webserver, PHP, and Drupal will have to do heavy processing. While a public file is served directly by the webserver, and 90% of the time is retrieved either from the frontend cache or even from the browser's cache.
Eigentlich sollte ja aber "nur" die Datei, die von dem jeweiligen depublizierten Medien-Objekt verwendet wird, nicht mehr aufrufbar sein. Dafür habe ich einen simpleren Ansatz gesucht und konnte mit dem Alleskönner-Tool ECA Abhilfe schaffen, ohne gleich ein eigenes Modul schreiben zu müssen. Das Drupal-Modul ECA (Event, Condition, Action) haben wir allgemein auch hier beschrieben.
Wie Dateien versteckt werden können
Die Idee hinter unserem leichtfüßigeren Ansatz ist simpel: wird ein Medien-Objekt depubliziert, benennen wir die Datei temporär so um, dass der Webserver sie schlicht nicht mehr ausgeben wird. Der simple Präfix .ht.
bewirkt das, genauso wie bei den altbekannten Dateien .htaccess
oder .htpasswd
.
Die ursprüngliche URL zur Datei liefert dann den Status 404 Not found
zurück, denn eine Datei mit diesem Namen gibt es nicht mehr. Sollte hypothetisch jemand versuchen, die umbenannte Datei aufzurufen, wird der Webserver mit 403 Forbidden
antworten.
Bekommt das Medien-Objekt wiederum den Status "publiziert", muss der Präfix der Datei wieder weggenommen werden: Problem 2) gelöst.
Medien beim Erstellen / Update prüfen
Der erste Teil unseres ECA Modells reagiert auf insert
und update
Events von Medien im System. In einem ersten Schritt wird lediglich geprüft, ob das Medien-Objekt ein relevantes Dateifeld besitzt (hier nur für Image, Document, Video – es lässt sich aber selbstverständlich für beliebige, eigene Medien erweitern).

ECA-Flow zum Prüfen, ob eine relevante Datei im Medien-Objekt enthalten ist.
Prüfen des Status und Umbenennen
Im zweiten Schritt wird der Custom Event Adjust Filename
ausgelöst. Dort wird dann geprüft, ob das Medien-Objekt publiziert ist oder nicht und entsprechend gehandelt:
- Ist es nicht publiziert und der Dateiname beginnt noch nicht mit
.ht.
wird die Datei umbenannt und bekommt diesen Präfix - Ist es publiziert und der Dateiname beginnt noch mit
.ht.
wird der Präfix wieder weggenommen

Der zweite ECA-Flow benennt Dateien um, je nach Publikationsstatus des übergeordneten Medien-Objekts